1. 项目概述
最近在开发一个疫苗预约小程序,采用了SSM框架(Spring+SpringMVC+MyBatis)作为后端技术栈,前端使用微信小程序技术。这个项目让我对医疗类小程序的开发有了更深入的理解,特别是在数据安全和并发处理方面积累了不少实战经验。
这个小程序主要解决三个核心问题:
- 让用户可以方便地查询和预约各类疫苗
- 帮助医疗机构高效管理疫苗库存和预约信息
- 为疾控部门提供实时的疫苗接种数据统计
系统采用B/S架构,后端使用Java语言开发,数据库选用MySQL,服务器采用Tomcat。这种技术组合在中小型Web应用中非常常见,既保证了开发效率,又能满足性能需求。
2. 技术选型与架构设计
2.1 后端技术栈解析
选择SSM框架组合主要基于以下考虑:
- Spring框架:提供了完善的IoC容器和AOP支持,让项目结构更清晰。通过注解配置大大减少了XML配置的复杂度,我们在项目中大量使用了@Service、@Repository等注解。
- SpringMVC:优秀的MVC框架,特别适合RESTful API开发。我们配置了@RestController来处理小程序端的各种请求,配合@RequestBody和@ResponseBody注解让前后端交互变得简单。
- MyBatis:相比Hibernate,MyBatis的SQL更灵活。我们为复杂的疫苗查询逻辑编写了定制化的SQL,并通过动态SQL特性处理多条件查询。
提示:在配置MyBatis时,建议开启二级缓存和批处理模式,这对疫苗预约这类读多写少的场景性能提升明显。
2.2 数据库设计要点
疫苗预约系统的数据库设计有几个关键点需要注意:
-
用户表(user):
- 包含openid(微信用户唯一标识)、基本信息、接种记录等
- 设置合适的索引提高查询效率
-
疫苗表(vaccine):
- 记录疫苗名称、类型、生产厂家、批次、有效期等关键信息
- 特别注意有效期字段,我们设置了自动任务定期检查临期疫苗
-
预约表(appointment):
- 关联用户和疫苗
- 包含预约时间、接种时间、状态等字段
- 建立了复合索引(user_id, vaccine_id)
sql复制CREATE TABLE `appointment` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`vaccine_id` int(11) NOT NULL,
`appoint_time` datetime NOT NULL,
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0-待接种 1-已接种 2-已取消',
PRIMARY KEY (`id`),
KEY `idx_user_vaccine` (`user_id`,`vaccine_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
2.3 微信小程序前端设计
小程序端开发有几个特别需要注意的点:
-
授权登录流程:
- 使用wx.login获取code
- 后端用code换取openid和session_key
- 建立自己的会话机制
-
疫苗展示页面:
- 采用分页加载
- 实现多条件筛选(疫苗类型、适用年龄等)
- 加入收藏功能提升用户体验
-
预约流程优化:
- 采用步骤引导式界面
- 实时显示可预约时段
- 预约成功后发送模板消息提醒
3. 核心功能实现细节
3.1 用户信息管理模块
用户管理不仅是简单的CRUD,还需要考虑:
- 微信用户同步:
- 首次登录自动创建用户记录
- 定期同步微信头像和昵称
- 实现代码示例:
java复制public User syncWechatUser(String openid, String nickName, String avatar) {
User user = userMapper.selectByOpenid(openid);
if(user == null) {
user = new User();
user.setOpenid(openid);
user.setNickname(nickName);
user.setAvatar(avatar);
userMapper.insert(user);
} else if(!nickName.equals(user.getNickname())) {
user.setNickname(nickName);
user.setAvatar(avatar);
userMapper.update(user);
}
return user;
}
- 敏感信息处理:
- 身份证号等敏感信息加密存储
- 实现数据脱敏展示
- 记录关键操作日志
3.2 疫苗信息管理
疫苗管理是系统的核心,我们实现了:
- 库存预警机制:
- 设置库存阈值
- 自动发送预警通知
- 实现代码逻辑:
java复制public void checkVaccineStock() {
List<Vaccine> lowStockVaccines = vaccineMapper.selectLowStockVaccines();
lowStockVaccines.forEach(vaccine -> {
String message = String.format("疫苗%s库存不足,当前剩余%d剂",
vaccine.getName(), vaccine.getStock());
notificationService.sendStockAlert(message);
});
}
- 批次管理:
- 严格记录疫苗批次
- 实现先进先出(FIFO)的分配策略
- 有效期自动检测
3.3 预约系统实现
预约系统需要考虑高并发场景:
- 预约锁机制:
- 使用数据库乐观锁防止超卖
- 关键代码实现:
java复制public boolean makeAppointment(int userId, int vaccineId) {
Vaccine vaccine = vaccineMapper.selectForUpdate(vaccineId);
if(vaccine.getStock() <= 0) {
return false;
}
int affected = vaccineMapper.reduceStock(vaccineId, vaccine.getVersion());
if(affected == 1) {
Appointment appt = new Appointment();
appt.setUserId(userId);
appt.setVaccineId(vaccineId);
appt.setAppointTime(new Date());
appointmentMapper.insert(appt);
return true;
}
return false;
}
- 时段分流设计:
- 将每天划分为多个时段
- 控制每个时段的预约人数
- 可视化展示各时段预约情况
4. 性能优化与安全实践
4.1 数据库优化技巧
-
索引策略:
- 为高频查询字段建立索引
- 避免过度索引影响写入性能
- 定期使用EXPLAIN分析慢查询
-
连接池配置:
- 使用HikariCP连接池
- 合理设置最大连接数
- 配置连接超时和泄漏检测
4.2 缓存设计
-
疫苗信息缓存:
- 使用Redis缓存热门疫苗数据
- 设置合理的过期时间
- 实现缓存击穿保护
-
预约结果缓存:
- 短期缓存预约成功结果
- 减少数据库查询压力
- 代码示例:
java复制public Appointment getAppointment(int id) {
String cacheKey = "appt:" + id;
Appointment appt = redisTemplate.opsForValue().get(cacheKey);
if(appt == null) {
appt = appointmentMapper.selectById(id);
if(appt != null) {
redisTemplate.opsForValue().set(cacheKey, appt, 30, TimeUnit.MINUTES);
}
}
return appt;
}
4.3 安全防护措施
-
接口安全:
- 所有API进行签名验证
- 敏感操作需要二次确认
- 实现防重放攻击机制
-
数据安全:
- 传输层使用HTTPS
- 敏感字段加密存储
- 定期备份数据库
5. 部署与运维实践
5.1 服务器环境配置
-
Tomcat优化:
- 调整JVM参数
- 配置线程池大小
- 启用GZIP压缩
-
Nginx配置:
- 实现负载均衡
- 配置静态资源缓存
- 设置合理的超时时间
5.2 监控与告警
-
系统监控:
- 使用Prometheus监控JVM
- 监控关键业务指标
- 设置仪表盘可视化
-
日志管理:
- 统一日志格式
- 实现日志分级
- 设置关键错误告警
在项目开发过程中,最大的体会是一定要提前考虑扩展性。比如我们最初设计的疫苗类型字段是简单的字符串,后来发现需要支持多级分类,不得不进行数据库结构调整。建议在初期设计时就为可能的变化预留空间,比如使用JSON字段存储可变属性,或者设计更灵活的数据模型。