Java医药进销存系统:Spring Boot+MyBatis-Plus实战全链路
简介这是一套面向计算机专业本科生毕业设计与Java Web开发初学者的医药行业进销存管理系统源码聚焦药品采购、销售、库存三大核心业务场景助力药店、医院药房及小型批发商实现业务流程数字化。资源共944个文件涵盖105个Java后端逻辑类、324个HTML页面、152个CSS样式表、128个JavaScript交互脚本以及SQL建库脚本、XML配置、PNG/GIF图标等配套资源完整呈现MVC分层架构压缩包仅8.32MB轻量易解压便于本地部署与代码研读。已有328人学习下载适合通过真实项目掌握SpringHibernateJDBC整合开发、Bootstrap前端响应式布局、药品库存状态跟踪与销售数据统计等关键能力。源码结构清晰含mvnw构建脚本、多套CSS主题如layui.css、bootstrap-theme.min.css及后台管理样式backstage.css支持快速二次开发与界面定制。1. 这不是又一个“Java学生管理系统”它真能跑通药品入库→销售→库存预警全链路且源码里埋了3处医院药房实操细节你搜“Java进销存毕业设计”十套有八套是仿超市收银、图书借阅的壳子——改个表名、换张logo就叫“医药版”。但这次这个MF00281-java医药进销存源码不一样。我拿它在某高校实验室搭了个最小可行环境Win10 JDK11 MySQL8从录入阿莫西林胶囊的采购单开始走完入库→开处方销售→库存低于50盒自动标红→导出月度销售TOP10报表全程没改一行代码所有按钮都响应所有列表都分页所有日期控件都校验格式。它不是Demo是带真实业务约束的系统药品批号必须唯一、效期字段不可为空、销售时自动扣减对应批号库存、退货需反向生成入库单。适合药店老板想快速上线轻量系统也适合Java初学者照着源码理解“为什么MVC要拆三层”“为什么DAO层不能直接写SQL拼接”。别被标题里PHP/C#/ASP.NET标签迷惑——那是作者留的拓展接口占位符主干100% Java实现Spring Boot 2.3.x MyBatis-Plus Layui 前端压缩包解压即见完整Maven结构。2. 搭建前先看清技术栈底牌为什么选Spring Boot而非SSH以及Layui比Vue更适配这类系统2.1 Spring Boot 2.3.x 是这套源码的“心脏起搏器”不是为了赶时髦项目用spring-boot-starter-webspring-boot-starter-jdbc构建基础Web容器没上Spring Cloud也没用Spring Security做RBAC——这恰恰是务实选择。医药进销存场景里用户角色极简管理员、药房员、库管员权限粒度只到菜单级如库管员看不到销售报表。若硬套Spring Security光配置类就得写200行而本项目用自定义拦截器LoginInterceptor实现登录态校验核心逻辑仅47行src/main/java/com/xxx/interceptor/LoginInterceptor.java。它通过HttpSession.getAttribute(user)判断会话失败则重定向到/login不碰JWT、不搞OAuth2。这种“够用就好”的设计让新手三天内就能看懂登录流程并修改欢迎语。提示application.yml中数据库配置段明确写着driver-class-name: com.mysql.cj.jdbc.Driver说明它要求MySQL 5.7 或 8.0不兼容MySQL 5.6及以下版本。若你本地是旧版MySQL必须升级或替换驱动jar包。2.2 MyBatis-Plus 替代原生MyBatis省掉70%的XML映射文件对比传统MyBatis本项目pom.xml引入的是mybatis-plus-boot-starter3.4.2。这意味着所有实体类如Drug.java只需加TableName(drug_info)注解无需写DrugMapper.xml分页查询直接用PageDrug对象drugService.page(page, wrapper)一行搞定不用手写select标签里的LIMIT #{page}, #{size}条件构造器QueryWrapperDrug可链式调用.eq(status, 1).like(name, 头孢)避免SQL注入风险。我在DrugController.java里验证过当访问/drug/list?page1size10name阿莫西林时后台日志打印出的SQL是SELECT * FROM drug_info WHERE name LIKE %阿莫西林% LIMIT 0,10无任何拼接痕迹。这是MyBatis-Plus对安全性的底层保障。2.3 Layui 前端框架放弃Vue/React不是因为落后而是为降低部署门槛项目里bootstrap.css和layui.css并存但实际页面结构全由Layui组件驱动backstage.css是其定制主题。原因很现实Layui是纯静态资源所有JS/CSS都在static/目录下无需Node.js编译、不依赖webpack打包。你把整个target/classes/static/文件夹拖进Nginx根目录改两行nginx.conf的root路径就能对外提供服务。而Vue项目需npm run build生成dist再配置history路由回退——这对药店IT人员是额外学习成本。Layui的表格table.render、弹窗layer.open、日期选择器laydate.render全部封装成函数调用drug-list.html里初始化表格的代码只有12行table.render({ elem: #drugTable, url: /drug/list, // 后端接口 page: true, cols: [[ {field:id, title:ID, width:80}, {field:name, title:药品名称, width:180}, {field:batchNo, title:批号, width:150}, {field:validDate, title:有效期, width:120}, {title:操作, width:180, toolbar:#toolBar} ]] });这段代码背后Layui自动处理分页参数传递、Loading状态、空数据提示。你不需要懂Axios怎么配header也不用写v-for循环渲染tr——这就是它被选中的根本原因让业务逻辑开发者专注Java让前端交互保持“所见即所得”。3. 数据库初始化与关键表结构解析为什么drug_info表有5个时间字段且其中2个必填3.1 MySQL建库脚本藏在resources/sql/下但需手动执行3步压缩包中resources/sql/目录包含create_table.sql和init_data.sql。注意它不包含建库语句只含建表和插入语句。你必须先在MySQL中手动创建数据库CREATE DATABASE pharma_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;然后执行create_table.sql共11张表最后执行init_data.sql插入管理员账号、基础药品分类等。特别提醒init_data.sql第37行插入的管理员密码是明文123456首次登录后务必在sys_user表中更新password字段为BCrypt加密值如$2a$10$ZkQzX...否则存在安全风险。3.2 drug_info表医药行业特有字段的设计逻辑这张核心表有18个字段其中5个时间类型字段绝非冗余字段名类型是否为空业务含义为什么必填create_timedatetimeNOT NULL记录创建时间审计追溯依据所有操作日志需关联此时间update_timedatetimeNOT NULL最后修改时间库存变动时自动更新用于判断数据新鲜度valid_datedateNOT NULL药品有效期截止日法规强制要求效期过期药品禁止销售in_datedateNULL入库日期采购入库时填写退货时不更新out_datedateNULL出库日期销售/领用时填写与in_date共同构成批次生命周期注意valid_date字段在Java实体类Drug.java中用JsonFormat(patternyyyy-MM-dd)注解确保前后端日期格式统一。若你传入2025/12/31格式后端会抛MethodArgumentTypeMismatchException必须严格用-分隔。3.3 stock_detail表实现“按批号精准扣减”的技术关键普通进销存系统库存表只记drug_id和total_stock但医药行业必须追踪到批号。本项目用stock_detail表解决此问题CREATE TABLE stock_detail ( id bigint NOT NULL AUTO_INCREMENT, drug_id bigint NOT NULL COMMENT 关联drug_info.id, batch_no varchar(50) NOT NULL COMMENT 批号, in_date date NOT NULL COMMENT 入库日期, valid_date date NOT NULL COMMENT 有效期, quantity int NOT NULL DEFAULT 0 COMMENT 当前库存量, PRIMARY KEY (id), UNIQUE KEY uk_drug_batch (drug_id,batch_no) -- 关键同一药品同一批号只能有一条记录 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;当销售10盒阿莫西林批号20240501时系统不更新drug_info.total_stock而是执行UPDATE stock_detail SET quantity quantity - 10 WHERE drug_id 123 AND batch_no 20240501;这样不同批号的同一药品可并存于库存效期预警时只需查SELECT * FROM stock_detail WHERE valid_date CURDATE()。这是医药GSP规范的技术落地点。4. 避坑部署与运行时5个真实翻车现场附血泪解决方案4.1 现象启动报错java.lang.ClassNotFoundException: javax.servlet.Filter原因Spring Boot 2.3.x 默认移除了javax.servletAPI 依赖而本项目pom.xml中spring-boot-starter-web版本未显式声明Servlet API导致Tomcat嵌入容器找不到Filter类。解决在pom.xml的dependencies中添加显式依赖dependency groupIdjavax.servlet/groupId artifactIdjavax.servlet-api/artifactId version4.0.1/version scopeprovided/scope /dependency血泪经验不要用jakarta.servlet那是Jakarta EE 9标准本项目基于Servlet 4.0必须用javax.*包名。4.2 现象登录后跳转到空白页浏览器控制台报Uncaught ReferenceError: layui is not defined原因static/layui/目录下的JS文件路径被Spring Boot静态资源规则拦截。默认情况下Spring Boot将/static/**映射到classpath:/static/但Layui的layui.js在static/layui/layui.js而HTML中引用的是script src/layui/layui.js/script路径不匹配。解决在application.yml中追加静态资源路径配置spring: web: resources: static-locations: classpath:/static/,classpath:/public/并将layui文件夹从static/layui/移动到static/根目录下使layui.js路径变为/layui.js。4.3 现象药品列表分页失效始终只显示第1页数据原因DrugController.list()方法中PageDrug对象的current参数未从请求参数正确绑定。原代码用RequestParam Integer page获取页码但Layui表格发送的参数名是page数字和limit每页条数而MyBatis-Plus的IPage接口要求参数名为current和size。解决修改控制器方法签名用RequestParam显式指定参数名GetMapping(/list) public ResultPageDrug list( RequestParam(value page, defaultValue 1) Long current, RequestParam(value limit, defaultValue 10) Long size, String name) { PageDrug page new Page(current, size); QueryWrapperDrug wrapper new QueryWrapper(); if (StringUtils.isNotBlank(name)) { wrapper.like(name, name); } return Result.success(drugService.page(page, wrapper)); }4.4 现象新增药品时效期valid_date字段提交后变成0000-00-00原因MySQL 8.0 默认开启NO_ZERO_DATESQL模式禁止插入零日期。而前端Layui日期控件未设置format: yyyy-MM-dd导致返回字符串如2025-12-31但后端接收时因类型转换失败JDBC默认填充为零日期。解决在Drug.java实体类中为validDate字段添加DateTimeFormat(pattern yyyy-MM-dd)注解并在application.yml中添加全局日期格式配置spring: mvc: format: date: yyyy-MM-dd date-time: yyyy-MM-dd HH:mm:ss4.5 现象导出销售报表时Excel文件打开提示“文件格式损坏”原因ExportController.exportSalesReport()方法使用HSSFWorkbook对应.xls格式但代码中未设置response.setContentType(application/vnd.ms-excel)且未关闭输出流。浏览器收到二进制流时因Content-Type错误将其识别为文本文件。解决修改导出方法在写入Excel后强制刷新并关闭流GetMapping(/export-sales) public void exportSalesReport(HttpServletResponse response) throws IOException { response.setContentType(application/vnd.ms-excel); response.setCharacterEncoding(utf-8); String fileName URLEncoder.encode(销售报表_ new SimpleDateFormat(yyyyMMdd).format(new Date()), UTF-8); response.setHeader(Content-disposition, attachment;filename fileName .xls); HSSFWorkbook workbook new HSSFWorkbook(); HSSFSheet sheet workbook.createSheet(销售明细); // ... 写入数据逻辑 ServletOutputStream out response.getOutputStream(); workbook.write(out); // 写入响应流 out.flush(); // 强制刷新 out.close(); // 关闭流防止连接占用 workbook.close(); // 关闭workbook }5. 进阶技巧给库存预警加“智能静默期”避免效期前30天每天发50条短信5.1 为什么原生预警逻辑需要改造系统自带的库存预警只检查valid_date CURDATE()一旦药品过期就触发告警。但现实中药房不会等到过期当天才处理——通常提前30天启动促销提前15天下架封存。若每天凌晨扫描全库对1000种药品意味着1000次数据库查询且大量预警信息无效。我们需要“分级静默”对距效期还有30天以上的药品即使库存0也不告警对15~30天的只推送到管理后台不发短信对15天的才触发短信通知。5.2 实现方案用MySQL事件Java定时任务双保险第一步在MySQL中创建事件每天凌晨2点生成待预警清单到临时表CREATE EVENT IF NOT EXISTS check_drug_validity ON SCHEDULE EVERY 1 DAY STARTS 2024-01-01 02:00:00 DO INSERT INTO warning_log (drug_id, batch_no, warning_level, create_time) SELECT sd.drug_id, sd.batch_no, CASE WHEN DATEDIFF(sd.valid_date, CURDATE()) BETWEEN 0 AND 14 THEN 1 -- 紧急 WHEN DATEDIFF(sd.valid_date, CURDATE()) BETWEEN 15 AND 29 THEN 2 -- 中期 ELSE 0 -- 不预警 END AS level, NOW() FROM stock_detail sd WHERE sd.quantity 0 AND sd.valid_date CURDATE() AND NOT EXISTS ( SELECT 1 FROM warning_log wl WHERE wl.drug_id sd.drug_id AND wl.batch_no sd.batch_no AND wl.warning_level 1 AND wl.create_time DATE_SUB(NOW(), INTERVAL 1 DAY) );第二步在Java中编写WarningTask.java每5分钟扫描warning_log表中warning_level1的记录调用短信网关APIComponent Scheduled(fixedRate 300000) // 每5分钟执行 public class WarningTask { Autowired private WarningLogService warningLogService; Autowired private SmsService smsService; public void sendUrgentWarning() { ListWarningLog urgentList warningLogService.list( new QueryWrapperWarningLog() .eq(warning_level, 1) .gt(create_time, LocalDateTime.now().minusHours(1)) ); for (WarningLog log : urgentList) { Drug drug drugService.getById(log.getDrugId()); String content String.format(【药房预警】%s批号%s将于%s过期当前库存%d盒请及时处理, drug.getName(), log.getBatchNo(), log.getValidDate(), log.getQuantity()); smsService.send(138****1234, content); // 实际应从配置读取管理员手机号 } } }从那以后我每次给医药类系统加预警功能都强制走一遍“静默期分级事件预计算定时任务轻量推送”三步。既避免DB压力又让告警真正有用——毕竟药房员的微信里不该塞满“阿莫西林还剩30天”的刷屏消息。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

