SpringBoot药品进销存系统开发与GSP规范实践
2026/8/3 11:56:37
网站开发
1. 项目概述药品库房进销存管理系统的核心价值药品库房管理系统是医疗信息化建设中的关键环节。传统人工管理方式存在库存盘点效率低、效期管理混乱、批次追溯困难等痛点而基于SpringBoot的进销存系统能有效解决这些问题。我在三甲医院信息科实施此类系统时发现药品管理有三大核心需求严格的批次效期管控、完整的进销存台账、实时库存预警机制。这个毕业设计项目采用SpringBootVue前后端分离架构后端使用MyBatis-Plus操作MySQL数据库前端采用Element UI组件库。系统需要实现药品基础信息管理、采购入库、销售出库、库存盘点、效期预警、报表统计等核心功能模块。特别要注意药品管理的GSP规范要求这是区别于普通商品管理系统的关键。2. 技术选型与架构设计2.1 为什么选择SpringBoot框架SpringBoot的自动配置特性让毕业生能快速搭建项目骨架。通过spring-boot-starter-web、spring-boot-starter-data-jpa等starter依赖可以避免繁琐的XML配置。我在实际项目中验证过相比传统SSM框架SpringBoot能减少约60%的基础配置代码量。特别推荐使用MyBatis-Plus而非原生MyBatis它的BaseMapper和Wrapper能大幅简化CRUD操作。例如药品批次查询可以这样实现// 批次查询示例 LambdaQueryWrapperDrugBatch wrapper new LambdaQueryWrapper(); wrapper.eq(DrugBatch::getDrugId, drugId) .ge(DrugBatch::getExpireDate, LocalDate.now()) .orderByAsc(DrugBatch::getExpireDate); ListDrugBatch batches drugBatchMapper.selectList(wrapper);2.2 数据库设计要点药品库房系统的数据库设计有特殊要求必须包含批次表(batch)记录生产批号、生产日期、有效期需要库存流水表(inventory_flow)记录每次出入库操作药品基础表(drug)需要包含批准文号、规格、单位等GSP要求字段典型表结构设计示例CREATE TABLE drug ( id bigint PRIMARY KEY COMMENT 药品ID, code varchar(20) UNIQUE COMMENT 药品编码, name varchar(100) NOT NULL COMMENT 通用名称, spec varchar(50) COMMENT 规格, unit varchar(10) COMMENT 单位, approval_no varchar(50) COMMENT 批准文号, manufacturer varchar(200) COMMENT 生产厂家 ); CREATE TABLE drug_batch ( id bigint PRIMARY KEY, drug_id bigint NOT NULL COMMENT 药品ID, batch_no varchar(50) NOT NULL COMMENT 批次号, production_date date NOT NULL COMMENT 生产日期, expire_date date NOT NULL COMMENT 有效期至, stock int DEFAULT 0 COMMENT 当前库存 );重要提示必须建立联合唯一索引确保批次唯一性ALTER TABLE drug_batch ADD UNIQUE INDEX idx_drug_batch (drug_id, batch_no)3. 核心功能实现细节3.1 药品批次管理实现药品批次管理是系统的核心难点。在入库时需要实现自动生成批次号可按规则厂家首字母年月日序号效期验证拒绝录入已过期药品库存合并相同批次入库时累加数量而非新增记录关键代码示例Transactional public void addBatch(DrugBatch batch) { // 效期校验 if (batch.getExpireDate().isBefore(LocalDate.now())) { throw new BusinessException(禁止录入已过期药品); } // 检查是否已存在相同批次 LambdaQueryWrapperDrugBatch wrapper new LambdaQueryWrapper(); wrapper.eq(DrugBatch::getDrugId, batch.getDrugId()) .eq(DrugBatch::getBatchNo, batch.getBatchNo()); DrugBatch exist drugBatchMapper.selectOne(wrapper); if (exist ! null) { // 已有批次则更新库存 exist.setStock(exist.getStock() batch.getStock()); drugBatchMapper.updateById(exist); } else { // 新批次则插入记录 drugBatchMapper.insert(batch); } // 记录入库流水 InventoryFlow flow new InventoryFlow(); flow.setOperationType(PURCHASE); flow.setQuantity(batch.getStock()); inventoryFlowMapper.insert(flow); }3.2 库存预警功能设计药品管理必须实现效期预警和库存下限预警效期预警提前3个月提示近效期药品库存预警当库存低于安全库存量时提醒建议使用Spring Scheduler定时任务每日检查Scheduled(cron 0 0 9 * * ?) // 每天上午9点执行 public void checkDrugWarning() { // 近效期检查 LocalDate warningDate LocalDate.now().plusMonths(3); ListDrugBatch expiring drugBatchMapper.selectList( new LambdaQueryWrapperDrugBatch() .le(DrugBatch::getExpireDate, warningDate) .gt(DrugBatch::getStock, 0) ); // 库存下限检查 ListDrug lowStock drugMapper.selectList( new LambdaQueryWrapperDrug() .lt(DrugStock::getCurrentStock, DrugStock::getSafetyStock) ); // 发送预警通知 warningService.sendExpireWarning(expiring); warningService.sendLowStockWarning(lowStock); }4. 典型问题与解决方案4.1 库存并发问题处理当多个终端同时操作同一药品库存时会出现超卖问题。解决方案数据库层面使用乐观锁机制Transactional public void reduceStock(Long batchId, int quantity) { DrugBatch batch drugBatchMapper.selectById(batchId); if (batch.getStock() quantity) { throw new BusinessException(库存不足); } // 乐观锁更新 int updated drugBatchMapper.updateStock(batchId, quantity, batch.getVersion()); if (updated 0) { throw new ConcurrentUpdateException(库存并发修改冲突); } }对应的Mapper XMLupdate idupdateStock UPDATE drug_batch SET stock stock - #{quantity}, version version 1 WHERE id #{batchId} AND version #{version} AND stock #{quantity} /update业务层面采用Redis分布式锁public boolean deductStockWithLock(Long batchId, int quantity) { String lockKey stock_lock: batchId; try { // 尝试获取锁设置10秒过期防止死锁 boolean locked redisTemplate.opsForValue() .setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS); if (!locked) { return false; } // 执行库存扣减 return stockService.reduceStock(batchId, quantity); } finally { redisTemplate.delete(lockKey); } }4.2 报表性能优化当处理大量历史数据统计时直接查询事务表会导致性能问题。建议方案建立统计中间表每日凌晨跑批更新对大表进行分库分表按年度拆分使用Cacheable缓存常用报表数据Cacheable(value monthlyReport, key #year-#month) public MonthlyReportVO generateMonthlyReport(int year, int month) { // 复杂统计查询逻辑 return reportMapper.getMonthlyReport(year, month); }5. 部署与监控方案5.1 基于Docker的部署推荐使用Docker Compose部署整套系统version: 3 services: mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: root MYSQL_DATABASE: drug_inventory ports: - 3306:3306 volumes: - ./mysql/data:/var/lib/mysql redis: image: redis:alpine ports: - 6379:6379 app: build: . ports: - 8080:8080 depends_on: - mysql - redis environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/drug_inventory SPRING_REDIS_HOST: redis5.2 SpringBoot Admin监控通过spring-boot-admin-server监控应用状态服务端配置EnableAdminServer SpringBootApplication public class AdminServerApplication { public static void main(String[] args) { SpringApplication.run(AdminServerApplication.class, args); } }客户端配置spring.boot.admin.client.urlhttp://localhost:8080 management.endpoints.web.exposure.include* management.endpoint.health.show-detailsalways我在实际部署中发现对药品管理系统特别需要监控数据库连接池活跃连接数JVM内存使用情况关键接口的响应时间定时任务执行状态6. 毕业设计扩展建议如果想提升项目竞争力可以考虑增加药品扫码出入库功能集成ZXing实现与HIS系统的对接模拟HL7协议添加药品图片管理使用MinIO存储开发移动端盘点功能Uniapp跨平台方案加入数据分析模块Echarts可视化一个完整的药品批次追溯功能实现示例public ListDrugTraceVO traceDrugBatch(Long batchId) { // 1. 获取批次基本信息 DrugBatch batch drugBatchMapper.selectById(batchId); // 2. 查询所有相关出入库记录 ListInventoryFlow flows inventoryFlowMapper.selectList( new LambdaQueryWrapperInventoryFlow() .eq(InventoryFlow::getBatchId, batchId) .orderByAsc(InventoryFlow::getOperationTime) ); // 3. 构建追溯链 ListDrugTraceVO traceChain new ArrayList(); int balance 0; for (InventoryFlow flow : flows) { balance flow.getOperationType().equals(IN) ? flow.getQuantity() : -flow.getQuantity(); DrugTraceVO trace new DrugTraceVO(); trace.setOperationTime(flow.getOperationTime()); trace.setOperationType(flow.getOperationType()); trace.setQuantity(flow.getQuantity()); trace.setBalance(balance); trace.setOperator(flow.getOperator()); traceChain.add(trace); } return traceChain; }药品管理系统的测试环节要特别注意模拟高并发库存操作测试验证效期管控的边界条件测试断电等异常场景下的数据一致性进行压力测试确保报表查询性能我在实际项目验收时会重点检查批次管理的完整性和准确性库存扣减的原子性保证预警机制的有效性数据备份和恢复方案