1. 项目概述
这个基于SpringBoot的药品商城系统采用了经典的三角色架构设计,是我去年为一个连锁药店客户开发的实际项目。系统上线后日均订单量稳定在3000+,经受住了618和双十一大促的考验。相比传统医药电商系统,我们特别强化了处方药审核流程和药品库存预警机制,这也是客户最终选择我们方案的关键原因。
系统包含的三个核心角色分别是:
- 管理员:负责商品管理、订单审核、数据统计等后台操作
- 医生:在线开具电子处方,审核用户用药请求
- 普通用户:浏览药品、下单购买、查看订单状态
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 基础框架选型
我们采用SpringBoot 2.7.18 + MyBatis-Plus 3.5.3.1的组合,主要考虑因素包括:
- 快速开发:SpringBoot的自动配置特性大幅减少了XML配置
- 维护性:MyBatis-Plus提供的CRUD接口让DAO层代码减少60%
- 稳定性:这两个版本都是经过市场验证的长期支持版本
java复制// 典型Controller结构示例
@RestController
@RequestMapping("/api/medicine")
public class MedicineController {
@Autowired
private MedicineService medicineService;
@GetMapping("/list")
public Result list(@RequestParam Map<String,Object> params){
PageUtils page = medicineService.queryPage(params);
return Result.ok().put("page", page);
}
}
2.2 数据库设计要点
药品类电商系统有几个特殊的设计考虑:
- 药品分类需要支持GSP认证要求的多级分类
- 处方药需要关联医生资质信息
- 库存管理需要实现批次管理和近效期预警
sql复制CREATE TABLE `t_medicine` (
`id` bigint NOT NULL AUTO_INCREMENT,
`name` varchar(100) NOT NULL COMMENT '药品通用名',
`spec` varchar(50) NOT NULL COMMENT '规格',
`approval_number` varchar(50) DEFAULT NULL COMMENT '批准文号',
`is_prescription` tinyint DEFAULT '0' COMMENT '是否处方药',
`price` decimal(10,2) DEFAULT NULL COMMENT '售价',
`stock` int DEFAULT '0' COMMENT '库存',
`batch_number` varchar(50) DEFAULT NULL COMMENT '批次号',
`expire_date` date DEFAULT NULL COMMENT '有效期',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 核心功能实现
3.1 处方药购买流程
这是系统最复杂的业务场景,涉及多角色协同:
- 用户提交购药请求
- 系统判断是否为处方药
- 处方药需医生在线审核
- 药师二次确认
- 最终完成订单
java复制// 处方审核状态机
public enum PrescriptionStatus {
INIT(0, "待提交"),
PENDING(1, "待医生审核"),
APPROVED(2, "审核通过"),
REJECTED(3, "已拒绝"),
COMPLETED(4, "已完成");
// 省略getter/setter
}
3.2 库存预警机制
药品过期是医药电商的重大风险点,我们实现了:
- 近效期预警(提前3个月)
- 库存下限预警
- 批次管理(先进先出)
- 自动停售过期药品
java复制// 定时检查库存
@Scheduled(cron = "0 0 9 * * ?")
public void checkStock() {
List<Medicine> medicines = medicineService.list();
medicines.stream()
.filter(m -> m.getStock() < m.getMinStock())
.forEach(m -> sendAlert(m));
}
4. 安全与合规设计
4.1 处方药合规处理
- 医生资质审核(对接卫健委数据库)
- 处方签名验证(采用国密SM2算法)
- 处方留存(PDF归档至少5年)
- 敏感操作日志(满足GSP审计要求)
4.2 敏感数据保护
- 患者隐私信息加密存储
- 处方图片加水印
- 数据库字段级加密
- 操作日志脱敏处理
java复制// 数据脱敏示例
public static String desensitize(String str) {
if(StringUtils.isBlank(str)) return "";
return str.substring(0,1) + "****" + str.substring(str.length()-1);
}
5. 性能优化实践
5.1 缓存策略
- 药品基础信息:Redis缓存24小时
- 分类信息:本地缓存Caffeine
- 用户购物车:Session级缓存
- 热点药品:前置CDN缓存
yaml复制# Redis配置示例
spring:
redis:
host: 127.0.0.1
port: 6379
cache:
medicine: 86400 # 24小时过期
category: 259200 # 3天过期
5.2 高并发处理
在大促期间我们遇到的主要挑战:
- 秒杀药品的库存扣减
- 处方审核队列堆积
- 支付结果回调延迟
解决方案:
- 采用Redis+Lua实现原子库存扣减
- 审核任务放入RabbitMQ队列
- 支付结果采用异步通知+主动查询
lua复制-- 库存扣减Lua脚本
local key = KEYS[1]
local num = tonumber(ARGV[1])
local stock = tonumber(redis.call('GET', key))
if stock >= num then
return redis.call('DECRBY', key, num)
else
return -1
end
6. 部署架构
6.1 生产环境配置
- 服务器:4台4C8G的ECS
- 数据库:阿里云RDS MySQL 5.7
- 缓存:Redis集群3节点
- 文件存储:OSS对象存储
- 监控:Prometheus + Grafana
6.2 CI/CD流程
- 代码提交触发Jenkins构建
- 自动化测试(单元测试覆盖率>70%)
- 安全扫描(使用SonarQube)
- 蓝绿部署(通过Nginx切换)
7. 踩坑经验
7.1 处方图片存储
初期直接存数据库导致性能问题,最终方案:
- 原始图片存OSS
- 数据库只存OSS地址
- 生成缩略图缓存
- 添加DRM水印
7.2 事务管理
医药订单的特殊性导致需要:
- 分布式事务(使用Seata)
- 处方状态与订单状态一致性
- 库存扣减与支付结果的最终一致性
java复制// 分布式事务示例
@GlobalTransactional
public void createOrder(OrderDTO dto) {
// 1. 扣减库存
stockService.reduce(dto);
// 2. 创建订单
orderService.create(dto);
// 3. 更新处方状态
prescriptionService.updateStatus(dto);
}
8. 扩展功能
8.1 智能推荐
后期增加的特色功能:
- 基于用药历史的协同过滤
- 症状-药品知识图谱
- 季节性疾病预测推荐
- 会员个性化推荐
8.2 移动端适配
- 微信小程序版本
- 药品扫码识别
- 处方拍照上传
- 用药提醒功能
这个项目让我深刻体会到医药电商与传统电商的差异,特别是在合规性和安全性方面的严格要求。如果重新设计,我会在初期就引入领域驱动设计(DDD)来更好地处理复杂的业务规则。现在系统仍在持续迭代,最近正在开发AI辅助处方审核功能,使用NLP技术自动检查用药合理性。
