1. 项目背景与核心价值
社区新生儿疫苗预约小程序是当前基层医疗数字化改造的重要切入点。去年参与某三甲医院儿科系统升级时,我亲眼目睹了年轻父母抱着孩子排队3小时打疫苗的场景。这种低效模式不仅浪费医疗资源,更增加了交叉感染风险。基于SpringBoot的预约系统能实现:
- 分流效应:将线下排队转化为线上分时段预约,减少现场等待时间
- 数据沉淀:建立辖区新生儿疫苗接种档案,便于后续健康管理
- 服务延伸:通过消息提醒降低漏种率,某试点区域数据显示可使按时接种率提升27%
技术选型上,SpringBoot的starter机制能快速集成微信小程序API、定时任务、消息推送等组件,其约定大于配置的特性特别适合社区医院有限的技术团队进行维护。下面这个案例就来自我帮某社区卫生服务中心实施的真实项目。
2. 系统架构设计
2.1 技术栈组合方案
采用分层架构实现高内聚低耦合:
code复制前端:微信小程序 + Vant Weapp组件库
网关:Nginx 1.18 + SSL证书
后端:SpringBoot 2.7 + JDK11
数据层:MySQL 8.0 + Redis 6.2
中间件:RabbitMQ 3.9(消息队列)
特别说明几个关键选择:
- 放弃MongoDB而采用MySQL:疫苗数据需要严格的事务支持,且社区医院现有IT系统多为关系型数据库
- 引入Redis缓存:预防预约高峰期的并发冲突,采用SETNX实现分布式锁
- 消息队列选型:RabbitMQ的延迟队列特性完美匹配疫苗提醒场景(相比Kafka更轻量)
2.2 数据库核心表结构
sql复制CREATE TABLE `vaccine_appointment` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`child_id` bigint NOT NULL COMMENT '新生儿ID',
`vaccine_id` int NOT NULL COMMENT '疫苗类型',
`schedule_id` int NOT NULL COMMENT '接种时段',
`status` tinyint DEFAULT '0' COMMENT '0-待接种 1-已完成 2-已取消',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_unique` (`child_id`,`vaccine_id`) COMMENT '避免重复预约'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `vaccine_inventory` (
`id` int NOT NULL AUTO_INCREMENT,
`vaccine_type` varchar(50) NOT NULL COMMENT '疫苗名称',
`batch_number` varchar(100) NOT NULL COMMENT '批次号',
`stock` int NOT NULL COMMENT '当前库存',
`freeze_stock` int DEFAULT '0' COMMENT '预扣库存',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
库存管理采用预扣模式:用户预约时先冻结库存,接种完成后扣减实际库存。这比直接减库存更能应对爽约情况。
3. 核心业务实现
3.1 预约流程的并发控制
疫苗预约存在典型的"秒杀"场景特征,采用三级防护策略:
- 前端限流:小程序按钮点击后立即禁用,防止重复提交
- 令牌桶算法:网关层限制单个IP请求频率
- 数据库防重:通过UNIQUE KEY防止同一儿童重复预约同种疫苗
关键代码示例:
java复制@Transactional
public String createAppointment(AppointmentDTO dto) {
// 1. 校验库存
VaccineStock stock = stockMapper.selectForUpdate(dto.getVaccineId());
if (stock.getAvailableStock() <= 0) {
throw new BusinessException("该疫苗已约满");
}
// 2. 分布式锁
String lockKey = "vaccine:lock:" + dto.getVaccineId();
boolean locked = redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if (!locked) {
throw new BusinessException("操作太频繁,请稍后再试");
}
try {
// 3. 创建预约记录
Appointment entity = convertToEntity(dto);
appointmentMapper.insert(entity);
// 4. 扣减冻结库存
stockMapper.freezeStock(dto.getVaccineId(), 1);
return "预约成功";
} finally {
redisTemplate.delete(lockKey);
}
}
3.2 动态时段生成算法
接种时段不是固定配置,而是根据以下因素动态计算:
- 医护人员排班情况
- 每种疫苗的平均接种时长(如乙肝疫苗需观察30分钟)
- 历史时段履约率(优化时段分配)
java复制public List<TimeSlot> generateTimeSlots(LocalDate date, int vaccineType) {
// 获取基础配置
VaccineConfig config = configService.getById(vaccineType);
int durationMinutes = config.getDurationMinutes();
int maxPerSlot = config.getMaxPerSlot();
// 获取可用医护人员
List<Staff> availableStaff = staffService.getAvailableStaff(date);
// 计算总接待能力
int totalCapacity = availableStaff.size() * (60 / durationMinutes) * 8; // 8小时工作制
// 动态调整每个时段的可预约数
int recommendedPerSlot = (int) Math.ceil((double)maxPerSlot *
historicalDataService.getAttendanceRate(date.getDayOfWeek()));
// 生成时段列表...
}
4. 异常处理与监控
4.1 典型异常场景应对
-
重复预约:
- 前端:预约成功跳转后禁用返回按钮
- 后端:通过child_id+vaccine_id唯一索引拦截
- 补偿机制:每日凌晨扫描异常状态预约
-
库存超卖:
java复制@Retryable(value = SQLException.class, maxAttempts = 3) public void deductStock(Long vaccineId) { int affected = stockMapper.deductStock(vaccineId); if (affected == 0) { throw new OptimisticLockingFailureException("库存不足"); } } -
消息推送失败:
- 采用本地消息表+定时任务重试
- 失败3次以上转人工处理
4.2 监控指标设计
通过Spring Boot Actuator暴露以下关键指标:
/metrics/appointment.success成功预约数/metrics/appointment.failure失败原因统计/metrics/vaccine.stock各疫苗库存水位
配置Grafana看板监控:
- 预约成功率波动
- 库存预警线(当可用库存<20时触发告警)
- 时段履约率热力图
5. 部署优化实践
5.1 性能调优参数
在application.yml中关键配置:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20 # 根据社区医院并发量调整
connection-timeout: 3000
redis:
lettuce:
pool:
max-active: 32
max-wait: 1000
rabbitmq:
listener:
simple:
prefetch: 10 # 控制消息消费速度
5.2 安全防护措施
- 接口鉴权:采用JWT+小程序openId双重验证
- 数据脱敏:儿童信息返回时自动隐藏敏感字段
- 操作日志:记录所有数据变更的完整轨迹
- 定期备份:每天凌晨3点全量备份SQL到OSS
6. 扩展功能建议
在实际运行中,我们后续增加了这些实用功能:
- 智能推荐:根据儿童出生日期自动计算应种疫苗
- 同行人管理:允许添加爷爷奶奶等陪同人员信息
- 接种证明:生成带电子签章的PDF接种凭证
- 异常反馈:拍照上传接种部位异常情况
重要提示:疫苗类系统必须通过等保三级认证,建议在开发初期就引入专业安全团队进行代码审计。我们项目曾因未对预约取消接口做权限控制,导致测试期间出现批量恶意取消的情况。
源码中特别值得参考的模块:
vaccine-calendar智能排期算法inventory-service库存预扣实现message-queue延迟消息处理export-service数据导出与统计