news 2026/4/19 21:53:20

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

作者头像

张小明

前端开发工程师

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/4/18 6:58:14

【2025 实战】WinSCP 高效文件传输:从基础连接到自动化脚本配置

1. WinSCP&#xff1a;为什么2025年它仍是文件传输的首选工具&#xff1f; 如果你经常需要在Windows和Linux服务器之间传输文件&#xff0c;WinSCP绝对是你工具箱里不可或缺的利器。作为一个从2000年就开始维护的开源项目&#xff0c;WinSCP在2025年依然保持着旺盛的生命力&am…

作者头像 李华
网站建设 2026/4/18 7:54:08

STM32H750缓存一致性陷阱:UART+DMA传输中的Cache管理实战解析

STM32H750高速串口通信中的Cache一致性实战指南 在嵌入式系统开发中&#xff0c;STM32H750凭借其Cortex-M7内核和丰富的外设资源&#xff0c;成为工业通信和高速数据采集等场景的热门选择。然而&#xff0c;当开发者尝试利用其高性能特性&#xff08;如Cache和DMA&#xff09;…

作者头像 李华
网站建设 2026/4/18 8:32:10

基于YOLOv8的毕业设计实战:从环境搭建到部署优化全流程解析

背景痛点&#xff1a;毕设里那些“看不见”的坑 做目标检测毕设&#xff0c;最怕的不是算法原理看不懂&#xff0c;而是“跑不通”。 我去年带 8 位师弟师妹&#xff0c;发现 90% 的时间都耗在下面三件事&#xff1a; 环境版本对不上&#xff1a;CUDA 11.7 配 PyTorch 1.13&a…

作者头像 李华
网站建设 2026/4/18 8:30:54

HEC-RAS在水利工程中的实战应用:从安装到复杂场景模拟

HEC-RAS在水利工程中的实战应用&#xff1a;从安装到复杂场景模拟 引言 对于水利工程师而言&#xff0c;掌握专业的河道水力计算工具是解决实际工程问题的关键。HEC-RAS作为行业标杆软件&#xff0c;其强大的模拟能力和广泛的应用场景使其成为水利工程领域不可或缺的利器。不…

作者头像 李华
网站建设 2026/4/18 8:37:58

智能科学与技术毕设实战:基于Python的电影推荐系统效率优化指南

智能科学与技术毕设实战&#xff1a;基于Python的电影推荐系统效率优化指南 摘要&#xff1a;在智能科学与技术专业毕业设计中&#xff0c;许多同学用 Python 搭电影推荐系统&#xff0c;却常因算法效率低、数据加载慢、接口响应卡&#xff0c;导致答辩演示翻车。本文聚焦“效率…

作者头像 李华
网站建设 2026/4/18 8:36:10

【2024边缘计算生死线】:Docker 27正式支持eBPF驱动编排——仅限v27.0.0+的3个隐藏API,错过将无法兼容下一代工业网关

第一章&#xff1a;Docker 27边缘计算架构演进全景图 Docker 27标志着容器运行时与边缘计算深度融合的关键转折点。其核心演进方向聚焦于轻量化、低延迟协同、异构设备原生支持及分布式生命周期管理&#xff0c;彻底重构了传统云边协同范式。 边缘就绪的运行时内核升级 Docker…

作者头像 李华