news 2026/5/9 0:12:31

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

作者头像

张小明

前端开发工程师

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/2 17:10:18

激光雕刻机DIY进阶:GRBL参数优化与实战调校

1. GRBL参数优化基础&#xff1a;从零开始理解核心配置 刚接触激光雕刻机的朋友可能会被GRBL那一长串参数搞得头晕眼花。别担心&#xff0c;我们先从最基础的几个参数开始讲起。记得我第一次调参数时&#xff0c;机器像喝醉酒一样乱跑&#xff0c;差点把工作台给毁了&#xff…

作者头像 李华
网站建设 2026/5/7 20:58:58

C盘爆满 修改VS Code缓存与插件目录指定方法

C盘爆满 修改VS Code缓存与插件目录指定方法 当C盘因VS Code的缓存、插件及配置文件堆积而爆满时&#xff0c;可通过以下三种核心方式将相关数据定向到非C盘目录&#xff0c;实现C盘空间释放&#xff0c;同时保证VS Code正常使用。三种方法覆盖从简单到进阶的不同需求&#xff…

作者头像 李华
网站建设 2026/5/7 12:45:46

CAN日志文件中的错误帧解析:从ASC文件看总线故障诊断

CAN总线故障诊断实战&#xff1a;ASC日志错误帧深度解析手册 在汽车电子和工业控制领域&#xff0c;CAN总线如同神经系统的血管般重要&#xff0c;而ASC日志文件则是诊断这些"血管"健康状况的X光片。当工程师面对一个满是错误帧的ASC文件时&#xff0c;如何快速定位…

作者头像 李华