首页 / 资讯中心 / 文章详情

SpringBoot智慧药店药品管理系统:从需求分析到答辩全流程拆解

SpringBoot智慧药店药品管理系统:从需求分析到答辩全流程拆解 ★ FEATURED ARTICLE
做毕设这几年药品管理系统算是被选烂了的经典题目但绝大多数成品还停留在“增删改查套壳”的阶段。这次分享的项目是一个基于SpringBoot的智慧药店药品信息管理系统最初是帮一个学弟做的毕业设计后来自己又重构了一版把库存预警、批次效期管理、供应商对账这些药店真实业务场景里的硬骨头啃了下来整体完成度比市面上一两百块钱买的Demo高不少。整套东西包含完整源码、毕业论文文档和答辩PPT这周刚帮他顺利通过了答辩。这篇复盘不打算吹技术多牛而是从选题思路、数据库设计、核心代码逻辑、论文写法到答辩话术把整个过程拆开揉碎讲清楚。项目本身技术栈并不花哨SpringBoot MyBatis Plus MySQL Redis Vue属于标准的Java Web毕设组合但里面的业务建模和异常处理思路是外面那些课程设计模板根本不会教你的。如果你正在纠结毕设选题或者已经选了药品管理但不知道怎么把深度做出来这篇文章应该能帮你在现有思路上打开一个口子。1. 项目整体定位与设计思路拆解1.1 为什么选药品信息管理这个方向毕设选题的第一个坑就是“太大”。我见过有人选“智慧校园系统”结果光功能模块就列了十几个最后论文写得像产品需求文档代码却只有登录和注册。药品信息管理这个方向之所以值得做是因为它属于典型的“小切口、深业务”场景——表面上就是库存增删改查但往深里挖药店的药品批号管理、有效期预警、处方药管控、供应商资质审核每一块都可以做出区分度。这个项目最终定位成“智慧药店”落点不是搞AI、搞物联网而是解决药店日常运营里三个核心痛点库存账实不符、近效期药品积压、进销存数据割裂。系统围绕这三个痛点设计了八个功能模块覆盖从药品入库、库存流转到销售出库、统计报表的完整链路。选这个题的第二层考虑是工作量可控。SpringBoot本身封装程度高一个CURD接口从Controller到Mapper往往不到十行代码配合MyBatis Plus的代码生成器基础接口几乎不用手写。省下来的时间可以全部砸在业务规则和论文深度上性价比很高。1.2 技术栈选型逻辑技术选型方面我坚持“主流稳妥、适度前瞻”的原则。后端用SpringBoot 2.7.x而非3.x原因很现实3.x强制要求JDK17很多学校机房和导师电脑的JDK版本还是8为了部署演示环节不出幺蛾子兼容性优先。ORM选择MyBatis Plus而不是原生MyBatis或JPA核心考虑是开发效率。MP内置的BaseMapper提供了大部分单表CRUD方法分页插件只需要两行配置。对比原生MyBatis每个实体都要手写XML里的resultMap和CRUD语句整体工作量至少省三分之一。而且MP的lambda条件构造器在做模糊查询、多条件组合筛选时非常好用代码可读性也强。数据库用MySQL 5.7没上8.0是因为5.7在Windows环境下的安装配置最省心而且学校机房的老机器跑起来也流畅。缓存和Token存储用Redis但从实际答辩演示的角度Redis也不是非用不可的——如果部署环境紧张完全可以用SpringBoot的EnableCaching缓存注解或者直接改成JWT无状态认证来替代。这个后面会细说。前端这块没有用前后端分离的大型框架而是采用Thymeleaf模板引擎 Bootstrap AdminLTE开源后台模板。好处是打包成一个Jar就能跑不需要单独部署Node服务答辩演示的时候不会出现“前端连不上后端”这种尴尬场面。技术选型在毕设答辩里几乎是必问项一定要能说清楚“为什么选A不选B”。建议把这句话记住技术选型的第一原则是解决当前问题的成本最低而不是技术本身有多新。1.3 功能模块拆解与边界划分系统最终划分成八个模块每个模块的职责和边界当初都经过仔细推敲毕竟毕设最容易犯的毛病就是模块划分混乱一个功能横跨三四个Controller。最终结构如下系统登录与用户权限模块管理员的账号管理、角色分配、菜单权限控制药品分类管理模块药品分类的层级结构维护药品信息管理模块药品基本档案名称、规格、厂家、批准文号药品库存管理模块入库、出库、库存查询、库存预警批号与效期管理模块批次绑定、近效期预警、过期药品停售供应商管理模块供应商档案和资质信息采购与入库管理模块采购单生成和入库审核流程销售与出库管理模块销售订单登记和出库扣减库存统计报表模块用ECharts展示库存周转和销售趋势数据这个设计要注意一个原则每个模块是独立可用的功能域模块之间通过领域ID比如药品ID、供应商ID关联不经由内部方法直接调用。比如销售出库需要扣减库存销售模块只负责生成销售单扣减库存通过调用库存服务暴露的接口完成。这样后期扩展RFID扫码、对接医保系统都不用破坏现有结构。2. 数据库设计与核心表结构解析2.1 表设计总览数据库设计是毕业设计论文里占分很重的部分也是最容易暴露“没做过真实项目”的地方。整套系统共设计了9张核心表这里列一下都是可以直接抄的作业。表名业务字段要点关键说明sys_userid, username, password, role_id密码采用BCrypt加密存储sys_roleid, role_name, role_key角色区分管理员、店长、店员drug_categoryid, parent_id, name自关联实现药品分类树drug_infoid, name, specification, manufacturer, approval_number, unit, price批准文号必须唯一索引drug_stockid, drug_id, batch_no, quantity, purchase_price批号药品ID联合唯一supplier_infoid, name, contact, phone, qualification_code资质编号要求非空purchase_orderid, supplier_id, drug_id, quantity, total_amount, status状态字段做流程控制sale_orderid, drug_id, batch_no, quantity, total_amount, buyer_name记录销售批次实现追溯stock_warningid, drug_id, threshold, warn_type预警规则可配置药品管理系统的核心不是药品信息表而是drug_stock库存表。这个表必须把批号作为一个独立维度拆出来因为同一款药品可能分多个批次进货生产日期、有效期、采购价都不一样。如果只做简单的数量加减一旦出现近效期药品你根本没法定位是哪一批出了问题。有效期字段我建议直接存在drug_stock表里用expire_date字段。查询近效期药品时直接按日期范围筛选SQL写起来简单索引命中率也高。很多参考项目把效期冗余到药品主表那是有问题的——同一个药不同批次效期完全不同放主表里根本没法查。2.2 批号与效期管理的建模细节批号与效期这段是药品管理系统区别于普通进销存系统的灵魂也是答辩时最能讲出东西的点。设计思路是入库时每个批次生成一条独立的stock记录字段包含batch_no批号、production_date生产日期、expire_date有效期至、quantity当前库存数量。药品界面上展示的库存总量是同一药品ID下所有批次数量的聚合值。查询逻辑用了一个视图来简化按药品维度聚合出总库存再单独提供批次明细列表。近效期预警的实现是一个定时任务每天凌晨扫描所有到期日在未来90天内的批次分三个警戒级别推送90天内到期黄色预警提示可参与促销30天内到期橙色预警禁止大额采购入库已过期红色预警自动锁定该批次禁止销售这套逻辑写进论文里非常出效果业务闭环完整而且实现成本并不高。核心就是一条SQL查询过期批次再定时调一下状态。2.3 用户权限表的三层结构权限模型的实现走了RBAC基于角色的访问控制的轻量方案一共三张核心表用户表、角色表、用户角色关联表。不搞菜单权限点级别那么细到角色级别就够了。管理员、店长、店员三个角色各司其职管理员拥有全部权限店长能操作采购和库存调价店员只能做销售开单和库存查询。在实际拦截层面SpringBoot的拦截器对路径做通配符匹配比如/api/admin/**需要管理员角色/api/sale/**登录即可访问。代码里配一个自定义注解配合拦截器比SpringSecurity省事得多——SpringSecurity虽然功能强但对于毕设系统来说配置繁琐密码加密那一套交接成本也比较高答辩的时候解释起来容易把非技术评委绕晕。3. 核心功能实现与关键代码逻辑3.1 登录认证与操作日志的实现登录认证这块我是在Session和JWT之间权衡过的。最终选择了JWT Redis黑名单方案原因是答辩的时候可以展示“无状态认证”这个亮点同时黑名单机制解决了JWT无法主动失效的痛点。用户登录成功后服务端生成Token返回前端同时把Token的jti唯一标识写入Redis设置过期时间为24小时。每次请求拦截器里校验Token签名和Redis中的状态用户修改密码或退出登录时把jti加入黑名单并对应用户所有Token失效。逻辑不复杂效果却比裸用JWT安全得多。还有一个容易被忽略但答辩加分的设计是操作日志。用AOP切片技术在Service层做一个切面所有带Log注解的方法都会自动记录操作人、操作类型、操作详情和IP地址。数据落到operation_log表里管理员可以在后台查看。这个功能代码量并不大一个注解加一个切面类就搞定但能很好地体现工程意识。说说这个切面的核心逻辑Aspect Component public class OperationLogAspect { Autowired private OperationLogMapper operationLogMapper; Pointcut(annotation(com.pharmacy.common.annotation.OperationLog)) public void logPointCut() {} Around(logPointCut()) public Object around(ProceedingJoinPoint point) throws Throwable { long beginTime System.currentTimeMillis(); Object result point.proceed(); long time System.currentTimeMillis() - beginTime; saveLog(point, time); return result; } }用Around环绕通知既执行了原方法又能记录执行耗时。这比用过AOP的人会习惯性用前置通知更合适因为只有环绕通知能拿到方法返回值也就能记录成功失败状态。3.2 库存预警的定时任务实现库存预警是整个系统里技术含量最高的一块也是论文里的重点章节。我用SpringBoot自带的Scheduled注解实现定时任务每天早上8点执行库存扫描。Component public class StockCheckTask { Autowired private DrugStockMapper drugStockMapper; Scheduled(cron 0 0 8 * * ?) public void checkExpiringDrugs() { LocalDate today LocalDate.now(); LocalDate warningDate today.plusDays(90); ListDrugStock expiringStocks drugStockMapper.selectExpiringStocks(warningDate); for (DrugStock stock : expiringStocks) { generateWarning(stock); } } }这里有几个细节整理一下都是实际开发中踩过的坑cron表达式是秒级精度5位或者6位都有人写但Spring的Scheduled用的是6位区分“秒 分 时 日 月 周”。0 0 8 * * ?表示每天早上8点整执行一次问号用于“周”字段表示不指定具体星期几。这里写错了任务根本不会触发而且Spring启动时不会报错排查起来很费劲。定时任务默认是单线程串行执行。如果任务执行时间超过1秒而中间又有其他任务会互相阻塞。建议在配置类里加一个TaskScheduler线程池配置。我这边是扫描写日志耗时不长但稳妥起见还是配了。关于预警状态我用的是生成预警记录标记批次状态。不直接删除库存数据也不直接改过期批次的数量而是通过状态字段隔离保证原始数据可追溯。3.3 JWT拦截器和Token校验的代码实现拦截器这一层我实现了前置拦截、Token校验、用户信息注入三个职责有几个细节值得写一下。登录接口放行、其余接口全部拦截。路径上排除掉/api/login、/error、静态资源的映射路径。如果框架用的拦截器注册类添加排除路径时记得要用addPathPatterns(/api/**)的写法限定拦截范围别直接用/**把静态资源也拦住。Token从Header的Authorization字段获取兼容Bearer前缀格式这是行业内比较通用的做法解析失败直接返回401错误码。校验通过后把解析出的userId和roleKey塞到request attribute里后续Controller通过RequestAttribute直接拿避免写工具类到处调Token解析。这段登录校验逻辑在答辩时几乎百分百被问到建议不要只停留在“能跑”阶段把“为什么存Redis”“为什么不用SpringSecurity”“Token过期怎么办”这三个问题提前想清楚面试基本就稳了。3.4 药品入库到出库的完整业务闭环药品入库和出库是整个系统的主动脉业务流程的严谨性直接决定系统成败。入库是一个事务性的操作先看整体顺序填制采购单选择供应商、药品和数量此时库存不变化采购单审核审核前可以做修改和撤销审核通过后点击“确认入库”系统自动执行库存增加逻辑写入批次信息批号、生产日期、有效期同时生成入库流水这个设计为什么不让入库直接改库存因为如果采购单还在审核中就直接加库存财务核对时账目会全部对不上这在真实的药店管理系统里是大忌。虽然毕设场景下不一定有这么严的财务对账需求但把这个流程做出来在论文里写成“采购流程控制”会比单纯“新增药品库存”的用例高级很多。出库是逆向流程销售订单登记提交时校验该批次库存是否充足充足则扣减库存、生成出库记录并计算销售额。这个扣减环节同样必须加事务控制防止并发操作时库存数量变成负数。这里有个典型的并发场景问题值得思考两个收银员同时卖同一盒布洛芬库存只剩1盒两人同时提交订单如果不对库存做乐观锁校验系统会允许两笔订单都通过库存变成-1。解决方式是在扣减库存的UPDATE语句里加上WHERE quantity #{num}的条件影响行数为0则抛异常回滚。这类细节写进论文能体现一定的知识储备。4. 前端页面与展示效果的关键设计4.1 页面布局与交互方式虽然这个项目不是纯粹的前端项目但页面美观程度在很大程度上影响答辩现场的第一印象。模板选用的是AdminLTE这是一套基于Bootstrap的开源后台模板整体风格简约专业做毕设完全够用。布局采用经典左右结构左侧是菜单栏右侧是内容区。菜单按照模块划分折叠分组并依当前页面高亮显示。顶部导航栏放用户名下拉框包含修改密码和退出登录。每一个列表页都做了搜索栏支持按药品名、分类、厂家等条件组合筛选。表单页都做了必填校验提交失败时使用弹窗提示而不是纯页面刷新确保交互体验流畅。首页设计了一个数据看板包括今日销售额、今日订单数、库存预警数量、低库存药品列表配合ECharts的折线图和饼图展示近7天销售趋势和分类占比。这块在答辩演示的时候视觉冲击力很强比逐个页面介绍功能要有说服力得多。ECharts的引入很简单不过有几个细节需要留意图表容器必须有明确的高度否则图表会被压缩成一片空白异步加载数据的话在调用setOption前务必确认DOM已经挂载完成可以放在mounted钩子里。4.2 图表统计的数据查询优化统计报表这个模块最容易掉进“全表扫描”的坑。举个例子统计近7天销售额如果直接对sale_order表执行GROUP BY DATE(create_time)数据量一大查询就很慢。优化思路是单独建一张每天汇总的统计表由定时任务每天凌晨把前一天的数据聚合写入查询时直接查聚合表。这个设计在论文里有两种写法一种是“数据统计模块设计”另一种是有分量的“数据仓库轻量建模”。其实就是一张冗余汇总表但同样的工作用“轻量级数仓”这个角度去包装论文档次完全不一样。这种原则同样适用于低库存预警的统计页面。4.3 Thymeleaf与Vue的取舍心得网上很多毕设教程喜欢SpringBootVue前后端分离但我最终选了Thymeleaf模板引擎原因不只是部署简单。一个很现实的点在于前后端分离的项目答辩需要有Node环境支撑而答辩用的电脑往往没有预装Node相关依赖。有一次答辩现场某同学的前端项目在指定电脑上跑不起来只能展示Postman接口调试截图——这种体验是比较遗憾的。Thymeleaf方案里后端Controller返回视图名称Model里绑定数据模板里用th:each遍历渲染表格。这套模式虽然看起来传统但胜在稳定可靠整个项目打成一个Jar包Java环境在就能跑。如果你将来要投简历展示项目前后端分离的项目可以作为亮点来说。但从毕业设计的稳妥交付角度Thymeleaf模板是不容易出错的方案。各有权衡可以根据情况二选一。5. 论文撰写与答辩展示的准备策略5.1 论文结构规划与各章节写作要点毕业论文文档通常是学校要求的结果导向型文本。这个项目的论文最终结构如下可直接作为参考第一章 绪论交代药品管理信息化的背景列举2-3篇近年文献知网上找“药品库存管理”“药品信息管理系统”等关键词即可最后说明论文主要工作内容。这块三四页即可不宜过长。第二章 相关技术介绍简要介绍SpringBoot、MyBatis Plus、MySQL、Redis、ECharts等。注意不要写成大段百科摘抄每门技术写两三段功能简介及应用场景即可导师重点看的是“简述其在本系统中所承担的角色”这句话。第三章 系统分析需求分析、可行性分析、用例图。用例图是必须的用绘图工具画三个用例图管理员、店长、店员三个角色分别画这是系统分析的标配。第四章 系统设计架构设计、功能模块设计、数据库设计。数据库设计是重点所有表的字段清单做成表格放进去加上E-R图。这章是论文的篇幅担当建议写到15页以上。第五章 系统实现按模块逐块描述每个模块配上核心代码片段界面截图。代码不能贴太长每段控制在20行内起到说明作用即可。第六章 系统测试功能测试用表格列出测试用例编号、测试项、输入数据、预期结果、实际结果性能测试可以写一个用JMeter或者Postman压测的结果体现工作量。章节之间的逻辑递进关系也很重要很多评审老师对逻辑结构是很看重的。绪论到技术介绍、从分析设计到实现测试每一步都要承接上一步环环相扣论文读起来会顺畅很多。5.2 答辩PPT的页面逻辑与演示顺序整个答辩过程大概10-15分钟PPT结构建议控制在10页以内。我帮学弟设计的顺序是封面目录1页、选题背景与意义1页、技术架构图1页、数据库设计1页、功能截图3-4页、核心代码展示1页、测试结果1页、总结与展望1页。演示环节最关键的是“顺序设计”好的演示顺序能够引导评委关注项目的亮点。建议的演示路径是先展示登录页输入账号密码进入系统首页此时停留5-8秒让评委看大屏的统计图表。紧接着打开药品库存页面筛选出预警药品展示预警效果。再到近效期管理页面展示过期和临期药品的状态。最后演示一次完整的入库到出库流程。这套流程演示完大约需要3分钟把系统主要的业务闭环都串起来了比东点一下西点一下要有说服力得多。如果是线上答辩或者录屏提交可以把这段操作录成视频嵌入PPT也是加分项。5.3 答辩评委高频提问的应对思路答辩环节评委老师的提问方向和侧重点通常在以下几个维度。提前准备好应对思路比临场硬答要从容很多系统技术选型的原因这类问题可以先回答技术栈组合的合理性再补充一句“在学校课程中学过JavaWeb而SpringBoot是当前业界的主流选择学习和使用成本较低”契合学生身份。数据库表与表之间的关系逻辑准备得越细致给评委的印象越深。可以从药品表和库存表的一对多关系切入说明为什么批号要在库存表中独立维护。密码安全存储方式明确回答使用BCrypt加密和MD5的区别在于每次加密生成的密文都不同且自带盐值。这一句话就能体现安全方面有基本的考量。系统哪里用了缓存、怎么用的如实说明Redis存Token黑名单和数据字典如果没做长远缓存优化就坦诚说同时引导到项目后续优化方向。6. 项目过程中的踩坑记录与优化心得6.1 数据库与编码层面的高频问题做这个项目时最容易遇到的一个坑是MySQL连接配置里的时区问题。如果使用高版本驱动连接串没加serverTimezoneAsia/Shanghai插入数据后时间比实际时间少8小时。排查了半天最后发现是连接池配置的问题。这个细节可以在论文的技术介绍里一句话带过显得有实战经验。另一个高频雷区是MyBatis Plus的分页插件。分页看似简单但只要写成new Page(current, size)传给Mapper方法却忘了配置分页拦截器PaginationInnerInterceptor查询结果就会带出全量数据穷尽内存。这个问题答辩的时候如果被问为什么自己分页失效了会很尴尬提前把拦截器配置好能避免很多麻烦。中文乱码问题也能分享。SpringBoot中如果项目文件编码不一致页面会显示乱码一般把IDEA全局编码、项目编码、文件编码都统一为UTF-8同时在配置里设置server.servlet.encoding的forcetrue就能解决。6.2 并发下的库存超卖问题库存超卖是系统里最具技术含量的一个业务坑。参考实现方案库存表加版本号字段version更新时带上version条件影响行数为0则重试或者报错。这种写法称之为乐观锁比直接用synchronized锁方法靠谱得多。如果答辩时能主动说出这段优化历程老师对你代码水平的印象会改变。实际写出来的UPDATE语句类似下面这样UPDATE drug_stock SET quantity quantity - #{num}, version version 1 WHERE drug_id #{drugId} AND batch_no #{batchNo} AND quantity #{num} AND version #{version}这个方案的优势在于扩展性好配合数据库事务的ACID特性就算是未来接入多台服务器并行部署也不存在单点失效的问题。6.3 项目扩展方向的几点思考毕设做完之后如果还有余力可以从三个方向升级系统这也是论文“总结与展望”章节的素材来源引入药品条码扫描接口实际药店操作通常用扫码枪快速录入可以对接公共API实现根据条码自动带出药品信息前端用input监听回车模拟扫码枪输入就可以实现。增加采购审批流引擎当前采购单只是“提交-审核-入库”的简单状态流转如果引入如Flowable等轻量级审批流框架可以配置多层审批。对接电子处方接口处方药销售需要一个处方来源登记功能可以预留回调接口模型后续对接医院HIS系统或互联网医院平台。移动端适配当前系统只在PC浏览器上使用后续可以做一个H5版本让店主在手机上查看实时库存和营业统计。结尾实际做完这个项目的一些体会花了大概三周的课余时间做完这个项目从一个只会写单个CRUD的学生到能独立设计一套管理系统最大的收获不是SpringBoot的注解用得多熟练而是真正理解了“业务流程就是系统的骨架”这句话。很多时候开发引以为傲的炫技代码在真实的药店场景里可能并不是核心需求反而是那些看着不起眼的批号效期、库存预警、权限控制才是让系统真正能用的关键。如果你正在做类似的毕设我的建议是先去附近药店蹲半小时看看店员是怎么收银、怎么盘点、怎么处理快过期药品的。这些观察比看十篇论文管用得多写出来的需求分析会真实且接地气。祝答辩顺利。
阅读完成 · 觉得有帮助?
咨询建站