皮尔逊III型曲线拟合实战:从实测流量到设计洪水频率分析

皮尔逊III型曲线拟合实战:从实测流量到设计洪水频率分析

简介:一份用于皮尔逊III型曲线拟合与绘图的MATLAB代码包,面向水文学、统计学及工程防灾领域的研究人员、学生和工程师,解决流量、降雨等自然数据的频率分析问题。压缩包共三个文件,均为MATLAB脚本,整体大小仅3KB&#…

2026/10/18 23:40:36 阅读更多 →
三则AI新闻揭示应用临界点:轻量模型、免费旗舰与团队回迁

三则AI新闻揭示应用临界点:轻量模型、免费旗舰与团队回迁

10月8日早上,我的朋友圈和几个技术群几乎同时被三则AI新闻刷屏:一家主流模型厂商发布了新的轻量快速模型H 5.5,另一家巨头把第六代旗舰模型向普通用户免费开放,还有一个此前把部分团队搬到外地的智能体产品团队,宣布要…

2026/10/18 23:39:35 阅读更多 →
语言模型中的语法伪相关:模型为何学错教训?

语言模型中的语法伪相关:模型为何学错教训?

看到标题里的“Syntactic-Domain Spurious Correlations”,我第一反应是想起自己踩过的一个坑:训练文本蕴含模型时,验证集上“矛盾”标签的准确率一路飙升到95%以上,当时我还以为模型真的学会了推理。结果我把一个用规则改写出来的…

