我先说明一下从你给的标题看这显然是一个毕业设计/课程设计方向的完整项目交付包。我的博客就要围绕这套东西的实际开发与交付来写从架构选型、数据库设计、前后端实现、部署、报告、答辩六个维度展开给出真正能落地的干货而不是泛泛介绍功能菜单。刚开始接触这类系统的时候很多同学容易上来就陷进代码细节里一写就是几周最后发现要么数据库设计有问题要么前后端对不上接口要么部署环节一头雾水。这篇内容我就按一套完整的毕业设计交付物来拆——程序、数据库、报告、部署、答辩指导——每块都讲清楚为什么要这样做以及实际操作中怎么避坑。1. 内容整体设计与思路拆解1.1 这套技术栈为什么是标配Java Vue Spring Boot 这套组合在近几年的毕业设计里几乎成了默认选项背后有很现实的原因。后端用 Spring Boot 是因为它把 Spring 家族里最繁琐的配置工作都干掉了。早期用 Spring MVC 写一个能跑起来的 Web 项目光 XML 配置就能写几百行数据源、事务、拦截器、视图解析器全是手写配置。Spring Boot 用自动配置加约定优于配置的思路一个启动类加几个注解内嵌 Tomcat 就能直接跑起来这对学生来说实在太友好了。前端用 Vue 则是因为它的上手曲线比 React 平缓得多。Vue 的模板语法非常直观像v-for、v-model、v-if这些指令学过 HTML 和 JavaScript 基础的人几乎一两天就能上手写页面。对于药店管理系统这种以表格表单为主的管理后台Vue 的组件化开发方式能很好地控制代码复杂度。数据库这块MySQL 没有任何悬念。免费、轻量、文档多、社区活跃学生机器上跑毫无压力答辩时老师也基本都用 MySQL 来问问题。这套组合还有一个隐藏优势——网上资料特别多遇到报错一搜基本都有现成答案对开发经验不多的同学来说这比技术先进性更重要。1.2 药店业务场景的独特性很多人觉得药店管理系统就是换个名字的 CRUD增删改查项目这种理解会直接拉低系统的设计质量。药店管理系统和普通的后台管理系统相比有几个明显的业务特点第一药品有严格的批次和效期概念。同一个药品可能进了好几批货批号不同、生产日期不同、有效期不同销售的时候必须先卖效期近的批次。如果数据库设计里不单独维护药品批次表后面做效期管理、批次管理全都是空中楼阁。第二库存变化涉及的类型多。入库、出库、销售、退货、报损、盘点每一种操作都会影响库存数量而且都要留痕。设计的时候需要一个统一的库存流水表来记录每次变动这样才能回答这个药品库存为什么少了这类问题。第三销售流程关联性强。一次销售可能涉及多条药品明细同时可能关联会员信息、结算信息主从表结构是必须的——销售单主表加销售明细子表通过主键关联。只有把这种关联关系想清楚后面的功能开发才顺畅。第四处方药需要登记购买者信息。根据行业规范处方药销售要有记录包括购买者姓名、联系方式、处方信息等这在学校答辩时也是一个很好的业务亮点。1.3 功能模块的合理切分药店管理系统的功能模块划分我建议围绕一条主线进货供应商→ 库存 → 销售顾客→ 统计再挂上员工和系统管理。系统管理员工账号管理、角色权限、密码修改、操作日志。权限不做太复杂基于角色的菜单级别控制就够比如管理员能看到全部菜单普通员工只能看到销售和库存相关页面。药品管理药品分类、药品信息维护、批次效期管理、库存查询与预警。药品信息是核心主数据字段要全而不冗余比如药品名称、通用名、规格、单位、生产厂家、批准文号、销售价格、库存上下限。供应商与采购管理供应商信息维护、采购订单管理、采购入库。这部分数据流是采购单 → 入库单 → 批次库存增加。销售管理前台收银、销售退货、销售流水查询。这是使用频率最高的模块交互要简单快捷。会员管理会员档案、积分管理、消费记录。统计报表销售日报、销售排行、库存预警、毛利统计。这样的切分逻辑清晰每个模块都能对应到药品零售行业的真实操作流程报告里也很容易写出业务背景和分析。2. 数据库设计与核心实现要点2.1 表结构设计的核心思路数据库设计是这个项目的根基表结构一旦定错后面改起来相当痛苦。我基于常见实践推荐核心表结构如下t_admin员工表主键、登录名、密码MD5加盐、姓名、手机号、角色ID、状态、创建时间。t_role角色表角色ID、角色名称、备注。t_category药品分类表分类ID、分类名称、父分类ID、排序。t_drug药品表药品ID、通用名、商品名、分类ID、规格、单位、生产厂家、批准文号、零售价、会员价、库存上限、库存下限、状态。t_batch药品批次表批次ID、药品ID、批号、生产日期、有效期、采购价格、库存数量、供应商ID。t_supplier供应商表供应商ID、名称、联系人、电话、地址、备注。t_purchase采购单表采购单号、供应商ID、采购日期、采购总金额、操作人ID、状态。t_purchase_detail采购明细表明细ID、采购单ID、药品ID、批号、采购数量、采购单价、生产日期、有效期。t_sale销售单表销售单号、会员ID、销售日期、总金额、实收金额、找零、操作人ID、支付方式。t_sale_detail销售明细表明细ID、销售单ID、药品ID、批次ID、销售数量、销售单价、小计金额。t_stock_record库存流水表流水ID、药品ID、批次ID、变动类型入库/出库/销售/退货/报损/盘点、变动数量、变动前库存、变动后库存、关联单据号、操作时间。t_member会员表会员ID、会员卡号、姓名、手机号、积分、余额、注册日期。这套结构里有两个容易被忽视但很关键的设计。第一个是药品表和批次表分开药品是静态主数据批次是动态库存载体。第二个是所有库存变动都走库存流水表这样库存数据可追溯、可对账出问题能查。2.2 关键字段与约束的设计意图先说药品价格字段。我之前见过一些项目把价格字段设计成float或double这在 Java 里涉及浮点数精度问题——算完总价出现 0.9999999 这种莫名其妙的结果。正确做法是用DECIMAL(10,2)类型存金额Java 实体用BigDecimal接收计算时用BigDecimal而不是直接转 double。药品表里必须有库存上下限字段这是库存预警功能的数据基础。预警逻辑很简单当某药品所有批次库存数量之和低于下限时系统在首页给出预警提示。但要注意如果只查库存上下限而不考虑批次效期会出现库存有货但近效期不能卖的情况库存数量不等于可售数量。批次表里expiry_date字段建议加索引因为效期查询和排序是高频操作。采购明细里同时记录batch_no批号、production_date生产日期、expiry_date有效期入库时同步生成批次记录这是后面所有效期管理的数据源头。任何一个环节漏配了批号后面的批次追踪就会断链条。员工表密码存储有个经典问题。直接用 MD5 加密其实有安全风险因为网上有大量 MD5 彩虹表。安全做法是 MD5 加随机盐再加密Java 里可以用DigestUtils.md5Hex(password salt)来实现存储的是盐值:密文这种格式校验时间再拼接一次比较。答辩时老师问到密码安全问题这个回答会加分。2.3 数据库设计中的避坑经验设计数据库时最容易踩的坑是冗余字段处理不当。比如药品分类有些人直接在药品表里存分类名称分类一改名就要全表更新这是典型的反范式设计。正确做法是分类单独建表药品表只存分类ID。还有一个常见问题是命名不规范。表名、字段名所有的命名必须用英文字母大写或小写统一风格不要出现拼音缩写、混用大小写、使用 MySQL 保留关键字比如用describe作字段名。之前见过有人把字段命名为money、count这种虽然不是保留字但容易出歧义建议用total_amount、stock_quantity这种见名知意的命名。日志表和主表规模差距很大操作日志这类流水数据会越来越多。运行一段时间后查询变慢是正常现象答辩时如果老师问性能问题可以回答操作日志表按月建分区或定期归档历史数据这比纯写 CRUD 有深度得多。3. 后端核心功能实现与实操过程3.1 Spring Boot 项目搭建与分层结构Spring Boot 项目的创建很简单用 IDE 的 Spring Initializr 直接生成即可。Java 版本建议 1.8 或 11取决于学校环境和你自己机器装的 JDKSpring Boot 版本建议 2.x 稳定版注意不要选太高的版本——有些网上的教程基于旧版本写的版本差异会导致配置不兼容对新手排查起来很崩溃。后端代码的分层我建议严格遵循主流规范这不仅是代码组织问题答辩时老师看你代码第一眼就是看包结构controller 层接收前端请求参数校验调用 service返回统一结果。service 层业务逻辑核心事务控制在这里。库存不足以要报错销售成功要同时生成多条记录这些都是在 service 层用Transactional控制的。mapper/dao 层用 MyBatis 操作数据库。entity 层数据库表对应的实体类。common 层统一返回结果类、全局异常处理器、工具类。config 层CORS 跨域配置、拦截器配置、WebMvc 配置。当 controller 到位、service 实现逻辑完整、mapper 写好 SQL整个后端骨架就算完成了。实际开发时顺序建议先写 entity 和 mapper再写 service最后写 controller因为依赖关系是从下往上的。3.2 统一返回结果与全局异常处理前后端分离的项目接口返回格式必须统一。我会定义一个Result类包含三个字段code状态码、msg提示消息、data具体数据。所有接口都返回这个结构前端拿到后统一判断code是否为 200再决定下一步操作。public class Result { private Integer code; private String msg; private Object data; public static Result success(Object data) { Result result new Result(); result.setCode(200); result.setMsg(操作成功); result.setData(data); return result; } public static Result error(String msg) { Result result new Result(); result.setCode(500); result.setMsg(msg); return result; } }全局异常处理是很多同学容易忽略的功能。没有全局异常拦截器时代码里任何 RuntimeException 都会抛给前端一个默认的 Whitelabel Error Page又难看又难调试。用RestControllerAdvice加ExceptionHandler做一个统一拦截把所有业务异常、运行时异常都转成统一的 Result 格式返回前端拿到错误信息直接弹提示体验好很多RestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(BusinessException.class) public Result handleBusinessException(BusinessException e) { return Result.error(e.getMessage()); } ExceptionHandler(Exception.class) public Result handleException(Exception e) { e.printStackTrace(); return Result.error(系统异常 e.getMessage()); } }自定义一个BusinessException类在 service 里碰到业务不满足的情况就直接抛出比如库存不足药品已过期用户名已存在前端统一处理错误提示这个设计在答辩时非常加分。3.3 药品入库与库存变动的完整流程采购入库这个模块是整个系统里最有技术含量、也最值得写进报告的核心流程。它的业务逻辑是前端提交采购单包含供应商信息和多条药品明细→ 后端创建采购单主表 → 创建采购明细 → 生成批次记录 → 增加库存 → 写入库存流水。这个流程任何一个环节断了都会造成数据问题。核心代码如下简化后Service public class PurchaseServiceImpl implements PurchaseService { Autowired private PurchaseMapper purchaseMapper; Autowired private PurchaseDetailMapper purchaseDetailMapper; Autowired private DrugMapper drugMapper; Autowired private BatchMapper batchMapper; Autowired private StockRecordMapper stockRecordMapper; Override Transactional(rollbackFor Exception.class) public void addPurchase(PurchaseDTO dto) { // 1. 保存采购单主表 Purchase purchase new Purchase(); purchase.setSupplierId(dto.getSupplierId()); purchase.setPurchaseDate(new Date()); purchase.setTotalAmount(dto.getTotalAmount()); purchase.setStatus(1); // 1 表示已入库 purchase.setOperatorId(dto.getOperatorId()); purchaseMapper.insert(purchase); // 2. 遍历明细逐条生成批次与库存记录 for (PurchaseDetailDTO item : dto.getItems()) { // 保存采购明细 PurchaseDetail detail new PurchaseDetail(); detail.setPurchaseId(purchase.getId()); detail.setDrugId(item.getDrugId()); detail.setBatchNo(item.getBatchNo()); detail.setQuantity(item.getQuantity()); detail.setPurchasePrice(item.getPurchasePrice()); detail.setProductionDate(item.getProductionDate()); detail.setExpiryDate(item.getExpiryDate()); purchaseDetailMapper.insert(detail); // 检查批次是否已存在不存在则新建 Batch batch batchMapper.findByDrugIdAndBatchNo(item.getDrugId(), item.getBatchNo()); if (batch null) { batch new Batch(); batch.setDrugId(item.getDrugId()); batch.setBatchNo(item.getBatchNo()); batch.setProductionDate(item.getProductionDate()); batch.setExpiryDate(item.getExpiryDate()); batch.setStock(0); batchMapper.insert(batch); } // 批次库存增加 batchMapper.increaseStock(batch.getId(), item.getQuantity()); // 写入库存流水 StockRecord record new StockRecord(); record.setDrugId(item.getDrugId()); record.setBatchId(batch.getId()); record.setType(采购入库); record.setChangeQuantity(item.getQuantity()); record.setRelationNo(purchase.getPurchaseNo()); record.setOperationTime(new Date()); stockRecordMapper.insert(record); } } }这段逻辑里最核心的一点就是Transactional注解。采购入库是多张表同时操作如果不加事务控制万一第 3 条明细插入失败前 2 条已经写进数据库里了——数据就处于一种对不上账的脏状态。加上事务后任何一个环节抛异常整个操作自动回滚到初始状态保证数据一致性。3.4 销售出库的并发与效期控制销售模块是另一条核心链路。前端提交销售单传购物车里的药品列表和一个批次ID列表后端处理逻辑是校验药品是否有效、效期是否在安全范围内、批次库存是否充足、总金额计算是否正确然后扣减库存、生成销售单、写入流水。效期校验这里很容易被忽略但却是药店系统区别于普通进销存系统的关键点。销售时通过批次查有效期如果有效期距今少于某个阈值比如 30 天可以设置为不允许销售或者在界面上做醒目的近效期标记。实际业务里效期不佳的药品要锁定或者特价处理这都可以作为系统功能亮点写进报告里。并发问题值得单独提一下。两笔销售同时抢最后一件库存数据库层面怎么处理MySQL 的更新语句默认加行锁所以只要用类似UPDATE t_batch SET stock stock - #{qty} WHERE id #{id} AND stock #{qty}这种带条件的更新语句天然能避免超卖。执行后影响行数为 0 就说明库存不足直接提示用户这种写法比先查再改安全得多。销售退货则是反向流程校验退货数量不能超过已售数量批次库存增加写入退货类型的流水同时更新销售单状态。如果会员付款了还涉及退款逻辑可以简化成线下退款、系统打标记但流程要能在报告里自圆其说。3.5 角色权限控制的实现思路药店管理系统里有管理员和普通员工两类角色权限控制不需要上 Spring Security 这种重框架用拦截器加自定义注解就能实现。思路是这样的登录成功后把用户信息和角色ID写入 Session或者生成 Token 存入 Redis对毕设来说 Session 就够。定义一个拦截器拦截所有请求在 handler 里判断这个接口需要什么角色才能访问。具体用自定义注解RequirePermission(admin)标注在 Controller 方法上拦截器读取注解并和当前用户角色比对没有权限直接返回无权限。这个方案代码量少、逻辑清晰、很容易讲清楚而且能在答辩时展示你对权限设计的理解——基于角色的访问控制RBAC。比直接集成 Spring Security 更能体现自身思考。4. 前端 Vue 页面设计与交互实现4.1 前端项目结构与页面规划前端用 Vue 2 Element UI 是最稳妥的组合Vue 3 也完全可以但 Element Plus 的资料相对少一些对新手来说 Vue 2 的生态更友好。项目初始化用 Vue CLI 或 Vite 都行推荐 Vite启动速度快很多。前端页面结构大致如下登录页账号密码输入校验后跳转首页。系统布局左侧菜单栏 顶栏 主内容区域。药品管理页药品列表分页查询、搜索、新增/编辑弹窗、删除按钮、库存预警标识。采购入库页采购单表单选供应商、明细表格多行添加药品选批次、填数量价格。销售收银页购物车式界面左侧药品选择列表右侧结算栏支持会员卡号录入。库存查询页批次维度的库存列表支持按效期排序筛选。统计报表页用 ECharts 展示柱状图和饼图。路由配置分两份一份是/login一份是主布局下的子路由比如/system/drug、/system/purchase、/system/sale。侧边菜单用el-menu子菜单控制在两级以内。4.2 简单踩坑记录前后端联调、跨域、日期格式前后端分离开发最坑的第一关是跨域。Vue 开发服务器默认端口是 8080Spring Boot 默认端口是 8080 或者你配置的 8081/9999两边端口不同浏览器会拦截跨域请求。解决办法有两种。第一种在前端配置代理在vue.config.js里配置devServer.proxy把/api开头的请求转发到后端地址这样浏览器看到的是同源请求生产环境再用 Nginx 反向代理。第二种在后端配置 CORSSpring Boot 里写一个WebMvcConfigurer实现类允许特定来源跨域。对毕设来说前端代理方案更标准也更接近真实项目做法我推荐用这个。日期格式是另一个很经典的坑。Spring Boot 默认返回的日期格式是yyyy-MM-ddTHH:mm:ss.SSSZ这种 ISO 格式而前端 Element UI 的日期组件默认传yyyy-MM-dd格式。所以要么后端配置统一日期的序列化格式在application.yml里加spring: jackson: date-format: yyyy-MM-dd HH:mm:ss time-zone: GMT8要么前端传值前先格式化。两种方式都要做前端负责传得对后端负责返得对两边都调整一下才能不出幺蛾子。4.3 Element UI 的高频组件用法与性能提示Element UI 里高频使用的组件就是表格el-table、表单el-form、弹窗el-dialog、提示el-message、下拉el-select、日期el-date-picker。药品列表页是典型的表格页分页建议把查询参数放在data里统一管理方法约定为loadData()每次点击搜索、翻页、删除后重新拉取列表。后端接口对应PageHelper.startPage(page, size)加 MyBatis 分页插件返回的数据结构里带上total总数前端分页组件才能正常显示总页数。el-table的每一列建议都设定好width或min-width不做全局设定会导致不同浏览器下布局错位。时间列设置formatter函数进行格式转换。金额列设置alignright和sortable排序属性。这类小细节能让页面整体观感专业很多答辩演示时老师看了也会觉得完成度不错。还有一个性能细节不要直接在表格里对每一行做复杂的v-if嵌套计算。比如药品名称加库存预警标识推荐在列表查询接口的 SQL 里直接把预警状态算好前端拿到值直接渲染不要让前端遍历每行去判断。数据量小的时候没感觉几万条药品时就能感到明显的卡顿差别。4.4 前端交互流程的体验优化药店系统的日常使用场景是店员在收银台前快速操作所以销售页面的交互流畅度直接影响使用体验。我之前做的时候在销售收银页做了几个优化实测效果很明显药品搜索区放大支持拼音码搜索比如输入apc能搜出阿莫西林胶囊这里用 Vant 或 Element 的 autocomplete 组件也可以直接在数据库加一个拼音码字段作为冗余条件。加入购物车后默认数量为 1双击数量可快速修改。计算合计和找零放在结算栏实时刷新。折扣金额和会员价做了联动。键盘回车事件绑定到扫码枪输入框扫完条码自动添加药品到购物车焦点自动回到扫描框。这在真实的药店收银场景里是刚需功能展示出来会非常加印象分。前端不是能跳转页面就行。答辩演示时老师看到扫码枪输入这种细节会认为你真的思考过业务场景而不是只会复制粘贴 demo。5. 部署流程与项目文档5.1 本地部署步骤部署是整个项目里环节最多、最容易出问题的地方。建议部署环境用 Windows 手动部署先跑通再考虑 Docker 和服务器。具体步骤如下安装 JDK 1.8配置JAVA_HOME环境变量。装完后在命令行输入java -version确认安装成功。安装 MySQL 5.7 或 8.0设置 root 密码为简单好记的比如123456答辩机器上方便演示。用 Navicat 或命令行执行项目附带的pharmacy.sql文件一键导入数据库和样本数据。修改后端项目的application.yml里的数据库账号密码改成你自己机器的实际配置。启动后端在 IDEA 里直接运行启动类或打成 jar 包后用java -jar pharmacy-server.jar启动。前端项目在package.json所在目录执行npm install安装依赖再npm run dev或npm run build启动。前端如果npm install时报错检查一下 Node.js 版本Vue 2 的项目一般需要 Node 14 或 16。装完依赖后npm run dev启动开发服务器浏览器打开 http://localhost:8080 就能看到登录页。5.2 Nginx 部署与跨域问题的生产级解法如果要在服务器上部署有的学校答辩要求提供演示链接建议用前端打包成静态文件 Nginx 托管 后端 jar 包运行的方式。前端执行npm run build打包后生成一个dist目录。把dist目录里的内容上传到服务器某个目录比如/usr/share/nginx/html。Nginx 配置里设置root指向这个目录并配置location /api/反向代理到 Spring Boot 服务server { listen 80; server_name your_server_ip; root /usr/share/nginx/html; index index.html; location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }这样前端页面和后端接口走同一个域名和端口不存在跨域问题。后端 jar 包用nohup java -jar pharmacy-server.jar log.txt 21 在后台运行保证服务器重启后程序还在。数据库装在服务器上注意开放防火墙对应端口。这套部署方案是生产环境常见形态把这套流程写进部署教程里含金量比单纯本机运行高得多。5.3 项目报告写作的实用框架毕业设计报告不是期末论文它的核心逻辑是你做了什么、为什么这样做、效果如何。我推荐这样一个章节框架也基本是各高校通用的结构绪论课题背景与意义、国内外研究现状、研究内容与方法这部分别写太长重点是引出你为什么做药店管理系统。相关技术介绍Java、Spring Boot、Vue、MySQL 的关键特性和选型理由。每个技术控制在 300-500 字别变成抄百度百科。需求分析系统角色、功能性需求模块清单加用例描述、非功能性需求性能、安全、可维护性。系统设计总体架构、功能模块设计、数据库设计E-R 图 表结构。系统实现按模块写每个模块配界面截图和核心代码片段代码只贴关键片段别整页贴代码。系统测试功能测试用例表、测试结果、缺陷修复记录。总结与展望总结完成的工作指出可改进的地方。写报告有一个关键技巧数据库设计部分一定要画 E-R 图系统实现部分一定要有运行界面截图。这两样东西是老师看报告时最先翻的地方有图比有大段文字有说服力得多。5.4 数据库设计与前端实现如何写进报告数据库设计部分要把每个表的关键字段用表格列出来尤其是那些有业务意义的字段要解释清楚。比如药品分批次的逻辑、库存预警字段、累计销售数量字段。我当时写报告时把库存流水表单独列出来详细解释——该表记录了所有库存变动包括采购入库、销售出库、退货、盘点便于追溯和统计老师在这个方向上追问了很多问题也给了不错的评价。前端实现部分除了截图和代码还需要补一个接口联调说明。说明某个页面调用了哪些后端接口、传了哪些参数、返回了什么数据。这样能体现你不仅会写前端还理解前后端数据交互。如果页面里用了 Element UI 的某些特性组件也可以简单提一下。写报告的原则是宁缺毋滥、重点突出。能画出完整架构图和技术流程图优先画架构图代码截图只截核心几行的效果不要截满屏。架构图推荐用 draw.io 画免费好用画完导出 PNG 插入 Word。6. 答辩准备与常见问题实战6.1 答辩前的准备清单答辩的本质是向老师证明系统是我做的我懂每个环节的原理。准备答辩前建议按以下清单自查能有效应付大多数提问能说清楚整个项目的技术架构和请求流转过程登录 → 前端 API 请求 → 后端 Controller → Service → Mapper → 数据库 → 返回结果 → 前端渲染。能解释项目中所有核心数据表的字段含义和表之间的关系。能现场演示核心功能流程新增药品 → 采购入库 → 查询库存 → 销售/退货 → 查看统计报表。能指出系统的优点和不足至少能说明两个改进方向。能回答为什么选择这个技术“为什么这样设计数据库”“怎么解决某个业务问题这类问题。答辩时演示代码权限关系的 open 方式建议先跑起来再展示代码顺序是系统界面 → 主流程演示 → 数据库设计 → 核心代码。别上来就贴代码老师看代码的耐心很有限。6.2 高频问题与回答思路整理根据我见过的毕业答辩问题整理一下高频问题和推荐回答供参考为什么选择 Spring Boot回答思路Spring Boot 内置了 Tomcat无需额外部署容器自动配置简化了项目搭建生态成熟与 MyBatis、Vue 等搭配方便这些特性适合快速开发中小型管理系统。账号密码是怎么存储的回答思路使用 MD5 加盐加密存储数据库里不保存明文密码。数据库设计时预留了盐值字段校验时用盐值结合输入密码重新计算摘要。库存预警怎么实现的回答思路药品表设计了库存下限字段批次表保存了当前各批次库存量。查询时按药品汇总批次库存和下限对比低于下限则预警。同时结合效期字段近效期批次也会标记预警。一个药品对应多个批次销售的时候怎么选择批次回答思路销售时前端按药品查询所有批次先按效期排升序先进先出先选择效期近的批次优先出售确保效期管理。同时校验批次库存是否足够。数据库怎么防止超卖回答思路使用带库存条件的 Update 语句UPDATE t_batch SET stock stock - #{qty} WHERE id #{id} AND stock #{qty}更新影响行数为 0 表示库存不足事务回滚。前端怎么和后端通信回答思路通过 HTTP 请求后端返回统一 JSON 格式。开发时用 Vue CLI 的代理解决跨域部署时用 Nginx 反向代理。6.3 演示翻车急救手册答辩现场最怕代码跑不起来或数据库连不上这类突发状况。实战经验建议如下提前做好预案数据库连不上先确认 MySQL 服务是否启动Windows 按 WinR 输入services.msc找到 MySQL 服务手动启动。再用 Navicat 测试连接。答辩前 10 分钟提前启动好环境。前端页面白屏多半是后端启动失败导致的接口全挂。打开浏览器 F12 看 Console 报错看是 404、500 还是跨域。500 就去后端的 IDEA 控制台看错误信息。后端启动报端口占用命令行netstat -ano | findstr 8080找到占用进程的 PID再taskkill /PID [进程号] /F杀掉。忘记密码直接用 Navicat 改 t_admin 表里用户记录的密码字段生成新 MD5 密文更新进去即可。演示时发现数据不对提前准备一个重置 SQL 脚本一键清空业务数据并重新插入干净的演示数据答辩开始前执行一次就行。这些平时不起眼的操作在答辩关键时会成为救命稻草。7. 避坑总结与个人经验心得回头再看整个项目从需求分析到部署答辩最深刻的体会是——毕业设计的成败其实在动手写代码前已经决定了。数据库设计得够不够好、技术栈选得对不对、模块划分清不清晰这些决策层面的东西比敲代码本身重要得多。很多人一上来就打开 IDE 建项目结果做到一半发现表结构不合理推倒重来非常浪费时间。我建议动手之前花一个晚上把数据表全部建好把前端页面清单列清楚把接口列表写出来。接口列表就是页面和后端之间的桥梁——每个页面需要哪些接口、传什么参数、返回什么数据提前规划好。后面开发时按接口列表逐条实现前后端联调就会顺畅得多。这是这几年做项目下来最实用的一条经验。第二个经验是数据库一定要弄一份干净的初始化和示例数据脚本。做完一个功能模块就同步更新一次脚本保证任何时候重新执行脚本都能得到一个可演示的系统状态。这份脚本不仅是你本地开发调试的保障也是最后打包提交给老师时数据库交付物的重要内容。第三个经验是不要做完系统才写文档和报告而是每完成一个模块就顺手把截图、核心代码和遇到的问题记录整理下来。不然最后赶报告时你还要重新去翻代码回忆当时怎么实现的又费时又容易遗漏细节。答辩前老师的灵魂拷问往往就藏在这些细节里。这套 javavueSpringBoot 药店管理系统不管是从毕设完成度、工作量、业务完整性还是答辩可展示性来说都是很扎实的选题。照着上面的思路把每一步做扎实项目验收和答辩都不会有问题。
