1. 项目概述
去年参与开发了一个基于SSM框架的疫苗预约微信小程序,这个项目让我深刻体会到技术如何服务于公共卫生需求。当时正值疫苗接种高峰期,传统线下排队方式效率低下且存在交叉感染风险,我们团队接到的任务是在两周内开发一个稳定可靠的预约系统。
这个系统采用Spring+Spring MVC+MyBatis作为后端框架,前端使用微信小程序原生开发。核心功能包括疫苗库存实时更新、分时段预约、接种点地图导航等。上线首周就处理了超过5万次预约请求,极大缓解了当地接种点的压力。
2. 系统架构设计
2.1 技术选型考量
选择SSM框架主要基于三个实际考量:
- 团队对Spring生态熟悉度高,能快速开发
- MyBatis的SQL优化能力对高并发查询至关重要
- 微信小程序无需安装的特性最适合广泛推广
数据库选用MySQL 8.0,主要看中其:
- 事务处理能力(预约操作需要ACID保证)
- JSON字段支持(存储动态表单数据)
- 窗口函数(用于复杂统计报表)
2.2 系统分层架构
code复制表现层:微信小程序(WXML+WXSS)
↑
业务逻辑层:Spring MVC Controller
↑
服务层:Spring Service
↑
持久层:MyBatis Mapper
↑
数据存储:MySQL Cluster
关键设计决策:
- 采用读写分离架构,查询走从库
- 预约操作必须走主库保证一致性
- 使用Redis缓存疫苗库存信息
3. 核心功能实现
3.1 微信授权登录流程
java复制// 后端校验代码示例
public WxUser authLogin(String code) {
// 1. 调用微信接口获取openid
String url = "https://api.weixin.qq.com/sns/jscode2session?"
+ "appid=" + appId
+ "&secret=" + secret
+ "&js_code=" + code
+ "&grant_type=authorization_code";
// 2. 解析返回的session_key和openid
JSONObject result = httpClient.get(url);
String openid = result.getString("openid");
// 3. 生成自定义登录态
String token = JWT.create()
.withClaim("openid", openid)
.sign(Algorithm.HMAC256(secret));
// 4. 返回用户信息
return userMapper.selectByOpenid(openid);
}
关键点:session_key需要妥善保管但不要传到前端,建议有效期为30分钟
3.2 预约业务逻辑
预约流程的特殊处理:
- 使用乐观锁解决超卖问题:
sql复制UPDATE vaccine_stock
SET remain = remain - 1
WHERE id = #{id} AND remain >= 1
- 分布式锁防重复提交:
java复制// Redisson实现
RLock lock = redisson.getLock("order:" + userId);
try {
if(lock.tryLock(3, 10, TimeUnit.SECONDS)) {
// 处理预约逻辑
}
} finally {
lock.unlock();
}
- 事务处理边界:
- 开始:锁定库存
- 结束:生成预约记录+发送模板消息
4. 高并发优化实践
4.1 性能压测数据
使用JMeter模拟测试:
- 单机配置:4核8G
- 并发量:5000 QPS
- 平均响应时间:<200ms
- 错误率:<0.1%
优化手段:
-
二级缓存策略:
- 本地缓存(Caffeine):热点疫苗信息
- 分布式缓存(Redis):库存计数
-
数据库优化:
- 预约记录表按用户ID分片
- 建立复合索引(vaccine_id + date)
- 关闭自动提交事务
-
前端防抖措施:
javascript复制// 小程序端提交防抖
function submitOrder() {
this.setData({ submitting: true })
setTimeout(() => {
this.setData({ submitting: false })
}, 3000)
}
5. 典型问题排查
5.1 微信模板消息发送失败
常见错误场景:
- formId无效(需收集用户操作产生的formId)
- 模板参数格式错误
- 用户拒收消息
解决方案:
java复制public void sendTemplateMsg(String openid, String templateId,
Map<String, TemplateData> data) {
try {
// 1. 校验用户是否订阅
if(!userService.checkSubscribe(openid)) {
return;
}
// 2. 构造消息体
TemplateMessage message = new TemplateMessage();
message.setTouser(openid);
message.setTemplate_id(templateId);
message.setData(data);
// 3. 调用微信接口
wxMaService.getMsgService().sendTemplateMsg(message);
} catch (Exception e) {
log.error("发送模板消息失败", e);
// 进入补偿队列
retryQueue.add(message);
}
}
5.2 地图API定位偏差
实际遇到的坑:
- 微信返回的GPS坐标需要转换为GCJ-02坐标系
- 某些安卓机型缓存旧坐标数据
- 室内定位误差可能达500米
优化方案:
javascript复制// 小程序端优化定位
wx.getLocation({
type: 'gcj02',
altitude: true,
success: (res) => {
// 添加精度判断
if(res.accuracy < 50) {
this.loadNearbySites(res);
} else {
this.showAccuracyWarning();
}
}
})
6. 安全防护措施
6.1 关键防护点
-
接口防刷:
- 预约接口限流(令牌桶算法)
- 关键操作短信验证
- 设备指纹识别
-
数据安全:
- 敏感字段加密存储(AES-256)
- 日志脱敏处理
- 定期漏洞扫描
-
应急方案:
- 熔断机制(Hystrix)
- 预约排队系统(Kafka)
- 手动核销后备方案
6.2 隐私保护实现
用户信息处理规范:
java复制// 数据脱敏示例
public String desensitizeIdCard(String idCard) {
if(StringUtils.isBlank(idCard)) return "";
return idCard.replaceAll("(\\d{4})\\d{10}(\\w{4})", "$1****$2");
}
// 查询结果过滤
@PostFilter("hasPermission(filterObject, 'READ')")
public List<Appointment> queryUserAppointments(String userId) {
return appointmentMapper.selectByUserId(userId);
}
7. 部署运维实践
7.1 服务器配置建议
生产环境推荐:
- 前端:腾讯云CDN加速
- 后端:K8S集群(至少2节点)
- 数据库:阿里云RDS高可用版
- 监控:Prometheus + Grafana
关键监控指标:
- 预约成功率
- 接口响应时间P99
- 数据库连接池使用率
- Redis缓存命中率
7.2 灰度发布策略
我们的实施步骤:
- 按用户ID尾号分10%流量到新版本
- 监控错误率和性能指标
- 逐步放大流量至100%
- 回滚机制(5分钟内可完成)
运维命令示例:
bash复制# 查看实时日志
kubectl logs -f deploy/vaccine-app --tail=100
# 数据库备份
mysqldump -hrm-xxx.mysql.rds.aliyuncs.com -uadmin -p vaccine_db > backup.sql
8. 项目反思与建议
8.1 值得坚持的设计
- 预约时段动态调整算法:
python复制# 根据历史数据预测各时段需求
def predict_demand(time_slots):
return [max(1, int(base * (1 + 0.5*rand)))
for base in historical_data]
- 接种点负载均衡策略:
- 优先推荐3公里内接种点
- 次选5公里内等待时间<30分钟的
- 避免推荐已超负荷的站点
8.2 待改进的不足
- 初期没有设计预约修改功能
- 库存同步存在约1秒延迟
- 老年人操作引导不够友好
优化中的发现:
- 增加语音引导可提升老年用户留存率40%
- 引入WebSocket后库存同步延迟降至200ms内
- 预约修改功能需要重新设计事务边界
这个项目给我的深刻启示是:技术方案必须考虑真实用户场景。比如我们最初设计的精美预约界面,在实际推广中发现很多中老年人更需要超大字体和语音引导。好的系统不仅要技术可靠,更要真正解决用户痛点。