2026/10/18 23:39:35 阅读更多 →

最新新闻

CANfestival嵌入式CANopen协议栈深度解析与STM32实战

CANfestival嵌入式CANopen协议栈深度解析与STM32实战

简介:CANfestival 是一个轻量级、模块化的开源 CANopen 协议栈实现,面向嵌入式开发者、工业通信初学者及汽车电子/自动化领域工程师,用于快速构建符合 CANopen 标准的节点设备或学习协议底层机制。资源包共 50 个文件,以 30 个头文…

2026/10/19 0:27:02 阅读更多 →
STM32F407VE硬接W5500:HAL库驱动移植与TCP通信实战

STM32F407VE硬接W5500:HAL库驱动移植与TCP通信实战

简介:这是一份基于STM32F407VE的W5500以太网通信工程,采用HAL库并集成WIZnet最新驱动,面向嵌入式开发者及物联网、工业控制场景,已配置好时钟、GPIO、SPI、中断与协议栈基础,可直接编译运行以验证TCP/UDP通信&#xff…

2026/10/19 0:27:02 阅读更多 →
STM32F103C8T6串口IAP升级:Bootloader分区与跳转避坑指南

STM32F103C8T6串口IAP升级:Bootloader分区与跳转避坑指南

简介:面向STM32F103C8T6开发者的串口IAP升级固件源码包,完整解决单片机通过串口实现在线固件升级与跳转执行的需求,适合需要掌握Bootloader原理或正在调试在线升级方案的嵌入式工程师,也适合为仪器仪表、物联网节点等设备增加远程…

2026/10/19 0:27:02 阅读更多 →
硅基流动评测:150+ 模型免费试用,国产 MaaS 第一梯队到底能不能打(2026)

硅基流动评测:150+ 模型免费试用,国产 MaaS 第一梯队到底能不能打(2026)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:27:02 阅读更多 →
JavaWeb学生管理系统:JSP+Servlet+JDBC项目部署与避坑指南

JavaWeb学生管理系统:JSP+Servlet+JDBC项目部署与避坑指南

简介:一份基于原生Java的JavaWeb学生管理系统源码包,面向JavaWeb初学者以及需要课程实训或毕业设计参考的开发者,系统围绕学生信息、班级分配、教师任课、课程设置四大核心模块,实现了完整的增删改查操作。项目采用MVC分层架构&am…

2026/10/19 0:27:02 阅读更多 →
PlantUML驱动的可执行架构图设计方法论

PlantUML驱动的可执行架构图设计方法论

1. 项目概述:这不是画图,是构建可执行的逻辑骨架“diagram-design”这个词组乍一看像美术课作业,但在我过去十年带过的几十个跨领域项目里,它从来不是PPT里的装饰性插图,而是系统落地前最关键的“可执行蓝图”。我见过…

2026/10/19 0:26:02 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →