做Java毕业设计这几年医药管理系统是出现频率最高的题目之一。很多学生在选择毕设题目时既想找一个看起来有行业含金量的主题又希望能在两三个月内真正做完于是“基于Spring Boot的医药管理系统”就成了热门选项。这个题目覆盖面很广从药品信息维护、库存预警到采购入库、销售出库再到供应商管理和月度统计都落在Web开发最典型的增删改查和报表场景里。对毕设来说拿它既能展示基本功又有足够业务故事可以讲。这篇文章我会结合自己调试、指导这类项目的经验把技术选型、数据库设计、环境搭建、核心代码实现、常见坑点一次讲清楚。不管你是准备选这个题目的学生还是刚拿到一套源码还没跑通都可以按下面的思路把项目吃透。1. 项目选题与整体设计思路1.1 为什么医药管理系统适合做毕业设计医药管理系统是典型的行业信息化课题。现在不管是连锁药店、单体药店还是医院药房都需要对药品库存、有效期、供应商和销售数据进行管理。药品与普通商品不一样它有批准文号、生产厂家、规格、有效期等属性意味着系统不能只做简单的商品增删改查还要关注批次、预警、库存安全。正因如此评审老师看到“医药管理系统”时会有明确的业务预期也能自然联想到使用场景这种“一看就知道是干什么的”优势是图书管理、学生管理这类基础题目不具备的。从开发难度上看医药管理系统也很适合作为毕业设计。它的业务线是进销存药品基础资料、供应商、采购入库、库存变动、销售出库、统计报表。这些功能是Web开发最经典的组合用Spring Boot MySQL就能全部覆盖。相比电商系统需要处理购物车、订单状态机、支付回调医药管理系统在复杂度上刚好处于“有挑战但能完成”的甜区。对大多数本科学生来说两三周写完核心功能再用两周补文档和打磨细节时间上是可控的。但这个题目也有一个明显的风险因为做的人太多网上流传的源码质量参差不齐。很多所谓“医药管理系统”其实只是把库存管理系统换个标题药品表里连有效期、批准文号都没有。如果你只是拿来自用可能没感觉但如果答辩时老师追问一句“批号和有效期怎么管理”就会很尴尬。所以我一直强调选这个题目之后一定要在业务字段和业务流程上做出医药行业的真实感这才是拿高分的起点。1.2 技术选型解析与选型理由技术选型是很多人在选题后会纠结的第二件事。我的建议非常明确不要追求花哨毕设项目的技术栈一定要满足三个条件——资料充足、自己能讲清、部署简单。所以下面这套组合是我个人认为最适合医药管理系统毕设的技术组件推荐选择选择理由开发语言Java 8/11Spring Boot支持稳定JDK8兼容性最好核心框架Spring Boot 2.7.x简化配置、内嵌Tomcat社区资料最多ORM框架MyBatis-Plus单表CRUD免写SQL分页插件好用数据库MySQL 5.7/8.0免费、通用、资料多模板引擎ThymeleafSpring Boot原生支持适合服务端渲染前端UILayui jQuery后台管理界面成熟表格组件开箱即用权限方案Shiro 或 拦截器轻量级适合单体应用构建工具Maven主流标准依赖管理方便这套技术栈不是什么新东西但胜在“稳”。Spring Boot解决了传统Spring配置复杂的问题内嵌Tomcat让项目可以一键启动MyBatis-Plus把常用单表操作简化到了极致能让开发时间大幅缩短Layui是老牌后台管理UI表格、表单、弹窗都封装得很完善写出来的页面在毕设答辩时也够看。很多同学会问为什么不用JSP为什么不用前后端分离的Vue原因很简单。JSP在Spring Boot里虽然能集成但本身已经不算主流方案而且查资料时容易混入老项目的坑前后端分离则需要同时维护前端工程和后端工程接口联调、跨域处理、前端打包这些内容都会增加工作量。如果你只有两个月时间还要写论文和准备答辩使用服务端渲染反而是更稳妥的路线。当然如果本身已经有Vue基础做一套前后端分离版本会更有亮点这个放到后面定制扩展里再说。2. 核心功能与数据库设计拆解2.1 从需求清单到功能模块划分医药管理系统的角色一般有三种管理员、库管员药师、收银员销售员。管理员负责用户、药品字典和供应商档案库管员负责采购入库和库存调整收银员处理销售出库和退货。不同角色通过登录后的菜单权限区分。核心功能模块可以拆为以下六块系统登录与用户管理登录认证、用户信息维护、角色权限分配。药品信息管理药品编码、名称、规格、厂家、批准文号、单价上下限和库存预警值。供应商管理供应商基础资料、联系人、供货状态。采购入库管理入库单创建、药品明细添加、入库后自动增加库存。销售出库管理选择药品、自动带出价格、校验库存、扣减库存并生成销售记录。统计报表按药品、按时间统计销售数量和销售额支持简单图表展示。这里面最容易被忽略的是“入库单明细”和“销售单明细”。很多初学者喜欢把每次入库或销售直接写在药品表上但这样丢失了业务单据信息不利于追溯。比较好的设计是主从表结构一张主表记录单据号、操作人、时间、供应商或会员信息一张明细表记录药品、数量、单价、总价。这样后续想统计、对账、退货都有据可查。在答辩时你可以明确说“我采用主从表保存销售单据既能保证业务记录的完整性又能方便扩展退款或对账功能”这比单纯说“我建了表”要有说服力得多。2.2 数据库表设计字段和关系数据库设计是一切功能的地基。建议至少包含以下核心表sys_user用户、drug_info药品信息、supplier供应商、drug_stock药品库存、purchase_order采购主表、purchase_detail采购明细、sale_order销售主表、sale_detail销售明细。其中drug_stock不同于drug_info药品基础信息是一物一档库存则可能多条因为不同批次、不同有效期的药品虽然“药品ID”相同但库存要分开算。先看用户表和药品表的常见结构CREATE TABLE sys_user ( id INT NOT NULL AUTO_INCREMENT COMMENT 主键, username VARCHAR(50) NOT NULL COMMENT 登录名, password VARCHAR(100) NOT NULL COMMENT 密码, real_name VARCHAR(50) DEFAULT NULL COMMENT 姓名, role_id INT NOT NULL COMMENT 角色1管理员 2药师 3收银员, status TINYINT DEFAULT 1 COMMENT 1正常 0禁用, create_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_username (username) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT系统用户表;CREATE TABLE drug_info ( id INT PRIMARY KEY AUTO_INCREMENT, drug_code VARCHAR(20) NOT NULL UNIQUE COMMENT 药品编码, drug_name VARCHAR(100) NOT NULL COMMENT 药品通用名, specification VARCHAR(50) COMMENT 规格, unit VARCHAR(10) COMMENT 单位, manufacturer VARCHAR(100) COMMENT 生产厂家, approval_number VARCHAR(50) COMMENT 批准文号, purchase_price DECIMAL(10,2) COMMENT 采购价, sale_price DECIMAL(10,2) COMMENT 零售价, stock_warning INT DEFAULT 20 COMMENT 库存预警下限, status TINYINT DEFAULT 1 COMMENT 状态1上架 0下架, create_time DATETIME ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT药品信息表;药品表里有一个很关键的字段是approval_number也就是批准文号。医药行业里一个药品能不能合法销售就看这个编号。把这个字段放进去一方面让系统更贴近真实业务另一方面也是答辩时证明“我有行业思考”的细节。stock_warning是库存预警下限低于这个值的时候系统可以在页面上标红提醒补货。接着是库存表CREATE TABLE drug_stock ( id INT NOT NULL AUTO_INCREMENT, drug_id INT NOT NULL, batch_no VARCHAR(50) DEFAULT NULL COMMENT 批次号, production_date DATE DEFAULT NULL COMMENT 生产日期, expire_date DATE DEFAULT NULL COMMENT 有效期至, quantity INT NOT NULL DEFAULT 0 COMMENT 当前数量, PRIMARY KEY (id), KEY idx_drug (drug_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT药品库存表;库存按批次分行是很多人容易忽略的设计。同一个药品今天进的货可能有效期到2027年仓库里剩的旧货可能有效期到2026年如果不按批次拆开只用一条库存记录那就没法做“先进先出”和“近效期预警”。入库时同一药品不同批次会插入多行出库时可以按批次号手动选择也可以按“先到期先出”的逻辑自动扣减。这个设计只要你能讲出来老师自然会觉得你的系统不是“玩具项目”。销售主表和明细表的经典写法是这样的CREATE TABLE sale_order ( id INT NOT NULL AUTO_INCREMENT, order_no VARCHAR(30) NOT NULL COMMENT 销售单号, user_id INT NOT NULL COMMENT 操作员, total_amount DECIMAL(10,2) NOT NULL COMMENT 总金额, sale_time DATETIME DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT销售主表; CREATE TABLE sale_detail ( id INT NOT NULL AUTO_INCREMENT, sale_id INT NOT NULL, drug_id INT NOT NULL, drug_name VARCHAR(100) DEFAULT NULL COMMENT 冗余名称, batch_no VARCHAR(50) DEFAULT NULL, price DECIMAL(10,2) NOT NULL, quantity INT NOT NULL, amount DECIMAL(10,2) NOT NULL, PRIMARY KEY (id), KEY idx_sale (sale_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT销售明细表;明细表里冗余一个drug_name是为了统计报表时少一次连表查询。严格按数据库三范式来说这算是冗余但在实际项目中适度冗余非常常见。答辩如果被问到你就说“查询高频字段冗余后减少关联提升报表响应速度”这个回答完全站得住脚。2.3 表关系与业务流转逻辑这些表的关系可以串成一条完整的业务闭环药品信息是主数据库存关联药品ID和批次采购入库时先生成采购主表和明细表然后写入或更新库存销售出库时选择药品和批次扣除库存同时生成销售主表和明细表系统用户表关联角色角色决定菜单权限。关于是否要建立物理外键我的建议是不要。用逻辑外键即可也就是在关联字段上建普通索引而不在数据库层面强制REFERENCES。因为物理外键在删除药品、修改主键时会带来各种限制MyBatis-Plus和很多管理员删除操作也会因为外键约束而失败。在文档里把ER图的关系画清楚代码层面通过事务保证数据一致性对毕设来说完全够用这也是实际企业开发中更常见的做法。3. 环境搭建与项目运行实操3.1 开发环境准备说明如果手上有源码最怕的不是代码复杂而是环境不一致导致起不来。建议按下面的版本准备兼容性最好JDK优先使用1.8或11对应Spring Boot 2.x项目。如果项目是Spring Boot 3.x请使用JDK17。Maven3.6.3以上配置好阿里云镜像否则依赖下载会卡到怀疑人生。IDEIDEA Community或Professional都可以建议用新版。MySQL5.7或8.0均可注意字符集设置为utf8mb4。数据库客户端Navicat、DBeaver、MySQL Workbench任选。安装完成后先在命令行确认环境是否正常java -version mvn -version如果mvn不是内部命令需要配置MAVEN_HOME环境变量同时把maven的bin目录加到Path中。很多项目启动失败不是代码问题而是Maven没有正确配置IDEA自带的Maven版本又和学生本机的不一致导致依赖包下载到一半就报错。建议先在IDEA的Settings里把Maven指向自己安装的那个确认本地仓库路径再打开项目。3.2 从源码到浏览器出现登录页的完整流程我在这类项目中常用的启动流程是固定的你可以照做用IDEA打开解压后的源码目录选择信任Maven项目等待右下角依赖下载完成。如果POM文件有下载失败的红色波浪线先执行mvn clean再重新导入。新建数据库medical在数据库工具中执行项目里的medical.sql脚本。注意脚本里可能包含多个CREATE DATABASE语句可以手动改成USE medical后再执行。找到application.yml或application.properties检查数据源配置。最常见的修改点是数据库名、用户名、密码以及端口号。如果项目使用了Redis或额外服务需要确认本机是否安装并启动。绝大部分医药管理系统毕设不需要Redis但有的版本会加缓存这种项目务必要看README。运行启动类比如MedicalApplication看到Started MedicalApplication in xxx seconds说明启动成功。浏览器访问http://localhost:8080跳转到登录页。用脚本里面的默认账号登录比如admin/admin123。拿到项目包后第一件事不是急着双击运行而是先读README.md。很多同学不看文档直接启动遇到问题又折返问人。其实源码里通常会把数据库脚本位置、默认账号、端口信息写在README里。看文档的时间可能只有五分钟却能把后面一小时排错的时间省掉。3.3 首轮调试的注意点首次运行后建议按业务链路走一遍不要只登录一下就说“跑通了”。我一般按下面顺序测试登录不同角色并检查菜单权限新增一个药品给它填库存做一个销售单查看库存是否减少查看统计报表是否有数据。这六个动作覆盖了系统核心闭环任何一个环节报错都能快速定位到Controller层还是数据库层。同时建议在IDEA的Services面板里看运行日志一边操作页面一边观察控制台输出的SQL。如果项目配置了MyBatis-Plus的SQL日志控制台会把每一条执行的SQL打印出来。日志不是摆设它在调试时是最好的老师。很多前端报“无数据”看后端SQL能一眼看出是查询条件拼错还是表名映射错误。4. 核心模块实现与关键代码解读4.1 后端分层与药品分页查询实现Spring Boot项目通常是标准三层架构Controller负责接收请求Service负责业务逻辑Mapper负责数据库访问。这样分层的目的是让代码职责清晰出问题时能迅速定位。我以药品分页查询为例展示一条完整的请求链路。Controller层RestController RequestMapping(/drug) public class DrugController { Resource private DrugService drugService; GetMapping(/page) public Result page(RequestParam(defaultValue 1) Integer pageNum, RequestParam(defaultValue 10) Integer pageSize, RequestParam(required false) String keyword) { return Result.success(drugService.pageQuery(pageNum, pageSize, keyword)); } }这里用Resource注入Service接口统一返回ResultResult对象内部包含code、msg、data方便前端Layui识别。Result.success是我常用的封装方式只需要三行代码就能统一接口格式。Service接口和实现public interface DrugService { PageDrugInfo pageQuery(Integer pageNum, Integer pageSize, String keyword); } Service public class DrugServiceImpl implements DrugService { Resource private DrugInfoMapper drugInfoMapper; Override public PageDrugInfo pageQuery(Integer pageNum, Integer pageSize, String keyword) { LambdaQueryWrapperDrugInfo wrapper new LambdaQueryWrapper(); if (StringUtils.hasText(keyword)) { wrapper.and(w - w.like(DrugInfo::getDrugName, keyword) .or().like(DrugInfo::getDrugCode, keyword) .or().like(DrugInfo::getManufacturer, keyword)); } wrapper.orderByDesc(DrugInfo::getCreateTime); return drugInfoMapper.selectPage(new Page(pageNum, pageSize), wrapper); } }LambdaQueryWrapper是MyBatis-Plus提供的一种类型安全查询构造器字段名写错时编译阶段就会暴露问题。这里用and把三个模糊查询条件包起来避免keyword为空时拼接出错误SQL。分页查询一定要配置分页插件否则selectPage不会真的分页而是把全表查出来这是初学者最容易踩的坑。分页插件配置如下Configuration MapperScan(com.example.medical.mapper) public class MybatisPlusConfig { Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor new MybatisPlusInterceptor(); PaginationInnerInterceptor pagination new PaginationInnerInterceptor(DbType.MYSQL); pagination.setMaxLimit(500L); interceptor.addInnerInterceptor(pagination); return interceptor; } }注意MapperScan要指向实际的Mapper接口包名不同项目结构不一样写错会导致所有Mapper找不到Bean启动时直接报Invalid bound statement。4.2 登录与权限控制的关键逻辑权限控制是管理系统绕不开的点。毕设项目最常用的两种方案Shiro、Spring Security。如果只是想节省时间也可以直接用拦截器加Session代码量小答辩时也更容易讲清楚。使用拦截器的基本思路是登录成功后把用户对象放进Session定义一个WebMvcConfigurer注册拦截器排除登录接口和静态资源路径。核心拦截器代码如下public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { Object user request.getSession().getAttribute(loginUser); if (user null) { response.sendRedirect(/login); return false; } return true; } }注册拦截器的配置类Configuration public class WebConfig implements WebMvcConfigurer { Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new AuthInterceptor()) .addPathPatterns(/**) .excludePathPatterns(/login, /logout, /css/**, /js/**, /layui/**, /images/**); } }这段代码很容易踩两个坑。第一个坑排除路径里如果漏了静态资源目录登录页会加载不出CSS和JS看着像“页面坏了”。第二个坑如果把/api/**这种接口路径也放行那么未登录用户可以直接请求后端数据权限形同虚设。配置时要逐条核对。如果项目里用的是Shiro整体思路类似只是把认证和授权交给Realm管理。Shiro的shiro.ini或配置类里需要指定登录页、放行路径、角色过滤链。从答辩角度来说拦截器方案更容易讲清楚原理从项目含金量来说Shiro会显得更专业一点。两者都可以不用过于纠结。4.3 前端页面的渲染与交互前端部分如果用Thymeleaf页面通常放在resources/templates目录静态资源放在resources/static目录。以药品列表页为例Layui渲染表格的写法非常经典table iddrugTable lay-filterdrugTable/table script layui.use([table, layer], function () { var table layui.table; table.render({ elem: #drugTable, url: /drug/page, page: true, cols: [[ {field: id, title: ID, width: 70}, {field: drugCode, title: 药品编码, width: 120}, {field: drugName, title: 药品名称, width: 150}, {field: specification, title: 规格, width: 100}, {field: manufacturer, title: 生产厂家, minWidth: 180}, {field: salePrice, title: 零售价, width: 100}, {field: createTime, title: 创建时间, width: 170} ]] }); }); /script前端交互时要特别注意Layui table默认发送的请求参数是page和limit如果后端接收参数名是pageNum和pageSize就会导致分页参数对不上列表会出现“只有第一页有数据点击第二页后没数据”的怪现象。解决办法有两种一是在后端方法参数里直接用RequestParam(page)和RequestParam(limit)二是在table.render里配置request参数指定page、limit对应的名称。统一命名比到处写兼容代码要省心得多。4.4 论文结构建议与答辩准备拿到源码和文档后不建议一字不改直接提交。合理做法是把项目文档改造成自己的。毕设论文通用结构是绪论、需求分析、系统设计、数据库设计、系统实现、系统测试、总结。其中需求分析和数据库设计是复习重点因为这两章最能体现“你是否理解这个系统”。答辩前一定要能回答下面几类问题为什么用Spring Boot答简化配置、自动装配、内嵌Tomcat、生态成熟。药品过期预警怎么实现答在库存表中有expire_date查询时增加“剩余有效期小于N天”的筛选条件。库存扣减防止超卖怎么做答用条件UPDATE同时加事务避免两个请求读到同一个旧库存。怎么保证订单和明细的一致性答Service方法上加Transactional明细插入失败时回滚主表记录。这些内容在写代码时注意过现场就不会慌。最怕的是拿了一套不熟悉的源码连药品表有哪几个字段都没翻开看过自然一问三不知。5. 调试运行中的常见问题与避坑指南5.1 环境与依赖问题速查表下面这张表是我在帮学生调试时遇到频率最高的问题基本覆盖了最常见的“起不来”原因问题现象解决办法端口被占用启动报Port 8080 was already in use改yml的server.port或用netstat -ano找到占用进程结束数据库连接失败Access denied for user检查yml中的用户名密码注意MySQL8的密码加密方式依赖下载超时IDEA一直转圈、pom报红配置阿里云Maven镜像切换JDK版本Lombok报错找不到getter/setter安装Lombok插件检查注解处理器JDK版本问题Unsupported major.minor version 52.0更换JDKSpring Boot 2.7要求JDK8及以上页面无样式登录页没有CSS拦截器排除静态资源路径或检查thymeleaf路径中文乱码页面显示??数据库库表字符集改为utf8mb4连接URL加characterEncodingutf8关于Maven镜像直接说结论国内网络环境下默认中央仓库的下载速度很不稳定。在settings.xml里配置阿里云镜像后依赖下载速度快得不是一点半点。如果IDEA里能看到某个依赖一直标红多半是下载失败删除本地仓库对应目录后重新拉取即可。5.2 业务逻辑Bug排查实录有些项目环境没问题能登录、能跳转但业务流程总有各种奇怪现象。我记录几个比较典型的案例方便排查时对照。案例一销售出库后库存不减反增。排查时发现Service层在插入销售明细后又调用了一个名为“inStock”的公共方法而这个方法实际上执行的是“增加库存”。这种问题是因为方法复用时不仔细看方法名。解决思路很简单把“增加库存”和“扣减库存”的方法名区分开比如increaseStock和decreaseStock并在方法上加清晰注释。案例二药品列表分页点击第二页没数据。原因是前端传的page和limit后端接收的是pageNum和pageSize导致第二页查询条件拼不上。解决方法是统一参数命名这样最直接。案例三新增药品报“药品编码已存在”但列表里看不到那条数据。后来发现是新增接口里没有给status赋初始值数据库默认被设置为0列表默认只查status1的数据于是这条记录成了“隐藏数据”。解决方法是新增时显式设置status1或在数据库字段里给默认值。案例四近效期预警怎么都出不来。检查后发现库存表里expire_date字段在实体类中被定义为String查询时用了字符串比较结果“2026-01-01”和“2025-12-31”的排序完全不对。解决方法是把字段类型改成DATE查询时用日期函数。这些问题本身不难但能反映出对业务表设计的理解。每改一个Bug先在纸上画出这次变更涉及哪几张表、哪几个方法能很大程度减少低级错误。5.3 从毕设到可展示项目的定制扩展方向如果不想止步于“又一个库存管理系统”可以往下面几个方向做定制扩展把这些作为亮点写进文档和答辩PPT药品近效期预警与过期药品统计库存查询加一个条件把有效期小于90天、30天的药品高亮显示。库存上下限自动补货建议当库存低于预警值时自动生成建议采购单。销售趋势图表引入ECharts按月份统计销售额画折线图或柱状图。导出Excel报表用EasyExcel或POI导出销售明细、库存台账让项目“交付感”更强。前后端分离改造把现有接口改成RESTful API前端用Vue3 Element Plus重新实现技术含金量明显提升。定制时要注意尽量在现有源码上小步修改不要一上来就大重构。比如先在原系统加一个“有效期预警”菜单成功后再加上导出功能每完成一个功能都重新跑一遍主流程避免最后一天才合并代码导致一堆冲突。6. 个人实操体会与几点建议6.1 三天跑通一个医药管理系统的节奏我见过很多学生拿到毕设源码后第一周都在纠结环境问题第二周还在改Bug最后一周疯狂赶文档。其实这款项目的节奏完全可以更人性化。我建议的节奏是三天第一天解决环境问题把项目启动起来至少能登录。别急着看代码先跑通建立信心。第二天把核心业务走一遍新增药品、入库、销售、看库存、看统计。每走一步都在代码里找到对应Controller和Service不用全看懂但要知道链路。第三天打开文档模板按照自己的页面截图和表结构把需求分析和数据库设计章节填上。再让朋友模拟“老师”问你两遍能顺畅说清核心流程基本就稳了。这个节奏不鼓励熬夜而是强调“先跑通再深挖”。多数毕设项目卡住不是代码难而是死磕一个非核心问题导致心态崩了。一个端口占用问题对着电脑调三个小时这时间完全可以去推进别的事情。6.2 答辩前必须能回答的三个核心问题我见过太多同学把PPT做得漂亮结果被一个问题问住“药品库存表里为什么要同时存drug_id和drug_name”如果你答不上来评审容易觉得代码不是自己写的。所以答辩前把下面三个问题练熟第一库存为什么要按批次分开答因为同一药品不同批次的有效期不同分开存储才能实现效期预警和先入先出。第二销售出库时怎么防止库存扣成负数答在更新SQL里加quantity #{num}条件并配合事务回滚。第三如果库存流动数据量很大报表统计会很慢怎么优化可以从索引、分页查询、统计聚合表上回答。即使系统还没做到那一步也能展示你的思考。最后再说一个实际带项目的小经验无论你是自己从零开发还是基于已有源码做二次修改都把数据库设计说明书当成重点。老师最常问的永远是表和表之间的关系。把ER图里每个实体、每个关系理清楚再配合一两个业务闭环的讲述这场答辩基本就稳了。医药管理系统不是多高深的项目但只要你把行业字段、主从表、库存批次、权限控制这几个点讲明白它就能从一摞相似题目里跳出来成为一份让人印象深刻的毕业设计。