简介:这份资源是面向高校计算机专业学生与Java初学者的一套药品信息管理系统完整项目,采用Spring Boot后端、Vue前端与MySQL数据库开发,适合用作毕业设计、课程设计或全栈入门练手。系统分为管理员与员工两类角色:管理员可管理员工信息、药品类别与药品信息,并通过表格和图表查看库存统计;员工则可修改个人资料、维护供应商信息、查看药品信息,完成药品入库、出库与库存管理及信息统计,业务闭环较为完整。压缩包共约2000个文件,以1430个md说明文档、507个js脚本、54个json配置为主,另含sql建库脚本、docx论文与少量html页面,整体约120.75MB,目录结构清晰,便于按模块查阅。资源同时附带需求分析、论文文档与演示视频,已有98人学习,能帮助读者快速理解项目架构、数据库设计与前后端交互流程,并对照源码完成部署与二次开发。
1. 药品信息管理系统这套源码,到底能帮你省下多少事
如果你正在做 Java 方向的毕业设计,选题又恰好落在「信息管理」这个大筐里,那这套基于 Spring Boot + Vue + MySQL 的药品信息管理系统,大概率能让你少熬好几个通宵。它不是那种只有增删改查的玩具 Demo,而是把药品分类、库存预警、出入库记录、供应商管理、有效期跟踪这些真实药房场景里绕不开的模块都串了起来,前端用 Vue 做交互,后端 Spring Boot 提供接口,数据落 MySQL,整套技术栈就是目前企业里最主流的组合。适合谁?适合那些不想从零搭架子、又怕拿到的源码跑不起来的人。你拿到的是一个压缩包,里面有源码、论文、需求分析和演示视频,等于把「写代码」和「写文档」两条线都给你铺好了。但别急着解压,先搞清楚它内部是怎么组织的,后面配置环境才不会翻车。
2. 环境搭建与依赖版本:别让 MySQL 和 JDK 成为第一道坎
2.1 后端运行环境的选择与版本对齐
Spring Boot 项目最怕的就是版本打架。这套源码常见做法是 Spring Boot 2.x 搭配 JDK 8 或 JDK 11,MySQL 用 5.7 或 8.0 都能跑,但驱动配置不一样。我一般会先看pom.xml里的spring-boot-starter-parent版本号,再决定 JDK 用哪个。如果你本机装的是 JDK 17,而项目用的是 Spring Boot 2.3,那启动时很可能报Unsupported class file major version,这就是典型的版本不匹配。解决办法要么降 JDK,要么升 Spring Boot,但升框架会牵连一堆依赖,毕业设计阶段不建议大动,直接换 JDK 8 最省事。
MySQL 这边,5.7 和 8.0 的差别主要在连接串和驱动类名。5.7 用com.mysql.jdbc.Driver,8.0 用com.mysql.cj.jdbc.Driver,而且 8.0 必须带时区参数,否则启动就报The server time zone value错误。下面这段application.yml是我在 8.0 环境下跑通后的配置,你可以直接抄,但记得把库名和密码换成你自己的。
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/drug_manage?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: your_password # 连接池用默认的 HikariCP 就行,毕业设计并发量不大逻辑说明:serverTimezone=Asia/Shanghai是 8.0 驱动必须加的,不然时区解析失败;useSSL=false避免本地开发时的证书警告。参数怎么改?库名drug_manage换成你实际导入 SQL 文件后创建的库名,用户名密码按本机 MySQL 来。如果你用 5.7,把驱动类名改回com.mysql.jdbc.Driver,URL 里的时区参数可以去掉,但留着也不报错。
2.2 前端 Vue 工程的依赖安装与代理配置
Vue 这边通常是 Vue CLI 脚手架生成的工程,package.json里锁定了 vue 2.x 或 vue 3.x。拿到源码后第一件事不是npm install,而是先看package.json里的dependencies和devDependencies,确认 node 版本要求。常见坑是 node 版本太高导致 node-sass 编译失败,这时候要么切到 node 14/16,要么把 node-sass 换成 dart-sass。我一般会先跑npm install,如果卡在 node-sass 那一步,直接换源重装。
# 先清缓存再装,避免旧包干扰 npm cache clean --force # 用淘宝源加速,毕业设计阶段没必要跟网络较劲 npm install --registry=https://registry.npmmirror.com # 如果 node-sass 报错,单独重装 sass 相关依赖 npm install sass-loader@10.1.1 sass@1.32.13 --save-dev逻辑说明:npm cache clean --force清掉可能损坏的缓存;--registry指定国内镜像,装包速度会快很多。参数怎么改?如果你本机 node 是 18 以上,sass-loader版本要相应提高,但 Vue 2 项目对高版本 sass-loader 兼容性一般,所以更推荐用 nvm 切到 node 16。装完依赖后,前端启动命令一般是npm run serve,端口默认 8080,如果跟后端冲突,在vue.config.js里改devServer.port。
2.3 数据库导入与初始数据检查
源码包里通常会带一个.sql文件,用 Navicat 或命令行导入都行。命令行导入更干净,不容易出字符集问题。
# 先创建库,字符集用 utf8mb4,避免药品名称里的特殊符号乱码 mysql -u root -p -e "CREATE DATABASE drug_manage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" # 再导入表结构和数据 mysql -u root -p drug_manage < drug_manage.sql逻辑说明:utf8mb4比utf8多支持 emoji 和部分生僻字,药品名称里偶尔会有特殊字符,用utf8mb4更稳。导入后别急着启动项目,先查一下用户表里有没有管理员账号,通常源码会预置一个admin用户,密码可能是加密后的字符串。如果登录报错,大概率是密码加密方式跟后端不一致,常见做法是看后端登录接口用的BCryptPasswordEncoder还是MD5,然后手动改一条已知密码的记录。
提示:导入 SQL 前先确认 MySQL 的
sql_mode没有开启ONLY_FULL_GROUP_BY,否则项目里一些分组查询会直接报错。临时关闭可以用SET GLOBAL sql_mode=(SELECT REPLACE(@@sql_mode,'ONLY_FULL_GROUP_BY',''));,但重启后会失效,毕业设计阶段够用。
3. 核心模块拆解:药品分类、库存预警与出入库记录怎么串起来
3.1 药品分类与信息维护的接口设计
药品信息管理系统的核心表通常包括drug_category、drug_info、stock_record、supplier这几张。分类表一般支持多级,但毕业设计里两级就够用了。后端接口按 RESTful 风格设计,/api/category/list返回树形结构,/api/drug/page做分页查询。前端用 Vue 的el-table或a-table渲染,配合el-pagination做分页。这里有个容易忽略的点:药品名称模糊查询时,如果直接拼 SQL 的LIKE '%${keyword}%',会有注入风险,正确做法是用#{}预编译。
// MyBatis Mapper 里这样写才安全 @Select("SELECT * FROM drug_info WHERE drug_name LIKE CONCAT('%', #{keyword}, '%') AND category_id = #{categoryId}") List<DrugInfo> selectByCondition(@Param("keyword") String keyword, @Param("categoryId") Long categoryId);逻辑说明:CONCAT('%', #{keyword}, '%')是预编译参数,不会被解析成 SQL 片段;@Param注解让多个参数能正确映射。参数怎么改?categoryId如果传 null,可以在 XML 里用<if test="categoryId != null">动态拼接,避免查不到数据。前端传参时注意把分类 ID 转成数字,字符串类型可能导致后端接收失败。
3.2 库存预警与有效期跟踪的实现逻辑
库存预警是这套系统里比较有业务价值的模块。常见做法是在drug_info表里加stock_quantity和min_stock两个字段,当stock_quantity < min_stock时,前端首页用红色标签标出来。有效期跟踪则是加一个expiry_date字段,后端写一个定时任务,每天凌晨扫描一次,把 30 天内到期的药品查出来,推送到消息表或者直接在前端弹窗提醒。
// 定时任务示例,用 Spring 的 @Scheduled 注解 @Scheduled(cron = "0 0 1 * * ?") // 每天凌晨 1 点执行 public void checkExpiry() { List<DrugInfo> expiringDrugs = drugMapper.selectExpiringDrugs(30); // 30 天内到期 for (DrugInfo drug : expiringDrugs) { // 写入预警记录表,前端轮询或 WebSocket 推送 warningMapper.insert(new Warning(drug.getId(), "即将过期", new Date())); } }逻辑说明:cron = "0 0 1 * * ?"表示每天 1 点执行,?是 Quartz 语法里表示不指定值。参数怎么改?30是预警天数,可以按业务需求调成 60 或 90。注意定时任务需要在启动类上加@EnableScheduling注解,否则不生效。如果项目里用了 Redis,也可以把预警结果缓存起来,减少数据库压力,但毕业设计阶段直接查库就够了。
3.3 出入库记录与供应商管理的联动
出入库记录表stock_record一般包含drug_id、type(入库/出库)、quantity、operator、create_time这几个字段。入库时增加drug_info.stock_quantity,出库时减少,同时写一条记录。供应商表supplier跟药品表是多对一关系,一个供应商可以供多种药。前端做入库表单时,供应商下拉框的数据从/api/supplier/list拉取,选中后自动带出联系人信息。
-- 入库操作的事务写法,保证库存和记录同时成功 START TRANSACTION; UPDATE drug_info SET stock_quantity = stock_quantity + 100 WHERE id = 1; INSERT INTO stock_record (drug_id, type, quantity, operator, create_time) VALUES (1, 'IN', 100, 'admin', NOW()); COMMIT;逻辑说明:START TRANSACTION和COMMIT包住两条 SQL,任何一条失败就回滚,避免库存加了但记录没写。参数怎么改?quantity和drug_id按实际业务传,operator从登录用户的 session 里取。如果项目用 MyBatis,可以在 Service 层加@Transactional注解,效果一样,代码更简洁。
注意:出入库并发高的时候,直接
UPDATE可能出现超卖,常见做法是用UPDATE drug_info SET stock_quantity = stock_quantity - #{quantity} WHERE id = #{id} AND stock_quantity >= #{quantity},靠数据库行锁保证安全。毕业设计演示时并发不高,但写上这个条件能体现你考虑过边界。
4. 避坑与排查:从启动报错到页面白屏的五个血泪经验
4.1 启动报Table 'xxx' doesn't exist但数据库里明明有表
现象:项目启动时控制台刷出一堆Table 'drug_manage.drug_info' doesn't exist,但你用 Navicat 连上去看,表就在那里。原因:多半是application.yml里的数据库名跟你实际建的不一致,或者 MySQL 区分大小写,你建库时用了大写,配置里写的是小写。解决:先确认url里的库名,再执行SHOW VARIABLES LIKE 'lower_case_table_names';,如果是 0 表示区分大小写,建库和配置统一用小写最稳。
4.2 前端页面能打开但接口全部 404
现象:npm run serve启动后浏览器能访问localhost:8080,但登录时提示网络错误,F12 看请求全是 404。原因:Vue 的代理没配,或者后端端口不是 8080。常见做法是在vue.config.js里配devServer.proxy,把/api开头的请求转发到后端端口。解决:确认后端server.port是多少,然后改代理配置。
// vue.config.js 里的代理配置 module.exports = { devServer: { proxy: { '/api': { target: 'http://localhost:9090', // 后端实际端口 changeOrigin: true, pathRewrite: { '^/api': '' } // 如果后端接口不带 /api 前缀,需要重写 } } } }逻辑说明:changeOrigin: true让代理服务器转发时修改请求头里的 host,避免跨域拦截;pathRewrite按后端实际路径决定要不要加。参数怎么改?target换成你后端启动时控制台打印的端口,pathRewrite如果后端接口本身就带/api,就删掉这一行。
4.3 登录成功但菜单权限不显示
现象:输入账号密码能进首页,但左侧菜单只有一两个选项,或者直接空白。原因:权限表sys_role_menu里的角色菜单关联数据没导入,或者当前登录用户的角色 ID 跟菜单表对不上。解决:先查sys_user表里当前用户的role_id,再查sys_role_menu里这个角色有没有菜单记录,没有就手动插几条。常见做法是源码里会带一个init.sql,专门初始化权限数据,别只导入主 SQL 文件。
4.4 药品图片上传后回显 404
现象:上传图片提示成功,但列表里图片位置是裂图,F12 看图片请求路径是localhost:8080/upload/xxx.jpg返回 404。原因:后端把文件存到了本地磁盘某个目录,但没有配置静态资源映射,或者前端拼接的路径跟后端实际存储路径不一致。解决:在后端加一个WebMvcConfigurer实现类,把上传目录映射到/upload/**。
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // 把本地上传目录映射出去,路径按实际存储位置改 registry.addResourceHandler("/upload/**") .addResourceLocations("file:" + System.getProperty("user.dir") + "/upload/"); } }逻辑说明:addResourceLocations里的file:前缀表示本地文件系统路径,System.getProperty("user.dir")是项目启动目录。参数怎么改?如果你把文件存到了D:/drug_upload/,就改成file:D:/drug_upload/。注意路径末尾的斜杠不能少,否则映射会失败。
4.5 打包部署后接口 500 但本地正常
现象:本地npm run serve和 IDEA 里跑都正常,打成 jar 包部署到服务器后,部分接口报 500。原因:常见的是服务器上 MySQL 版本跟本地不一致,或者时区没配,导致日期字段插入失败。解决:看服务器日志里的Caused by,如果是Data truncation或Incorrect datetime value,就在连接串里加serverTimezone=Asia/Shanghai,并确认服务器时间跟数据库时间一致。另一个常见原因是 jar 包里的application.yml还是本地配置,打包前记得改成生产环境参数。
5. 论文与需求分析文档的复用技巧:把源码变成能交差的材料
5.1 需求分析文档里的用例图与功能模块对应关系
压缩包里的需求分析文档通常包含用例图、功能模块图和数据流图。别把它当成摆设,写论文时「系统分析」那一章可以直接参考它的模块划分。我一般会先把文档里的功能模块跟源码里的 Controller 做对照,比如文档写「药品信息管理」对应DrugController,写「库存预警」对应WarningController,这样论文里的模块描述和代码实现就能对上,答辩时老师问起来也有据可依。如果文档里的模块名跟代码包名不一致,以代码为准改文档,别改代码,改代码容易引入新 bug。
5.2 论文查重与代码注释的平衡
论文里的核心代码片段不能直接大段贴源码,查重系统会标红。常见做法是把 Service 层的业务逻辑用自然语言描述,只在关键算法处贴几行伪代码或流程图。源码里的注释可以保留,但论文正文里不要出现跟源码一模一样的注释块。如果你需要展示数据库表结构,用表格列出字段名、类型和说明,比贴CREATE TABLE语句更安全。演示视频里如果出现了完整代码,论文里就不要再重复贴,避免重复率飙升。
5.3 演示视频的录制节奏与重点展示
演示视频一般要求 5 到 10 分钟,别从头到尾录一遍增删改查,那样既枯燥又容易暴露 bug。我建议按「登录 → 药品分类维护 → 入库操作 → 库存预警触发 → 出库操作 → 报表查看」这个顺序录,每个环节控制在 1 分钟左右。重点展示库存预警那个红色标签,以及出入库后库存数量的实时变化,这两个点最能体现系统不是纯 CRUD。录之前先把数据库里的测试数据准备好,别现场造数据,容易手忙脚乱。视频格式用 MP4,分辨率 1080P 就够了,太大反而不好上传。
提示:演示视频里不要出现个人隐私信息,比如真实姓名、手机号,测试数据用「张三」「13800000000」这种明显虚构的就行。如果源码里预置了真实医院或药企的名称,录之前全局替换掉。
5.4 从源码到论文的章节映射表
下面这张表是我带学生时常用的映射关系,你可以按自己的论文大纲调整。核心思路是让论文每一章都能在源码里找到对应实现,而不是空对空写理论。
| 论文章节 | 对应源码模块 | 关键类/文件 |
|---|---|---|
| 系统需求分析 | 需求分析文档 | 用例图、功能模块图 |
| 系统设计 | 数据库设计 | drug_manage.sql建表语句 |
| 系统实现 | 后端接口 | DrugController、StockService |
| 系统实现 | 前端页面 | views/drug/List.vue |
| 系统测试 | 演示视频 | 录屏文件 |
逻辑说明:这张表帮你快速定位每个章节该写什么,避免论文跟代码脱节。参数怎么改?如果你的论文要求写「详细设计」,就把StockService里的方法逐个展开,说明入参、出参和异常处理。如果要求写「概要设计」,就只写到模块级别,不用深入到方法。
5.5 答辩前必须自己走一遍的检查清单
答辩前别只看代码,把系统完整跑一遍,重点检查这几个地方:登录能不能用不同角色进去、药品新增时必填项校验有没有生效、库存为 0 时出库会不会报错、删除分类时如果下面有药品会不会级联删掉。这些边界问题老师最爱问。如果发现删除分类把药品也删了,就在 Service 层加一个判断,有药品的分类不允许删除,返回提示信息。这个改动不大,但能体现你考虑过数据一致性。另外,把application.yml里的数据库密码改成你自己的,别用源码默认的,答辩时老师看到默认密码会觉得你没认真配环境。
从那以后我每次拿到这种带论文的源码包,都先把 SQL 导入、改配置、跑通登录,再去看论文文档,顺序反了容易在环境上耗掉半天。希望帮到你。
本文还有配套的精品资源,点击获取