☰
基于SpringBoot+Vue的医院药品管理系统设计与全栈实现
2026/10/15 15:07:26 网站建设 项目流程

SpringBoot+Vue 医院药品管理系统,这个标题在毕设、课设资源里出现的频率相当高,Java+MySQL 的全栈组合,功能覆盖药品信息管理、库存监控、采购入库、处方销售这些典型业务。不管是拿来交毕业设计、课程作业,还是作为学完 Spring Boot 和 Vue 之后练手的第一个完整项目,它都是一个非常合适的选择。

这几年我带过不少同学的毕业设计和课程项目,反复接触过类似的管理系统。这类项目最有价值的一点是:它不是一个简单的"增删改查 Demo",而是真实医院药品流转的缩略版。你从中能学到的不只是代码,还有业务单据怎么流转、库存如何控制、角色权限怎么区分,这些在课堂作业和拼凑的小练习里很难完整遇到。本文会从整体架构拆解、数据库设计、后端关键逻辑、前端页面实现、本地运行操作、常见问题排查这几个维度,把这类系统的完整脉络讲清楚。

1. 先弄明白:这套系统到底解决什么问题

1.1 医院药品管理的核心业务链路

医院药剂科每天面对的工作远不只是"进货、卖药"这么简单。一支抗生素从供应商送抵药库,到它最终被门诊医生开给患者,中间要经历验收入库、库存存储、效期监控、药房领药、处方审核、发药出库、用药记录归档这好几个环节。任何一个环节出错,轻则库存对不上账,重则过期药品流入临床。

这类系统就是为这个过程服务的。它把药品从"进院"到"离院"的全生命周期管理起来,核心业务链路大致是:药品资料建档 → 供应商采购 → 入库审核 → 库存更新 → 药房/临床科室领用 → 门诊处方销售 → 库存扣减 → 效期与库存预警。此外还有用户管理、登录鉴权、操作日志、统计报表等支撑性功能。

在做项目拆解之前,建议先把上面这条链路画一遍。你会发现所有功能模块本质上都是这条链上的一个节点,理解了业务流,代码再复杂也不会走偏。

1.2 技术栈选型的真实原因

市面上同类系统不少,有的用 SSM(Spring + Spring MVC + MyBatis),有的用 Spring Boot + Thymeleaf 服务端渲染,而SpringBoot + Vue + MySQL这套组合之所以在毕设和课设项目中成为主流,有它的现实原因。

Spring Boot 最大的价值是"自动配置 + 约定优于配置",它帮开发者省掉了大量 XML 配置和繁琐的依赖管理。用 Spring Boot 写后端,只需要一个标注了@SpringBootApplication的入口类,配合若干 Controller、Service、Mapper 就能跑起来一个完整的 Web 服务。配合 MyBatis-Plus,单表的增删改查基本不用手写 SQL,开发效率明显高于传统的 Spring + Spring MVC。

前端选择 Vue,是因为 Vue 的学习曲线在三大前端框架里相对平缓,而且 Vue 的单文件组件结构非常直观。模板、脚本、样式写在一个.vue文件里,对于 Java 后端同学来说非常容易上手。再搭配 Element UI 或者 Element Plus 这样的组件库,表格、表单、弹窗、分页器几乎都是现成的。一个基础还算扎实的同学,两周时间可以完整做出来,毕设进度压力不会太大。

数据库选 MySQL 则是最稳的选择,它足够成熟、社区资料多、Navicat 等图形化工具齐全,部署和学习成本在校园网环境里基本没有门槛。

1.3 这类系统的三重用途

毕业设计看重的是功能完整度 + 技术覆盖面 + 论文可写性。药品管理系统涵盖了权限管理、业务单据、库存预警、统计图表,这些都能拆成独立章节写进论文,答辩时也容易讲清楚。

课程设计看重的是结构清晰、调试方便、一人能完成。这种规模的系统刚好卡在一个"不太大也不太简单"的点上,同理,不容易出现代码多到看不完的情况,也不会被老师说工作量不足。

日常练手看重的是学到了什么。通过这套系统,你能把 Vue 前端、Axios 请求、Spring Boot 接口开发、MyBatis 持久层、MySQL 表设计、JWT 鉴权这些知识串成一个闭环,这是做几百道练习题换不来的经验。

2. 系统模块拆解与数据库设计

2.1 功能模块怎么划分最合理

动手写代码之前,先按业务域把系统切成几个模块。参考我见过的大多数项目,一个功能完整、答辩经得起问的药品管理系统通常包含以下几个模块:

模块核心功能对应的典型页面
系统管理用户登录、账号管理、角色权限、修改密码、操作日志登录页、用户列表、角色分配
药品信息管理药品档案的增删改查、药品分类、处方药/非处方药标记药品列表、药品详情、新增/编辑弹窗
库存管理入库登记、出库发放、库存查询、库存流水、效期提醒库存列表、入库单、出库单、预警列表
供应商管理供应商档案、联系方式、历史供药记录供应商列表、供应商编辑
采购与入库采购订单生成、到货审核确认、自动写库存流水采购单创建、待收货列表、入库确认
处方/销售门诊处方录入、销售记录、销售明细统计销售开单、销售记录查询
统计报表月度出入库统计、销售金额排行、库存周转分析图表看板、排行榜

功能模块的划分要遵循一个原则:每个模块之间的关系要单向依赖,避免循环引用。比如药品库存模块可以依赖药品信息和供应商模块,但供应商模块就不要反向去查库存表的统计结果,否则后面维护起来非常头疼。

模块划分好之后,前后端的菜单结构、路由结构、权限控制点基本都定下来了。后端的包结构建议按模块而不是按技术层来建包,也就是先建controller、service、mapper、entity四大层,再在层内按业务模块分包,比如entity/drug、entity/purchase、entity/system。这样代码量大了之后依然能找到头绪。

2.2 核心数据表结构与设计思路

数据库设计决定了这个项目的质量上限。很多同学拿着别人的源码导入数据库,发现表之间外键散落、字段类型混乱,改一个功能牵连出一堆 Bug。我按实际项目的标准,梳理出最核心的几张表:

用户表(sys_user)

字段类型说明
idbigint主键
usernamevarchar(50)登录名,唯一
passwordvarchar(100)BCrypt 加密后的密码
real_namevarchar(50)姓名
rolevarchar(20)角色标识:admin / pharmacist / buyer
statustinyint是否禁用
create_timedatetime创建时间

药品信息表(drug_info)

字段类型说明
idbigint主键
drug_codevarchar(30)药品编码,唯一
drug_namevarchar(100)药品名称
category_idbigint药品分类ID
specificationvarchar(50)规格,如 0.25g*24粒
unitvarchar(10)单位:盒/瓶/袋
manufacturervarchar(100)生产厂家
prescription_flagtinyint是否处方药,1是0否
retail_pricedecimal(10,2)零售价
stock_thresholdint库存预警阈值
statustinyint上下架状态

库存表(drug_stock)

字段类型说明
idbigint主键
drug_idbigint关联药品ID
batch_novarchar(50)批次号
quantityint当前数量
expire_datedate有效期至
supplier_idbigint来源供应商
warehouse_posvarchar(50)库位

这里单独立一张库存表,而不是把"库存数量"直接写在药品表里,是因为药品存在批次的概念。同一款药品不同批次的有效期不同、采购价格不同,混在一起没法做效期管理。这也是毕设答辩时一个非常容易被追问的设计亮点。

销售记录表(sale_record)

字段类型说明
idbigint主键
record_novarchar(30)销售单号
drug_idbigint药品ID
quantityint销售数量
amountdecimal(10,2)销售金额
user_idbigint操作人
sale_timedatetime销售时间

