SSM+Vue药房药品管理系统:前后端分离毕业设计源码详解

发布时间:2026/10/26 22:37:12

SSM+Vue药房药品管理系统:前后端分离毕业设计源码详解 简介这套源码包面向药房药品管理业务场景基于Java与SSM框架Spring、SpringMVC、MyBatis构建后端服务前端采用Vue.js渐进式框架实现数据驱动与组件化页面同时整合SpringBoot简化配置、Maven管理项目依赖数据库选用MySQL 5.7是适合Java学习者、毕业设计及中小型管理软件二次开发的完整参考项目。压缩包为zip格式大小22.7MB包含项目源码及必要配置支持在IDEA或Eclipse中直接打开便于对照学习框架整合细节。目前已有83人学习覆盖药品信息维护、库存管理、处方处理等核心业务代码层次清晰后端分层与前端组件化设计明确配合Navicat或SQLyog等数据库工具可直观理解表结构设计与数据流转过程。通过研读该项目读者能够掌握SSM与Vue前后端分离开发模式熟悉Maven构建生命周期及MySQL5.7的使用要点积累从环境搭建到功能实现的实战经验是一份兼具教学与工程参考价值的资源。1. 药房药品管理系统SSM Vue 前后端分离的完整毕业设计源码药房药品管理这个场景本质上就是围绕“药品从入库到出库的全生命周期”做增删改查与状态追踪而本项目用 SSM 后端 Vue 前端 MySQL 数据库把这套业务完整实现了。源码适合三类人一是拿它做毕业设计、课程设计的学生二是刚入行想搞清楚 SSM 和 Vue 怎么协同工作的 Java 开发三是小药房、诊所想低成本自建进销存系统的从业者。这套系统的业务闭环很完整——登录鉴权、药品信息维护、入库出库登记、库存实时查询、过期预警每个模块都能对应到实际的药房运营需求。从架构上看它选择了 Spring SpringMVC MyBatis 做后端服务Vue 做前端展示层走的是典型的前后端分离路线这对理解企业级 Java Web 项目的组织方式非常有帮助。下面我从环境搭建、项目导入、数据库设计一路拆到那些新手必踩的坑把这套源码彻底讲透。2. 为什么是 SSM Vue这套技术栈的选型逻辑与项目结构拆解2.1 前后端分离架构不是 SpringBoot 不好而是 SSM 更能看清底层这套系统的后端选了 SSM 而不是直接上 SpringBoot很多人会问为什么。放在课程设计或教学场景里SSM 有它不可替代的价值Spring 的 IoC 容器管 Bean、SpringMVC 的 DispatcherServlet 管请求路由、MyBatis 的 SqlSessionFactory 管数据库交互每一层都是显式配置、显式调用你改一条 SQL 或加一个拦截器能明确知道改动发生在哪个环节。SpringBoot 把配置封装掉之后遇到异常时反而不好排查底层。前端的 Vue 选择同样是基于渐进式框架的适用性。药房药品管理系统包含药品列表、入库单、出库单、统计报表等十余个页面每个页面里都有表单校验、列表渲染、状态切换这类交互Vue 的双向数据绑定直接让 DOM 操作工作量下降一个量级。组件化设计也方便复用——药品表格组件、分页组件、弹窗表单组件基本每个页面都在用。项目本身已经给出了 Maven 依赖管理的骨架核心依赖组合如下dependencies !-- Spring 核心容器 -- dependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.2.22.RELEASE/version /dependency !-- SpringMVC 请求处理 -- dependency groupIdorg.springframework/groupId artifactIdspring-webmvc/artifactId version5.2.22.RELEASE/version /dependency !-- MyBatis 持久层框架 -- dependency groupIdorg.mybatis/groupId artifactIdmybatis/artifactId version3.5.7/version /dependency dependency groupIdorg.mybatis/groupId artifactIdmybatis-spring/artifactId version2.0.6/version /dependency !-- MySQL 数据库驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version5.1.49/version /dependency !-- 数据库连接池 -- dependency groupIdcom.alibaba/groupId artifactIddruid/artifactId version1.2.8/version /dependency /dependencies这段配置里 spring-webmvc 负责处理前端发来的所有 HTTP 请求mybatis-spring 负责把 MyBatis 的 SqlSessionFactory 纳入 Spring 容器管理Druid 连接池解决了数据库连接的复用问题。有个细节要注意MySQL 驱动版本选了 5.1.x 系列是因为项目默认配套 MySQL 5.7如果你的本地数据库装的是 MySQL 8.0驱动要换成 com.mysql.cj.jdbc.Driver 且版本升到 8.0.x否则启动直接报 ClassNotFoundException 或连接时区错误。数据源的配置一般放在 jdbc.properties 里参数项包括 url、username、password、initialSize、maxActive其中 initialSize 是连接池初始连接数maxActive 是最大连接数药房这种小并发管理系统初始 5 个、最大 20 个足够用了。2.2 目录结构视角从 controller 到 vue 组件的数据流路径把导入 IDEA 后的项目目录展开你能看到一个很清晰的纵向依赖链。后端部分com.xxx.pharmacy 包下按职责分了 controller、service、mapper、entity 四层前端部分src 下按 api、components、router、views 四个目录组织。一个典型的业务请求是这么走的Vue 页面里的药品查询按钮调用src/api/drug.js里封装好的 axios 方法 → 发送 GET 请求到/drug/list→ SpringMVC 的 DispatcherServlet 根据 HandlerMapping 找到 DrugController → Controller 调用 DrugService 接口 → ServiceImpl 里通过 DrugMapper 接口映射到 XML 里的 SQL 语句 → MyBatis 执行查询并封装成 Drug 实体返回 → 逐层回传到 Vue 页面v-for指令渲染表格。这个链路的每一环都有对应文件而不是一个接口一个方法打天下这正是 SSM 工程规范和 SpringBoot 工程的主要区别。对于药房系统的实际需求来说这个结构够清晰也够用。Vue 端的router/index.js里能看到完整的页面路由表登录页、药品管理、入库管理、出库管理、供应商管理各占一个 component利用 Vue Router 的懒加载机制component: () import(../views/Drug.vue)页面只在路由被访问时才加载首屏性能更好。2.3 关键配置文件web.xml 与 spring-mvc.xml 里容易被忽略的参数SSM 项目最容易出问题的反而是配置文件里的一两个参数。web.xml 中 DispatcherServlet 的url-pattern如果配置成/SpringMVC 会接管所有请求静态资源必须额外放行如果配置成*.do意味着所有前端请求路径必须以 .do 结尾Vue 端 axios 的 baseURL 也要跟着拼上/api/*.do这种格式。源码里用的是 REST 风格路径就是/drug/list这种所以 url-pattern 配的是/同时用mvc:resources标签将 /static/ 路径下的 JS、CSS、图片放行。spring-mvc.xml 里有两个参数要特别记录。第一个是mvc:annotation-driven这个标签必须存在它负责注册 DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter没有它你 Controller 上的 RequestMapping 全部失效接口请求会直接 404。第二个是 InternalResourceViewResolver 的 suffix 和 prefix 参数如果前后端没有完全分离视图解析器会把 Controller 返回的字符串拼成 JSP 路径但本项目是前后端分离后端接口只返回 JSON 数据所以要加上ResponseBody注解或RestController组合注解让 SpringMVC 跳过视图解析、直接用 Jackson 把对象序列化成 JSON 响应给前端。3. 把源码跑起来IDEA 导入、Maven 配置、Vue 环境搭建全流程3.1 环境版本匹配JDK、Maven、Node 之间不能随便搭先把这个项目需要的环境版本一次性说清楚因为版本不匹配导致的报错占新手调试时间的一半以上。JDK 建议用 1.8也就是 Java 8版本SSM 项目的 Spring 5.2.x 框架和 Tomcat 8.5 容器配合得非常稳JDK 11 以上对反射和类加载的模块化限制会更严格SSM 项目运行时可能出现 IllegalAccessError。Maven 用 3.6.x 版本这个版本对 settings.xml 的 mirror 配置兼容性最好。前端环境需要 Node.js 14 以上的 LTS 版本npm 会随 Node 一并安装。打开 IDEA 导入项目时选择File → New → Project from Existing Sources定位到项目根目录下的 pom.xmlIDEA 会自动识别 Maven 项目结构并开始下载依赖。这一步有个小坑没配置阿里云 Maven 镜像源的话中央仓库的下载速度会让你怀疑人生。在%MAVEN_HOME%/conf/settings.xml里找到 mirrors 节点加一段mirror idaliyunmaven/id mirrorOfcentral/mirrorOf name阿里云公共仓库/name urlhttps://maven.aliyun.com/repository/public/url /mirror这段配置的意思是所有从 central 仓库拉取的依赖都转发到阿里云的镜像地址在国内环境下 jar 包下载速度能从几十 KB/s 提升到几 MB/s。如果你发现依赖始终下载不完整大概率是 IDEA 里 Maven 的 settings.xml 路径没指到这个文件进File → Settings → Build, Execution, Deployment → Build Tools → Maven把 User settings file 改成你实际修改的那个文件路径。后端项目的启动入口是 spring-mvc.xml 里配置的 ContextLoaderListener 加载classpath:spring/applicationContext.xml和classpath:spring/spring-mvc.xml如果你用 IDEA 的 Tomcat 插件直接部署需要把项目 artifact 设置成 war exploded 格式。这里我一般会先跑一次mvn clean package -DskipTests确认依赖没问题、能打出 war 包后再配置 Tomcat 容器否则 Tomcat 启动时报的错可能是 Maven 编译的问题。3.2 Vue 前端项目npm install 卡住的排查与路由配置要点前端部分需要用 IDEA 打开前端的pharmacy-ui目录或源码里对应的 Vue 工程名然后在 Terminal 面板执行 npm install 安装依赖。node_modules 目录往往需要 5 到 10 分钟才能装完依赖包数量通常在 800 到 1200 个之间。如果 npm 安装过程报 ERESOLVE 错误或者某个包拉取超时可以切换成淘宝镜像源npm config set registry https://registry.npmmirror.com npm install npm run serve完成之后前端开发服务器默认启动在 8080 端口但这里必须注意后端接口如果部署在 Tomcat 的 8080 端口上前端 dev server 需要换端口Vue CLI 项目里可以通过vue.config.js配置 devServer 的 proxy 实现跨域代理。一个典型的前端代理配置是module.exports { devServer: { port: 3000, proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这个配置解决的是前端页面和后端接口的地址一致性问题前端运行在 3000 端口页面请求接口时写的是/api/drug/list这种相对路径代理会把请求转发到http://localhost:8080后端的 Controller 上同时修改请求头 Origin 避免跨域。要注意 target 的端口必须和 Tomcat 实际端口一致改错一个数字前端就是白屏加一堆 Network Error。这个阶段最常见的表现就是能打开登录页、但点了登录按钮没反应或者 F12 开发工具里看到请求直接失败优先检查代理配置和端口。3.3 数据库连接配置Navicat 建库与 druid 参数对齐后端连数据库前先用 Navicat 或 SQLyog 建好数据库实例。连接上 MySQL 后执行项目里自带的pharmacy.sql脚本这个脚本会创建数据库结构、表结构和初始数据。执行脚本时注意要么在 Navicat 里右键运行 SQL 文件要么在当前连接的查询窗口里直接 source 脚本路径。建库完成后需要到后端的 jdbc.properties 文件里对齐四行参数jdbc.drivercom.mysql.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/pharmacy_db?useUnicodetruecharacterEncodingutf8useSSLfalse jdbc.usernameroot jdbc.password你的数据库密码这个配置说明一下useUnicodetrue 和 characterEncodingutf8 这两个参数决定中文字段是否正确存储和返回。如果缺了这两项药品名称的中文在数据库里能存进去但查询出来就是乱码。useSSLfalse 是为了消除 MySQL 连接时的 SSL 警告。3306 是 MySQL 默认端口装了多个 MySQL 实例的话这里是很容易被忽略的坑点。4. 数据库设计与核心业务表从药品信息到入库出库的数据建模4.1 六张核心表的设计意图与字段说明翻开源码里的 SQL 脚本你会发现这个项目的数据库设计非常有代表性。它不是简单的单表 CRUD而是围绕药房业务设计了相互关联的六张核心表。在 Navicat 里打开表结构整体的关联关系是用户表sys_user管登录权限药品表drug_info管药品静态信息入库表stock_in和出库表stock_out管药品流动记录库存表drug_stock管实时数量供应商表supplier管采购来源。这里直接给出药品表和库存表的核心建表语句源码里有规范物理表名这里用可读文件名代替CREATE TABLE drug_info ( id int(11) NOT NULL AUTO_INCREMENT, drug_code varchar(50) NOT NULL COMMENT 药品编码, drug_name varchar(100) NOT NULL COMMENT 药品名称, specification varchar(100) DEFAULT NULL COMMENT 规格, unit varchar(20) DEFAULT 盒 COMMENT 单位, manufacturer varchar(100) DEFAULT NULL COMMENT 生产厂家, approval_number varchar(100) DEFAULT NULL COMMENT 批准文号, expire_date date DEFAULT NULL COMMENT 有效期至, status tinyint(4) DEFAULT 1 COMMENT 1启用 0停用, PRIMARY KEY (id), UNIQUE KEY uk_drug_code (drug_code) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4; CREATE TABLE drug_stock ( id int(11) NOT NULL AUTO_INCREMENT, drug_id int(11) NOT NULL COMMENT 关联药品表ID, batch_no varchar(50) DEFAULT NULL COMMENT 批次号, quantity int(11) NOT NULL DEFAULT 0 COMMENT 当前库存数量, warn_threshold int(11) NOT NULL DEFAULT 50 COMMENT 库存预警阈值, last_update_time datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_drug_id (drug_id) ) ENGINEInnoDB AUTO_INCREMENT1 DEFAULT CHARSETutf8mb4;从这两张表能看出药房业务的一个核心设计逻辑药品基础信息和库存信息分表存储而不是直接在一个表里加 quantity 字段。原因是药品的批次不同、有效期不同同一款药可能有两个批次的库存如果都写在一个表里查批次明细和做有效期预警都会很困难。drug_stock 通过 drug_id 外键关联 drug_info同时保留 warn_threshold 预警阈值字段默认 50意思是当 quantity 低于 50 时系统就提示需要补货了。expire_date 单独作为日期字段是为了计算距离保质期还剩多少天从而支撑过期预警功能。4.2 后端 MyBatis 关联查询手动组装多表数据前端药品列表页面展示的是一个包含库存数量和供应商信息的复合表格这意味着后端接口不能只查 drug_info 单表。在源码的 DrugMapper.xml 里能看到一段多表联查的 SQL这是整个系统查询部分的核心节点select idselectDrugList resultTypemap SELECT d.id, d.drug_code, d.drug_name, d.specification, d.manufacturer, d.expire_date, s.quantity, s.warn_threshold FROM drug_info d LEFT JOIN drug_stock s ON d.id s.drug_id where if testdrugName ! null and drugName ! AND d.drug_name LIKE CONCAT(%, #{drugName}, %) /if if teststatus ! null AND d.status #{status} /if /where ORDER BY d.id DESC /select这段 SQL 的逻辑说明LEFT JOIN 保证即使某药品还没有入库记录也能在列表中显示基础信息库存量为 NULL 时前端展示为 0 标签和 标签是 MyBatis 动态 SQL 的经典组合解决了查询条件可选的问题——用户在前端搜索框输入药品名称才加 LIKE 条件没输入就不拼这段。CONCAT(%, #{drugName}, %) 这里用了参数占位符而非字符串拼接是防止 SQL 注入的关键新手很容易在 XML 里直接写%${drugName}%那在 MyBatis 里属于字符串替换一旦药品名里包含单引号就会破坏 SQL 结构。status 的判断直接比对数字前端传入的是 0 或 1对应药品停用和启用。4.3 入库出库事务处理多张表更新的原子性控制药品入库操作涉及三个数据源的变动往 stock_in 表插入一条入库记录、在 drug_stock 表更新现有库存数量或插入新批次记录、更新 drug_info 表的状态为启用。这三步只要有一个失败就会造成库存数和流水账不一致的脏数据。源码中在 Service 实现类的入库方法上加了 Transactional 注解这是 Spring 声明式事务的标准用法Override Transactional(rollbackFor Exception.class) public boolean inboundStock(InboundDTO dto) { // 1. 写入入库流水表 stockInMapper.insert(dto); // 2. 查找当前药品是否存在库存记录 DrugStock stock drugStockMapper.selectByDrugId(dto.getDrugId()); if (stock null) { // 首次入库创建新的库存记录 DrugStock newStock new DrugStock(); newStock.setDrugId(dto.getDrugId()); newStock.setBatchNo(dto.getBatchNo()); newStock.setQuantity(dto.getQuantity()); drugStockMapper.insert(newStock); } else { // 已有库存增加数量 stock.setQuantity(stock.getQuantity() dto.getQuantity()); drugStockMapper.updateById(stock); } return true; }方法里的逻辑分两条路径走如果药品还没有库存记录插入一条新数据如果已经有库存记录在原有数量上累加。Transactional 注解的意义在于把这几个数据库操作放进同一个事务上下文任何一步抛异常都会触发全局回滚库存不会出现“流水记了但库存没变”或者反过来。rollbackFor Exception.class 表示只要是运行时异常或者受检异常都回滚而不是只回滚 RuntimeException这是一个重要的细节。很多人写事务时候漏了 rollbackFor 参数导致部分 SQL 异常被吞掉后事务照样提交。5. 避坑记录这套源码最容易踩的五个坑与排查路径5.1 启动报错 ClassNotFoundException: org.springframework.web.servlet.DispatcherServlet现象Tomcat 启动时抛 ClassNotFoundException指向 spring-webmvc 包里的 DispatcherServlet 类。原因项目以 war 包形式部署到 Tomcat 时IDEA 的 artifact 配置里没有把 Maven 依赖的 jar 包打进 WEB-INF/lib 目录Tomcat 找不到 SpringMVC 的类。解决进入File → Project Structure → Artifacts选中部署的 artifact在 Available Elements 面板里找到项目依赖的 jar 包右键选 Put into /WEB-INF/lib。之后重新构建项目再启动。我拿到任何 SSM 源码的第一步都是检查这个配置它能省掉一半的部署报错时间。5.2 前端能打开但后端接口 404拦截器放行路径没配好现象登录页能正常显示但点击登录按钮后浏览器 Network 面板显示请求到了后端返回状态码 404Tomcat 控制台没有任何请求日志。原因spring-mvc.xml 里配置了拦截器拦截所有/api/**请求做 token 校验但登录接口的放行路径没有加入 exclude 列表请求还没到 Controller 就被拦截器截断了。解决找到 WebMvcConfig 或 spring-mvc.xml 里的拦截器配置把登录接口、静态资源路径加入排除列表mvc:interceptors mvc:interceptor mvc:mapping path/**/ mvc:exclude-mapping path/api/login/ mvc:exclude-mapping path/static/**/ bean classcom.pharmacy.interceptor.LoginInterceptor/ /mvc:interceptor /mvc:interceptors路径说明mapping 的/**表示拦截所有请求exclude-mapping 的 /api/login 放行登录接口/static/** 放行静态资源。如果你改了后端接口路径记得同步改这个配置不然任何一个新接口被拦截器挡住前端就会看到 404 和 CORS 报错混在一起的局面。5.3 MySQL 8.0 数据库驱动导致连接失败现象使用 MySQL 8.0 本地数据库运行项目报错Loading class com.mysql.jdbc.Driver. This is deprecated. The new driver class is com.mysql.cj.jdbc.Driver随后连接超时。原因项目的 pom.xml 里默认引入的是 mysql-connector-java 5.1.49这个版本的驱动类名和连接方式只适配 MySQL 5.7 及更早版本MySQL 8.0 改了认证插件和驱动名。解决把 pom.xml 中的依赖替换成dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency同时在 jdbc.properties 里把 driver 改成新版驱动并且 url 增加时区参数jdbc.drivercom.mysql.cj.jdbc.Driver jdbc.urljdbc:mysql://localhost:3306/pharmacy_db?useUnicodetruecharacterEncodingutf8useSSLfalseserverTimezoneAsia/ShanghaiserverTimezoneAsia/Shanghai 这个参数不加的话MySQL 8.0 的驱动会报 CST 时区无法识别或默认时区错误这也是本地连接 MySQL 8.0 时的高频坑。改完 pom 依赖需要重新加载 Maven 项目IDEA 右侧 Maven 面板点一下 Reimport。5.4 中文乱码Vue 传参到后端显示问号现象前端页面提交药品名称后数据库表里存进去的是“阿莫西林”但显示成“???”或者 Tomcat 日志里打印的中文是乱码。原因三段链路的编码不一致——前端页面编码、SpringMVC 的 POST 请求编码过滤器、MySQL 表字段编码。Tomcat 8.5 默认对 POST 请求使用 ISO-8859-1 解码中文自然就乱了。解决三层分别处理。前端 Vue 页面保证 HTML 头 meta 标签设置 charsetutf-8后端在 web.xml 加 Spring 提供的编码过滤器filter filter-nameencodingFilter/filter-name filter-classorg.springframework.web.filter.CharacterEncodingFilter/filter-class init-param param-nameencoding/param-name param-valueUTF-8/param-value /init-param init-param param-nameforceEncoding/param-name param-valuetrue/param-value /init-param /filterforceEncodingtrue 表示强制请求和响应都使用指定编码。数据库端在连接 URL 里保留前面说的 characterEncodingutf8 参数即可。三层全部对齐之后中文就不会再出问题。如果你跳过其中任何一层都可能出现“开发环境好好的、打包部署后乱码”的玄学问题。5.5 端口占用导致 Tomcat 或 Vue Dev Server 启动失败现象启动 Tomcat 时报Port 8080 was already in use或者 npm run serve 报Port 3000 is already in use。原因系统中已有其他 Java 进程或 Node 进程占用了端口。很多人在本机同时跑过多个项目某个残留进程没杀掉。解决Windows 上打开命令行执行netstat -ano | findstr 8080找到对应的 PID然后在任务管理器里结束那个进程或者直接启动前在 IDEA 的 Run Configuration 里把 Tomcat 端口改掉。我一般会在C:\Windows\System32\drivers\etc\hosts保持干净的前提下把项目的端口固定在 8080避免和本机的其他服务冲突。对于 Vue Dev Server 的端口冲突可以在 package.json 的启动脚本里加--port 3001参数或者直接改 vue.config.js 里的 devServer.port。5.6 前端 npm install 后启动报 Vue Router 版本不兼容现象npm install 成功但npm run serve执行时报错提示 Vue Router 某个 API 不存在页面路由无法加载。原因package.json 里 vue-router 的版本号写的是^3.0.0或^4.0.0npm 安装时自动拉取了该主版本下的最新小版本。Vue Router 4 只兼容 Vue 3而这个项目的前端是基于 Vue 2 写的版本对不上直接白屏报错。解决先确认项目里 App.vue 或 main.js 的导入方式Vue 2 项目统一用 Vue Router 3。执行npm install vue-router3.6.5锁定版本然后在 main.js 里按 Vue 2 的标准写法引入Vue.use(VueRouter)。如果你发现源码的 main.js 里用的已经是 createRouter 这种 Vue 3 写法那么 project 本身是基于 Vue 3 的依赖保持一致即可。这个坑尤其隐蔽——你只看了 package.json 没看 main.js 的写法装错了版本浏览器控制台的报错信息还不直白新手容易在这个问题上耗掉一晚上。6. 进阶技巧库存预警与到期药品查询的 SQL 优化实践这套系统的核心价值不只是 CRUD而是围绕药品数据做的实时计算和预警。药房每天都面临两个高频问题哪些药快卖完了需要补货哪些药快到保质期需要下架源码里这两块功能是通过 SQL 加后端定时逻辑实现的这里给出一个可以实际优化的方向。药品到期提醒的做法是在当前日期和 expire_date 之间做差值计算。一个常见的低效写法是在 Java 层把 drug_info 表全量查出然后遍历计算每个药品还剩多少天到期。药房药品数量小则几百、多则上千这种全量查询在数据量小时看不出问题但一旦过万接口响应直接从毫秒级劣化到秒级。更合理的做法是把日期计算下沉到 SQL 层利用 MySQL 的 DATEDIFF 函数在查询时直接完成筛选。在源码的 DrugMapper.xml 里加上一段到期预警查询select idselectExpiringDrugs resultTypemap SELECT d.drug_code, d.drug_name, d.specification, d.expire_date, DATEDIFF(d.expire_date, CURDATE()) AS days_left FROM drug_info d WHERE d.expire_date IS NOT NULL AND d.expire_date BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 30 DAY) ORDER BY days_left ASC /select这段 SQL 的查询条件限定 expire_date 在当天和未来 30 天之间一次性把近效期药品抓出来DATEDIFF 计算出的 days_left 字段表示剩余天数ORDER BY days_left 让最紧急的药品排在最前面前端拿到这个结果后可以直接用 v-for 渲染成预警列表。对比原来的全表查询这个用法的 SQL 执行计划能用到 expire_date 字段上的索引如果建了的话查询时间从线性扫描变成索引范围扫描性能提升明显。库存预警也有一个类似的技巧。drug_stock 表里已经有 warn_threshold 字段默认值是 50查询低库存药品可以这样写SELECT di.drug_name, di.specification, ds.batch_no, ds.quantity, ds.warn_threshold, (ds.warn_threshold - ds.quantity) AS shortage_count FROM drug_stock ds LEFT JOIN drug_info di ON ds.drug_id di.id WHERE ds.quantity ds.warn_threshold ORDER BY shortage_count DESCshortage_count 表示还差多少达到预警线这个字段在前端展示时可以直接拼成“库存不足差 X 件”的提示文案。需要注意这里的比较条件用的是quantity warn_threshold而不是quantity 0因为药房的补货节奏是提前预警而非卖光再补。一次性把这两种预警 SQL 放到 Service 层封装成接口前端加一个“预警信息”菜单整个系统的实用性立刻提升一个档次。使用源码时还有一个建议从这套 SSM 项目迁移到 SpringBoot 时保留 MyBatis 的 Mapper XML 不动只把 Spring 的注解配置换成 SpringBoot 的 starter 自动配置你会发现这套代码的业务逻辑层几乎不需要改动这也从侧面说明 MyBatis 的 XML 和 Spring 的注解解耦做得比较干净。即使是技术再迭代Mapper 里的手写 SQL 和表结构设计始终是你需要保留的核心资产。源码初跑时先别急着看业务细节。我会先通读一遍 jdbc.properties 的数据库配置、web.xml 的过滤器和拦截器、前端 vue.config.js 的代理配置三处改成本地环境后启动后端确认无报错再启动前端联调。从那以后我每次接手这类 SSM 项目都强制走一遍这个流程能省下大量查接口 404 和跨域问题的时间。希望这套药房药品管理系统的源码拆解能帮到你把这套技术栈真正变成自己能改、能用的东西。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/26 22:37:12

MATLAB速率方程模拟ASE:氮气离子空气激光强度计算实战

简介:ASE.zip 面向激光物理与光学工程方向的研究者和高年级学生,聚焦激光放大与激光放大自发辐射(ASE)两大核心主题,并以氮气离子型空气激光的自发放大辐射过程为具体应用场景开展数值计算与仿真。压缩包体积约3KB&…

2026/10/26 22:37:12

元宇宙办公室:分布式团队的沉浸式协作未来

1. 元宇宙办公室:分布式团队的终极协作形态当GitHub宣布全员远程办公时,整个科技圈都在讨论分布式团队的未来。三年后的今天,我们突然发现:Zoom会议和Slack消息组成的"数字流水线"正在消耗创意工作者的灵魂。每周40小时…

2026/10/26 22:37:12

端到端测试实战:e2e profile1配置机制与核心链路设计

1. 从“e2e”说起:端到端测试到底在测什么第一次看到“e2e”这个词,很多人会以为是某个新框架的缩写,或者某个工具的名字。其实它是end-to-end的缩写,中文叫“端到端”。在软件研发语境里,它指的是一种测试层级——从用…

2026/10/27 0:47:33

零基础入门DeepSeek:从提示语设计到模型选择,避开新手五大坑

简介:这份PDF资料源自清华大学新闻与传播学院新媒体研究中心团队,面向希望系统掌握DeepSeek大模型的初学者与进阶用户,帮助读者厘清推理模型与通用模型的差异,并掌握提示语设计的核心策略。内容围绕DeepSeek是什么、能做什么、如何…

2026/10/27 0:47:33

AI工具链可扩展性竞赛:Claude Code Mod化与Meta上下文改写

1. 三条新闻背后,其实是同一件事在三个方向上的推进2026年10月2日这天,AI圈子里同时冒出来三条看起来八竿子打不着的消息:加州那边给OpenAI递了传票,Claude Code宣布开放Mod化能力,Meta在推一个让模型自己改写上下文的…

2026/10/27 0:47:33

隐私优先的AI对话本地存储方案与技术实现

1. 为什么我们需要一个隐私优先的AI对话收藏工具?最近两年AI对话工具爆发式增长,从ChatGPT到Claude,我们每天都会产生大量有价值的对话记录。但你是否注意到,绝大多数第三方收藏工具都在云端存储你的数据?这就像把私人…

2026/10/27 0:47:33

神经逻辑编程:融合神经网络与符号推理的自动化决策技术

1. 神经逻辑编程与自动化推理的融合趋势去年在调试一个复杂业务规则引擎时,我遇到了传统逻辑编程的典型困境:当需要处理模糊边界条件和动态权重计算时,Prolog的确定性子句逻辑显得力不从心。正是这次经历让我开始关注神经符号系统&#xff08…

2026/10/26 0:20:20

全国计算机二级C语言真题PDF高效刷题指南

简介:这份PDF是全国计算机二级C语言考试的试题与答案解析,专为备考二级C语言的考生准备。内容涵盖C语言特点与设计理念、程序基本组成单位、main函数执行流程、函数嵌套调用规则、标识符命名规范、整型实型字符型数据类型、八进制十六进制数合法形式、运…

2026/10/26 1:53:47

requests+BeautifulSoup:爬虫抓取h1标题的入门实战指南

简介:一份以实战为导向的Python爬虫入门资源,面向具备基本编程基础、希望快速掌握网络数据抓取的初学者,可解决从零编写简单爬虫的常见困惑。实例以requests库发送HTTP请求、BeautifulSoup解析HTML文档,完整演示从网页中提取 标题…

2026/10/26 0:20:17

递推最小二乘参数辨识MATLAB编程:二阶系统与渐消记忆实现

简介:这是一篇面向控制系统、信号处理与机器学习等领域学习者的最小二乘参数辨识程序说明文档。资源共包含一个docx格式文档,压缩包大小七十八KB,内容围绕递推最小二乘算法和渐消记忆最小二乘算法展开:先构造一个极点位于单位圆内…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式19_“模式选错”的典型代价

“模式选错”的典型代价 摘要 在软件工程中,设计模式、架构模式、并发模式乃至团队协作模式的选择,往往在项目早期就决定了后续的开发效率和维护成本。本文通过多个真实场景,剖析“模式选错”带来的典型代价——包括返工成本、技术债务累积、…

2026/10/27 0:02:28

WorkBuddy_新建任务与工作模式20_新手推荐路径

新手推荐路径 摘要 在 AI 辅助开发工具快速普及的今天,新手面对最多的困惑往往不是"工具够不够强",而是"我该从哪一步开始用"。本文提出一条经过实践验证的三阶段学习路径:先从 Ask(问答式交互)起…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