news 2026/5/23 16:52:08

药房管理系统毕业设计:从零实现一个高内聚低耦合的入门级架构

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
药房管理系统毕业设计:从零实现一个高内聚低耦合的入门级架构


药房管理系统毕业设计:从零实现一个高内聚低耦合的入门级架构


1. 背景痛点:为什么“能跑就行”的代码在答辩时总被怼?

做毕业设计时,很多同学把“药房管理系统”当成“药品 CRUD 大合集”:一个DrugController里塞满增删改查,SQL 拼在 Java 字符串里,前端把表格数据一股脑儿v-for出来。结果演示时老师一句“如果药库管理员和售药师权限分开怎么做?”直接原地社死。

典型症状总结如下:

  • 功能堆砌:业务代码、权限判断、数据校验全写在 Controller,方法行数飙到 300+。
  • 硬编码:数据库连接、文件上传路径、角色名称直接static final写死,换环境就崩。
  • 安全裸奔:拼接 SQL、返回全字段实体、未做参数过滤,Postman 一把梭就能删库。
  • 无扩展点:药品字段加个“保质期”要改 5 张表 3 层代码,牵一发动全身。

毕业设计不是“能跑就行”,而是“跑得快、改得动、讲得清”。下面给出一条最小可运行、又足够拆分的架构路线,Spring Boot + MyBatis + Vue,3 天可搭出骨架,1 周能写 PPT。


2. 技术选型:为什么不是 Django / JSP / 纯 SSR?

技术放弃理由选择理由
DjangoPython 语法简洁,但国内药房项目主流是 Java 技术栈,后续二开、接入医保接口时 Java 生态更香
JSP + Servlet模板与后端高耦合,前端同学无法并行开发;IDE 支持弱,调试效率低
Spring Boot自带 IOC、AOP、Starter,一键跑起内嵌 Tomcat,Maven 依赖管理成熟
MyBatis比 JPA 易控 SQL,药房报表字段多且复杂,需要手写多表关联
Vue3 + ElementPlus组件化开发,双向数据绑定,打包后纯静态文件,与后端仅通过 JSON 交互,真正做到前后端分离

一句话:Java 系毕业设计,Spring Boot 是“默认答案”;MyBatis 让你写 SQL 不慌;Vue 让页面不再刷新全屏白。


3. 核心模块拆解:高内聚低耦合从“分包”开始

3.1 项目结构(仅列关键目录)

text com.example.pharmacy ├─ common // 全局异常、分页、常量 ├─ config // MyBatis、Swagger、Cors、RBAC 配置 ├─ controller // 仅接收与校验参数,一行代码不写业务 ├─ service // 接口 + 实现,事务在此层开 ├─ mapper // MyBatis XML 与接口 ├─ domain // PO + DTO + VO,每层只看到自己需要的数据 └─ security // SpringSecurity + JWT,RBAC 模型

3.2 药品库存管理——“只写库存,不管卖”

业务场景:药库管理员做采购入库、盘亏盘盈;售药师做销售出库。两个角色看到的数据一样,但操作按钮不同。

  1. 表设计
    drug(药品字典) ← 1:N →drug_stock(批次库存,含生产日期、有效期、数量)

  2. 关键接口

    • POST /api/stock/in入库
    • PUT /api/stock/check盘点
    • GET /api/stock/page库存列表(带有效期预警 ≤ 90 天)
  3. 代码片段(Java)

@RestController @RequestMapping("/api/stock") @RequiredArgsConstructor public class StockController { private final StockService stockService; @PostMapping("/in") public R<Void> stockIn(@Valid @RequestBody StockInDTO dto){ // 1. 参数校验由 @Valid + DTO 注解完成 // 2. 业务逻辑下沉到 service,Controller 仅做路由 stockService.saveStockIn(dto); return R.ok(); } } @Service public class StockServiceImpl implements StockService { private final DrugStockMapper drugStockMapper; private final DrugMapper drugMapper; @Override @Transactional(rollbackFor = Exception.class) public void saveStockIn(StockInDTO dto){ // 1. 根据药品 ID 查字典,不存在抛 BizException Drug drug = drugMapper.selectById(dto.getDrugId()); if (drug == null) throw new BizException("药品不存在"); // 2. 构造库存记录 DrugStock stock = new DrugStock(); stock.setDrugId(dto.getDrugId()); stock.setBatchNo(dto.getBatchNo()); stock.setQuantity(dto.getQuantity()); stock.setExpireDate(dto.getExpireDate()); drugStockMapper.insert(stock); } }
  1. 前端 Vue 调用
// api/stock.js import request from '@/utils/request' export function stockIn(data) { return request({ url: '/api/stock/in', method: 'post', data }) } // views/stock/In.vue import { stockIn } from '@/api/stock' const submit = async () => { await stockIn(formModel) ElMessage.success('入库成功') }

Controller、Service、Mapper 各管一摊,后期想加“库存预警”只需在 Service 层写定时任务,不动 Controller。


4. 用户权限:RBAC 最简实现

  1. 五张表
    userrolepermission,中间表user_rolerole_permission
    用户表存usernamepassword(BCrypt)、enabled

  2. SpringSecurity 配置要点

@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }
  1. 方法级鉴权——售药师不能入库
@PreAuthorize("hasAuthority('stock:in')") @PostMapping("/in") public R<Void> stockIn(@Valid @RequestBody StockInDTO dto){ ... }
  1. Vue 侧动态菜单
    登录后GET /api/user/info返回permissions: ['stock:in','drug:sale'],前端根据权限过滤路由表,按钮级用v-has自定义指令。

5. 安全性三板斧