加上供应商表、分类表、采购入库单表、库存流水表,总共七八张核心表就可以支撑一套完整系统了。表设计时注意统一主键策略,推荐ASSIGN_ID雪花算法,不要用数据库自增,因为后续做数据迁移和分布式部署时自增主键容易冲突。

2.3 药品库存与有效期关系的细节

这是一个容易踩坑的点。如果你只在药品表里放一个总库存数量字段,遇到同一药品有两个入库批次、有效期各不相同时,就没办法区分哪些接近过期。而医院药房实际发药时是有原则的:近效期先出、先进先出。

所以在设计库存流水(stock_flow)时,除了记录"入/出/调整"类型、数量、经办人、时间之外,还要额外记录批次号、关联的单据号。这样拿着批号就能反查某一批药进出情况,效期预警按expire_date倒排,把 90 天内过期的批次单独拉出来。

如果部分源码中药品表直接存总库存也能满足基本演示,但答辩时如果老师问"同一药品两个批次如何管理",只靠一个数字字段是答不上来的。所以我在系统设计里强烈建议库存用批次表存。

3. 后端核心逻辑:从登录鉴权到库存扣减

3.1 工程结构与依赖配置

一个规范的 Spring Boot 后端工程,至少要分成这些包:

com.example.hospital ├── config // 配置类、拦截器、跨域配置 ├── controller // 接口层 ├── service // 业务逻辑层 ├── mapper // 数据访问层 ├── entity // 实体类 ├── common // 通用工具类、统一返回结果、异常处理 └── HospitalApplication.java // 启动类

依赖管理建议直接使用 Spring Initializr 生成,然后手动添加 MyBatis-Plus、MySQL 驱动、JWT 相关依赖、Lombok。核心依赖如下:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.3.1</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>

MyBatis-Plus 的使用值得多说两句。它内置了BaseMapper<T>,把单表的增删改查、分页查询、条件构造器都封装好了。比如查某个分类下的所有药品,传统 MyBatis 要写<select>标签和对应 SQL,用 MyBatis-Plus 直接这样写:

LambdaQueryWrapper<DrugInfo> wrapper = new LambdaQueryWrapper<>(); wrapper.eq(DrugInfo::getCategoryId, categoryId); wrapper.eq(DrugInfo::getStatus, 1); List<DrugInfo> list = drugInfoMapper.selectList(wrapper);

Lambda 写法能避免硬编码字段名,字段名改了也会在编译期暴露问题,比手写字符串安全。这是提升开发效率最明显的一环。

3.2 JWT 登录鉴权和角色权限控制

系统里不同角色看到和能操作的菜单不一样:管理员可以管理用户、查看全部数据,药剂师可以开销售单,采购员负责录入采购和入库。所以登录校验之后还要做权限控制。

登录接口的处理逻辑很简单:

  1. 根据用户名查用户表;
  2. 用 BCrypt 校验密码(不要让自己成为不会加密的反面教材);
  3. 校验通过,生成 JWT Token,将userId、role写进 token 的 claims;
  4. 返回 token 给前端,前端后续请求在请求头Authorization里带上。
String token = Jwts.builder() .setSubject(user.getUsername()) .claim("userId", user.getId()) .claim("role", user.getRole()) .setExpiration(new Date(System.currentTimeMillis() + 2 * 60 * 60 * 1000)) .signWith(SignatureAlgorithm.HS256, secretKey) .compact();

光生成 token 还不够,还要写一个拦截器或过滤器,在所有接口请求进来时做校验。我习惯在HandlerInterceptor里做,先放行登录接口,再校验其他请求的 token:

@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (request.getMethod().equals("OPTIONS")) { return true; } String token = request.getHeader("Authorization"); if (token == null || !token.startsWith("Bearer ")) { throw new BusinessException("未登录或登录已过期"); } // 解析并校验 token,将 userId 放入 request attribute return true; }

