1. 项目概述与核心需求
药品商城系统作为医药电商领域的典型应用,其核心在于实现药品的安全交易与合规管理。基于SpringBoot框架开发的药品商城系统,通常需要设计三个关键角色:管理员、药店商家和普通用户。这种角色划分既符合医药电商的监管要求,又能满足不同参与方的业务需求。
在实际开发中,我们采用SpringBoot 2.7.x版本(兼顾稳定性和新特性)配合MyBatis-Plus作为持久层框架。系统前端采用Vue3+Element Plus实现响应式布局,通过RESTful API与后端交互。数据库选用MySQL 8.0,利用其JSON字段类型存储药品的扩展属性。
提示:医药类系统需特别注意《药品网络销售监督管理办法》的合规要求,包括处方药销售限制、药品信息展示规范等,这些都会直接影响角色权限设计。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 三角色权限体系设计
2.1 管理员角色实现
管理员拥有最高权限,主要功能模块包括:
- 用户管理:使用Spring Security OAuth2实现RBAC模型
- 药品类目审核:采用工作流引擎(集成Activiti)实现多级审批
- 交易监控:通过Spring Boot Admin实时监控订单异常
关键代码示例(权限校验切面):
java复制@Aspect
@Component
public class AdminAuthAspect {
@Before("@annotation(com.med.mall.auth.AdminRequired)")
public void checkAdmin(JoinPoint joinPoint) {
String currentRole = SecurityContextHolder.getContext()
.getAuthentication().getAuthorities();
if(!currentRole.contains("ROLE_ADMIN")) {
throw new AccessDeniedException("需要管理员权限");
}
}
}
2.2 药店商家角色设计
商家端核心功能实现要点:
- 药品管理:
- 使用HanLP分词实现药品搜索关键词提取
- 采用MinIO对象存储管理药品图片和资质文件
- 订单处理:
- 集成Redis实现库存预扣减
- 使用Spring事务管理确保数据一致性
商家入驻流程的特殊处理:
java复制// 商家资质审核状态机
public enum MerchantStatus {
PENDING("待审核", () -> {/* 发送审核通知 */}),
APPROVED("已通过", () -> {/* 初始化商家账户 */}),
REJECTED("已拒绝", () -> {/* 发送拒绝邮件 */});
private final String desc;
private final Runnable action;
// 枚举构造函数和方法...
}
2.3 普通用户角色功能
用户侧关键技术实现:
- 药品搜索:Elasticsearch聚合查询+拼音分词器
- 购物车:Redis Hash结构存储,key=user:cart:
- 订单支付:集成支付宝沙箱环境,使用RSA2签名
安全防护措施:
- 使用Spring Validation校验入参
- 防XSS攻击:自定义Jackson序列化器过滤HTML标签
- 敏感数据脱敏:基于Jackson注解实现
java复制public class UserDTO {
@JsonSerialize(using = PhoneEncryptSerializer.class)
private String phone;
@JsonDeserialize(using = HtmlEscapeDeserializer.class)
private String address;
}
3. 核心业务模块实现
3.1 药品信息管理
采用DDD领域模型设计药品核心聚合根:
java复制public class Medicine {
private Long id;
private String name;
private String approvalNumber; // 国药准字号
private MedicineSpec spec; // 规格值对象
private List<MedicineImage> images;
// 业务方法
public boolean isPrescription() {
return this.spec.getType() == MedicineType.PRESCRIPTION;
}
}
药品缓存策略设计:
- 一级缓存:MyBatis本地缓存(会话级别)
- 二级缓存:Redis集群,采用Hash结构存储
- 缓存击穿解决方案:Redisson分布式锁
3.2 订单交易系统
分布式事务处理方案对比:
| 方案 | 适用场景 | 本系统选择理由 |
|---|---|---|
| Seata AT模式 | 简单业务 | 学习成本低 |
| TCC模式 | 高一致性要求 | 代码侵入性强 |
| 本地消息表 | 最终一致性 | 选择此方案,配合定时任务 |
订单状态机实现代码:
java复制public class OrderStateMachine extends StateMachine<OrderStatus, OrderEvent> {
@Override
protected void configure(StateMachineTransitionConfigurer<OrderStatus, OrderEvent> transitions) {
transitions
.withExternal()
.source(OrderStatus.UNPAID)
.target(OrderStatus.PAID)
.event(OrderEvent.PAY_SUCCESS)
.action(paymentAction());
// 其他状态转换...
}
}
4. 特殊业务场景处理
4.1 处方药销售流程
合规性实现要点:
- 问诊记录存储:使用MongoDB存储结构化问诊数据
- 处方审核:集成OCR识别处方图片(OpenCV预处理)
- 双重验证:医生电子签名+药师审核标记
处方校验流程伪代码:
python复制def validate_prescription(prescription_img):
# 图像预处理
processed = cv2.threshold(prescription_img, 0, 255, cv2.THRESH_OTSU)
# 文字识别
text = paddleocr.ocr(processed)
# 关键信息提取
return extract_medicine_names(text)
4.2 药品搜索优化
多维度搜索方案:
- 基础搜索:Elasticsearch IK分词+同义词扩展
- 拼音搜索:自定义拼音分词器
- 相似药品推荐:Word2Vec向量相似度计算
搜索DSL示例:
json复制{
"query": {
"bool": {
"should": [
{"match": {"name": "阿莫西林"}},
{"match": {"pinyin": "amxl"}},
{"nested": {
"path": "spec",
"query": {"match": {"spec.dosageForm": "胶囊"}}
}}
]
}
}
}
5. 系统安全与合规
5.1 敏感数据保护
具体实施方案:
- 数据库加密:使用Jasypt加密敏感字段
yaml复制jasypt: encryptor: password: ${JASYPT_PASSWORD} algorithm: PBEWITHHMACSHA512ANDAES_256 - 接口安全:
- 防重放攻击:timestamp+nonce校验
- 数据签名:SHA256WithRSA
- 审计日志:使用Spring AOP记录关键操作
5.2 合规性检查
自动化检查方案:
- 药品信息校验:定时任务检查批准文号有效性
- 资质过期提醒:Quartz调度任务提前30天预警
- 敏感词过滤:DFA算法实现实时检测
6. 部署与性能优化
6.1 容器化部署
Docker Compose配置要点:
yaml复制services:
redis:
image: redis:6-alpine
ports: ["6379:6379"]
volumes:
- redis_data:/data
es:
image: elasticsearch:7.17.0
environment:
- discovery.type=single-node
ulimits:
memlock: -1
6.2 性能调优实战
实测有效的优化手段:
- JVM参数:
bash复制
-XX:+UseG1GC -Xms512m -Xmx512m -XX:MaxGCPauseMillis=200 - MySQL优化:
- 药品表使用覆盖索引
- 订单表按用户ID分片
- 缓存策略:
- 热点药品本地缓存(Caffeine)
- 库存数据Redis原子操作
7. 问题排查实录
7.1 典型异常处理
-
订单超卖问题:
- 现象:促销时库存出现负数
- 解决方案:Redis Lua脚本实现原子扣减
lua复制local stock = tonumber(redis.call('HGET', KEYS[1], 'stock')) if stock >= tonumber(ARGV[1]) then return redis.call('HINCRBY', KEYS[1], 'stock', -tonumber(ARGV[1])) end return -1 -
支付掉单问题:
- 现象:支付成功但订单未更新
- 解决方案:支付宝异步通知+主动查询补偿
7.2 监控方案
推荐监控组合:
- 基础监控:Prometheus+Grafana
- 日志分析:ELK收集Spring Boot日志
- 链路追踪:SkyWalking监控微服务调用
关键指标看板配置:
sql复制-- 药品销量TOP10
SELECT m.name, COUNT(o.id)
FROM orders o JOIN medicine m ON o.medicine_id = m.id
GROUP BY m.name ORDER BY COUNT(o.id) DESC LIMIT 10
在项目开发过程中,我们发现SpringBoot的自动装配特性极大简化了第三方组件集成。比如整合MinIO时,通过自定义starter只需几行配置即可完成对象存储服务接入。但也要注意避免过度依赖自动配置,对于药品资质文件存储这类核心功能,建议显式配置校验规则和异常处理逻辑。