  • 参数校验:DTO +javax.validation注解,拒绝 SQL 拼接。
  • SQL 注入:MyBatis#{}占位,杜绝${}拼接。
  • 越权访问:RBAC +@PreAuthorize,并在 XML 层加tenant_id等字段隔离数据。

6. 生产环境避坑指南

  1. 数据库连接池
    默认HikariCP足够,毕业设计并发低,但一定把minimum-idle设 5 以上,避免 MySQL 8 小时自动断开。

  2. 静态资源缓存
    Vue 打包后dist/放 Nginx,location ~* \.(js|css|png)$ { expires 30d; },回锅肉式提速。

  3. 配置外置
    application.ymlspring.datasource.url${DB_URL},服务器启动脚本加-DDB_URL=xxx,防止账号密码提交到 GitHub。

  4. 日志分级
    logback-spring.xmlcom.example.pharmacy.mapper=DEBUG,生产环境改为 INFO,避免控制台刷 SQL 暴露字段。


7. 进阶思考:把“毕业”做成“产品”

  1. 处方审核流
    医生端开方 → 药师端审核(状态机:待审核/已驳回/已通过)→ 售药出库。可引入 Flowable 轻量级工作流。

  2. 库存预警
    定时任务扫drug_stock表,近效期 ≤ 30 天自动发邮件给管理员;低于安全库存时钉钉 Webhook 提醒采购。

  3. 批次追溯
    给每盒药贴二维码,出库扫码记录sale_itemdrug_stock_id,实现“一批次一去向”,方便召回。

  4. 接入医保
    国家医保接口基于 HTTPS + 数字签名,先把签名工具类封装好,后续直接插拔。



写在最后

整套代码不到 2k 行,却能把“药品字典—库存—销售—权限”串成闭环。答辩时老师若问“如果以后增加连锁门店怎么改?”你可以指着 Service 层说:“门店当租户字段下沉到各表,加一层 Mapper 拦截即可,Controller 不用动。”——这就是低耦合带来的底气。

毕业设计不是终点,把代码推到云服务器,真刀真枪地让家人朋友的药店试用,才是把“学分”升级成“作品”的开始。祝你一次过答辩,早日把项目写进简历,面试时谈笑风生。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/23 3:08:49

PostgreSQL矢量数据库实战:从零部署pgVector扩展指南

1. 为什么需要pgVector扩展 如果你正在使用PostgreSQL数据库&#xff0c;并且需要处理向量数据&#xff08;比如AI模型生成的嵌入向量&#xff09;&#xff0c;那么pgVector绝对是你不可或缺的利器。这个开源扩展让PostgreSQL摇身一变&#xff0c;成为一个功能强大的向量数据库…

作者头像 李华
网站建设 2026/5/23 2:57:19

RK3568开发笔记(九):基于Qt的RS485协议调试工具开发与实战应用

1. RS485协议调试工具开发背景与需求 在工业控制和嵌入式设备开发中&#xff0c;RS485通信协议因其抗干扰能力强、传输距离远等优势被广泛应用。RK3568作为一款高性能嵌入式处理器&#xff0c;板载RS485接口为设备间通信提供了硬件基础。但在实际开发中&#xff0c;我们常遇到…

作者头像 李华
网站建设 2026/4/30 19:09:23

【推荐100个unity插件】体积照明体积光 —— Volumetric Light Beam

文章目录 前言 插件下载安装 实战 1、进行体积光束配置 2、在检查器窗口中确保渲染管线属性设置为正确的值 3、你需要检查深度纹理属性来启用这个功能 4、可以开始在你的场景中创建一些体积滑翔光束了 给已有灯光添加体积照明效果 1、添加组件 2、调整衰减距离 3、改变光束的厚…

作者头像 李华
网站建设 2026/5/14 22:46:20

如何为Chatbot集成Ollama:AI辅助开发实战指南

背景痛点&#xff1a;Chatbot 想变聪明&#xff0c;却常被这三座大山拦住 过去一年&#xff0c;我帮不少团队把“人工智障”升级成“人工智能”&#xff0c;发现大家踩的坑惊人地致&#xff1a; 模型选择困难症 公有云大模型接口丰富&#xff0c;但按 Token 计费&#xff0c;一…

作者头像 李华
网站建设 2026/5/20 13:41:07

基于LLM和RAG的智能客服系统实战:从架构设计到生产环境部署

基于LLM和RAG的智能客服系统实战&#xff1a;从架构设计到生产环境部署 摘要&#xff1a;本文针对传统客服系统响应速度慢、知识库更新滞后等痛点&#xff0c;提出基于LLM&#xff08;大语言模型&#xff09;和RAG&#xff08;检索增强生成&#xff09;的智能客服解决方案。通过…

作者头像 李华
网站建设 2026/5/22 8:58:06

智能客服系统架构图:从高并发到弹性扩展的设计实践

智能客服系统架构图&#xff1a;从高并发到弹性扩展的设计实践 摘要&#xff1a;本文深入解析智能客服系统的架构设计&#xff0c;针对高并发请求、弹性扩展和容错机制等核心痛点&#xff0c;提出一套基于微服务和事件驱动的解决方案。通过详细的架构图和技术选型对比&#xff…

作者头像 李华