关于密码存储,这里强烈建议使用 BCrypt。它每次加密的结果是随机的,但校验结果一致,就算数据库泄露,反推明文密码的成本也极高。代码实现上用 Spring Security 里的BCryptPasswordEncoder或者 jBCrypt 库都可以。

3.3 库存扣减的并发安全处理

这是整个系统里最有技术含量的地方,也是最能体现"你有没有真正理解业务"的点。

我们先看一个错误示范。很多同学写销售出库是这样:

DrugStock stock = stockMapper.selectById(stockId); if (stock.getQuantity() >= quantity) { stock.setQuantity(stock.getQuantity() - quantity); stockMapper.updateById(stock); }

先查出来再修改。如果两个请求同时操作同一批次库存,都查出来quantity = 10,各自减 5,两边都认为扣减成功,最终数据库可能只变成 5,而不是 0。这在并发访问量稍高的系统里必然出问题。

正确做法是用一条带条件的 SQL 完成扣减,这也是我在项目里采用的方案:

int rows = stockMapper.deductStock(drugId, batchNo, quantity); if (rows == 0) { throw new BusinessException("库存不足或批次不存在"); }

对应的 Mapper SQL:

UPDATE drug_stock SET quantity = quantity - #{quantity} WHERE drug_id = #{drugId} AND batch_no = #{batchNo} AND quantity >= #{quantity}

UPDATE语句自带行锁,两个事务同时执行时,第二个事务会等待第一个事务提交后,再基于最新数据判断quantity >= ?是否成立。如果第二个请求扣减数量超过了剩余库存,影响行数就是 0,业务层抛异常回滚即可。这套方案非常简单,不需要引入 Redis 分布式锁,但对单机应用已经足够。

同时,每次扣减后别忘了写一条库存流水。流水记录的不仅是操作行为,也是日后对账、排查问题的唯一线索。这个环节在答辩时提出来,老师基本都会认可。

3.4 药品有效期预警与库存阈值报警

预警功能是药品管理系统区别于普通商品管理系统的标志之一,学生时代很容易忽略,但医院药剂科非常看重。

效期预警的实现逻辑是:查询所有库存批次,把expire_date距离当前日期小于 90 天的批次筛选出来。90 天这个阈值建议直接做成配置,不要写死在 SQL 里。SQL 大概是这样:

SELECT * FROM drug_stock WHERE expire_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 90 DAY)

库存阈值报警是在药品信息表里设置一个stock_threshold字段,比如某药品低于 50 盒就报警。统计当前库存小于阈值的药品时,可以用一条带子查询的语句:

SELECT d.*, s.total_quantity FROM drug_info d LEFT JOIN ( SELECT drug_id, SUM(quantity) AS total_quantity FROM drug_stock GROUP BY drug_id ) s ON d.id = s.drug_id WHERE s.total_quantity < d.stock_threshold

把这两类预警查出来之后,管理系统里做一个醒目的"库存预警"菜单,前端进入页面就触发一次查询,有预警数据时在导航栏展示红点或徽标数。这样系统一下子就从一个"记录工具"升级成了"管理工具"。

4. 前端 Vue 实现:页面交互与数据对接

4.1 前端工程结构与路由划分

前端部分我见过两种方案:一种是纯 Vue + Vue Router + Vuex/Pinia + Axios,自己手写全部页面;另一种是直接使用若依(RuoYi)这类开源脚手架做二次开发。先说结论:自己从零写前端更推荐,因为你得真正理解页面数据是怎么来的,而不是一直停留在"改别人模板"的层面。

推荐的前端工程结构:

src ├── api // 按模块封装的请求接口 │ ├── drug.js │ ├── stock.js │ ├── sale.js │ └── user.js ├── assets // 静态资源 ├── components // 公共组件 ├── layout // 主界面布局,包含侧边栏和顶栏 ├── router // 路由配置 ├── store // 全局状态管理 ├── utils // 请求封装、工具函数 ├── views // 页面组件 │ ├── login │ ├── drug │ ├── stock │ ├── purchase │ └── report ├── App.vue └── main.js

路由配置要按照后端模块一一对应。比如:

{ path: '/drug', component: Layout, meta: { title: '药品管理', roles: ['admin', 'pharmacist', 'buyer'] }, children: [ { path: 'list', component: () => import('@/views/drug/list.vue'), meta: { title: '药品列表' } }, { path: 'category', component: () => import('@/views/drug/category.vue'), meta: { title: '药品分类' } } ] }

路由的meta.roles是后端返回的角色标识,前端在路由守卫里判断用户角色是否有权限进入。光有前端路由守卫其实不够,后端接口也要做权限校验。前端控制只是把没权限的菜单隐藏掉,真正的安全防线必须放在后端,这个原则在答辩时被问到安全问题可以着重讲。

4.2 药品管理页面的增删改查

药品列表页是整个前端最核心也最典型的页面,它几乎涵盖了所有你会在项目中反复使用的交互方式:条件查询、分页表格、新增弹窗、编辑回显、删除确认。

具体实现时,页面加载时调用getDrugPage(params)接口,返回的分页数据包含records和total。表格绑定records,分页组件绑定total,切换页码或改变每页数量时重新调用接口。

新增/编辑药品用 Dialog 弹窗,表单字段和后端实体对齐。这里有个小建议:表单校验规则可以用 Element UI 内置的rules,比如必填项、数字范围、价格精度。提交前做一次整体校验,能拦住大部分低级错误,减少后端处理"脏数据"的负担。

删除操作用this.$confirm弹出确认框,确认后调用删除接口,成功后刷新列表。这类看似简单的内容,很多同学会漏掉删除后的关联处理:比如直接删除一个药品,而库存表和销售记录表里还引用着这个药品ID,就会产生脏数据。所以合理的做法是:有库存或者有销售记录的药品不能物理删除,只能用status字段做逻辑下线。这个细节非常能够体现一名开发者的工程意识。

4.3 Axios 封装与跨域处理

如果前端代码里每个页面都写axios.get(url).then(...),那叫能用,不叫工程。实际项目里我会先在utils/request.js里做 Axios 实例封装:

import axios from 'axios' import { Message } from 'element-ui' import router from '@/router' const service = axios.create({ baseURL: process.env.VUE_APP_BASE_URL, timeout: 10000 }) // 请求拦截器:自动携带token service.interceptors.request.use(config => { const token = localStorage.getItem('token') if (token) { config.headers['Authorization'] = 'Bearer ' + token } return config }) // 响应拦截器:统一处理返回状态码 service.interceptors.response.use( response => { const res = response.data if (res.code !== 200) { Message.error(res.msg) if (res.code === 401) { router.push('/login') } return Promise.reject(res) } return res }, error => { Message.error(error.message) return Promise.reject(error) } ) export default service

这样每个 API 模块只需要这样调用:

import request from '@/utils/request' export function getDrugPage(data) { return request({ url: '/api/drug/page', method: 'post', data }) }

开发环境的跨域处理有两种常用办法。第一种是后端写@CrossOrigin或者全局 CORS 配置;第二种是前端用 devServer 的 proxy,把/api开头的请求代理到http://localhost:8080后端地址:

// vue.config.js module.exports = { devServer: { port: 3000, proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } } } }

我在实际开发中更推荐用前端代理,而不是在后端开启跨域。因为后端开启跨域等于允许所有来源访问,而开发环境代理只存在于本地开发阶段,部署上线后由 Nginx 统一转发,后端接口可以保持同源,安全策略更清晰。

4.4 可视化统计与告警展示

药品管理系统一般会加一个统计看板,展示销售趋势、库存预警数量、药品分类占比。这些图表用 ECharts 实现比较方便。

销售趋势图的逻辑是:后端按天聚合销售金额,返回一组{ date, amount }数据,前端把数据放进去:

const chart = echarts.init(document.getElementById('saleChart')) chart.setOption({ xAxis: { data: dates }, yAxis: {}, series: [{ type: 'line', data: amounts, areaStyle: {} }] })

库存预警的数字展示则可以用一个 Statistic 组件,把warningCount以醒目的红色数字放在看板右上角,点击可跳转到库存预警列表。

这类视觉内容也是答辩展示时的加分项。老师通常不会逐行看代码,但看到界面上的图表和数字会形成第一印象:这个项目不是空壳。

5. 本地运行实操:从环境准备到项目跑通

5.1 环境准备与工具版本搭配

把项目从源码变成能跑的系统,这一趴写给完全没起步的新手,老手可以直接跳到 5.3。

推荐的环境版本如下:

组件推荐版本说明
JDK1.8 或 11Spring Boot 2.x 首选
Maven3.6+管理后端依赖
MySQL5.7 或 8.0项目数据库
Node.js14 或 16Vue2 项目的运行环境
npm / yarnnpm 6+ 或 yarn前端包管理

这里有一个很重要的经验:不要用最新的 JDK 版本跑 Spring Boot 2.x 项目。JDK 17 或更高版本虽然能启动基础项目,但会遇到一些反射访问受限、依赖不兼容的问题,对于学习和调试来说毫无必要。Spring Boot 2.7 配 JDK 8 或 11 是最稳的组合。

5.2 数据库初始化与配置文件修改

拿到项目源码后,通常在根目录或sql目录下能找到init.sql或hospital_db.sql这样的文件。用 Navicat 或命令行执行:

mysql -u root -p < hospital_db.sql

执行完以后确认数据库hospital_db存在,并且能看到sys_user、drug_info、drug_stock等表和数据。

然后修改后端的application.yml,把数据库地址、用户名、密码改成你自己的:

server: port: 8080 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/hospital_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: root password: 123456

这里serverTimezone=Asia/Shanghai一定要加,否则 MySQL 8.0 会报时区相关的错误。如果你的数据库密码是空,password那行留空也可以,但不建议这么做。

5.3 后端启动步骤

在项目根目录(包含pom.xml的目录)打开终端,执行:

mvn spring-boot:run

第一次启动会下载大量依赖,可能需要几分钟到十几分钟,取决于网络情况。启动成功的标志是控制台出现Started HospitalApplication in x.x seconds,并且没有红色报错。

如果mvn命令不可用,用 IDEA 打开项目,等待右下角 Maven 依赖导入完成后,直接运行启动类也可以。建议直接使用 IDEA 的 Maven 面板,点击spring-boot:run,比命令行更方便调试。

启动后可以用浏览器访问http://localhost:8080,如果配置了欢迎页则能看到效果,否则访问任意接口路径会得到 JSON 或 404。至少能证明程序没有崩。

5.4 前端启动与页面验证

前端代码在vue或frontend目录下。进入目录,先安装依赖:

npm install

npm install 是新手最容易卡住的环节。如果下载极慢或者报错,换成国内镜像:

npm config set registry https://registry.npmmirror.com

依赖安装完成之后直接启动:

npm run serve

默认情况下 Vite 或 Vue CLI 会起一个本地服务(端口一般在 8080 或 3000),你需要在vue.config.js里把代理目标地址指到后端的8080,就像 4.3 节写的那样,避免跨域问题。

启动成功后访问前端地址,用初始账号登录。常见的初始账号密码会在项目的README.md里说明;如果源码里没有,直接在sys_user表里看数据,通常就是admin/admin123。登录后检查药品列表能否正常加载,新增一条药品再刷新,能出现就说明前后端联调成功。

6. 常见问题排查与毕设答辩加分点

6.1 高频问题排查表

把我在指导项目中遇到的最典型问题和解决方式整理成下面的表,很多坑都是反复出现的高频问题。

问题现象可能原因解决办法
前端页面能打开,但列表数据一直加载不出来后端没启动 / 接口代理路径配错检查后端控制台,看 8080 是否在监听;检查/api代理是否指对了
后端报 Access denied for user数据库用户名或密码写错用 Navicat 验证账号能否登录,再去改 application.yml
前端报 401 Unauthorizedtoken 过期或未携带用浏览器开发者工具查看请求头,确认 Authorization 字段存在
MySQL 提示 Unknown database没导入 SQL 或导错库确认init.sql完整执行,并确认连接的是同一个库名
控制台报端口占用8080 或 3000 被其他进程占用Windows 用 `netstat -ano
Maven 依赖下载报红本地仓库缺包 / 镜像未配配置阿里云 Maven 镜像,IDEA 中File -> Settings -> Maven -> Mirror添加
中文乱码数据库字符集不对建库时指定DEFAULT CHARSET utf8mb4,连接 URL 加characterEncoding=utf8
分页查询返回 total 始终为 0忘记配置 MyBatis-Plus 分页插件在 config 类中添加PaginationInnerInterceptor

6.2 润毕设/课设时的几个切入点

如果这个项目拿来当毕业设计,不建议直接原封不动交上去。答辩老师对热门项目的源码往往非常熟悉,翻来覆去就是那几套,不加点自己的东西很容易被质疑工作量。

我建议从几个方向做增量优化:

第一个方向是增加多级审核流程。采购入库单不直接生效,而是先创建"待审核"状态,由管理员或药房主任审核后方可入库。这个改动需要加审核状态字段、审核时间字段、审核人字段,业务复杂度立刻上升一个档次,论文里可以写一章"业务流程设计与审批模型"。

第二个方向是增加报表模块。除了简单的查询列表,用 ECharts 按药品分类做月度销售雷达图、按供应商做采购占比饼图。后端用日期函数做分组统计即可,前端只用 ECharts 呈现,履历上写"数据可视化模块",观感好很多。

第三个方向是引入 Redis 缓存。把登录 token 存到 Redis,设置过期时间,顺便实现登录验证码的存储。这个改动虽然不大,但涉及 Redis 的使用,能在技术栈上加一分。注意,如果你的毕设只要求 Java + MySQL,引入 Redis 前先确认一下老师的要求,不要额外给自己挖坑。

第四个方向是优化密码找回与个人信息管理。增加修改密码的强校验流程,例如旧密码校验、密码强度校验,这类细节在课设答辩时很容易获得好评。

6.3 这套系统再扩展还能怎么玩

药品管理系统虽然在业务上看起来比较"传统",但它的扩展潜力不小。可以把它往移动端方向扩展,开发一个小程序或 H5 版本的药师端,实现移动审批和库存盘点;也可以往数据分析方向扩展,除了销售金额,增加药品滞销分析、效期消耗率、科室领药频次统计等指标,让系统从"记录工具"变成"决策工具"。

如果你对微服务感兴趣,可以把用户模块、药品模块、库存模块拆开,用 Spring Cloud Alibaba 的方式做服务化改造。改动幅度很大,但对学习和简历讲述来说是一次完整的架构升级锻炼。做这一步之前先想想自己的时间投入,如果是在准备论文的关键阶段,不建议轻易动刀。

我在实际带项目的过程中发现,很多同学把大部分时间耗在"改 bug"和"倒腾环境"上,反而没有时间去深究那些能体现设计能力的地方,比如严格的库存批次管理、逻辑删除策略、权限模型的角色粒度划分。而答辩聊得深的,往往不是功能多不多,而是某个关键业务问题你是怎么思考的。这套系统从头到尾走一遍,恰好能把这些问题都覆盖到。

最后分享一个很实用的小技巧:项目开发过程中,每次启动前把application.yml里数据库密码错填一次,强迫自己看一遍报错日志。连续几次下来,你对 Spring Boot 启动链路上的常见报错会变得非常敏感,以后再遇到类似排错问题,基本一眼就能定位。这种动手排查的能力,才是做这类项目沉淀下来最值钱的东西。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询