1. 项目背景与核心需求
医院门诊预约挂号一直是医疗服务的痛点之一。传统线下排队挂号不仅耗费患者大量时间,也增加了医院管理成本。我在大三实习期间曾亲眼目睹三甲医院早晨6点就排起的长龙,这种低效模式催生了我的毕业设计选题——基于SpringBoot的智能预约平台小程序。
这个系统的核心要解决三个问题:
- 患者侧:实现分时段精准预约,减少无效等待
- 医生侧:动态管理接诊量,避免超负荷工作
- 管理侧:可视化监控门诊数据,优化资源配置
2. 技术选型与架构设计
2.1 为什么选择SpringBoot+Vue+小程序组合
后端采用SpringBoot框架主要基于三个考量:
- 自动配置特性大幅减少XML配置(相比传统SSM)
- 内嵌Tomcat方便打包部署
- 丰富的Starter依赖(如spring-boot-starter-data-redis)
前端技术栈的搭配逻辑:
- Vue.js:组件化开发适合管理后台的复杂交互
- 微信小程序:即用即走的特性符合挂号场景
- Uni-app:一套代码多端发布(后期可扩展App)
2.2 系统分层架构详解
code复制┌─────────────────────────────────┐
│ 微信小程序端 │
└──────────────┬──────────────────┘
│HTTP/HTTPS
┌──────────────▼──────────────────┐
│ API Gateway │
│ ┌───────────┴───────────────┐ │
│ │ SpringCloud │ │
│ └───────────┬───────────────┘ │
└──────────────▼──────────────────┘
┌─────────────────────────────────┐
│ 业务微服务集群 │
│ ┌───────┐ ┌───────┐ ┌─────┐ │
│ │ 预约 │ │ 支付 │ │ 消息│ │
│ └───────┘ └───────┘ └─────┘ │
└──────────────┬──────────────────┘
┌──────────────▼──────────────────┐
│ 数据持久层 │
│ ┌───────────┴───────────────┐ │
│ │ MySQL │ Redis │ │
│ └───────────────────────────┘ │
└─────────────────────────────────┘
3. 核心功能实现细节
3.1 智能分时段预约算法
关键代码逻辑:
java复制// 基于历史数据动态计算时段权重
public List<TimeSlot> generateTimeSlots(LocalDate date, Long deptId) {
// 1. 获取该科室医生排班信息
List<Schedule> schedules = scheduleMapper.selectByDeptAndDate(deptId, date);
// 2. 查询过去30天同星期几的就诊时长数据
List<DurationStat> stats = statMapper.selectDurationStats(
deptId,
date.getDayOfWeek().getValue(),
LocalDate.now().minusDays(30)
);
// 3. 计算每个时段的可预约量(核心算法)
return schedules.stream()
.flatMap(schedule -> {
LocalTime start = schedule.getStartTime();
LocalTime end = schedule.getEndTime();
int slotMinutes = 15; // 基础时间片
return Stream.iterate(start, t -> t.plusMinutes(slotMinutes))
.takeWhile(t -> t.isBefore(end))
.map(t -> {
double weight = calculateTimeSlotWeight(t, stats);
int available = (int)(schedule.getMaxPatients() * weight);
return new TimeSlot(t, available);
});
})
.collect(Collectors.toList());
}
3.2 高并发场景下的锁号机制
采用Redis分布式锁+乐观锁双重保障:
- 先用SETNX抢锁(设置3秒过期)
- 查询剩余号源
- 使用CAS更新库存:
sql复制UPDATE registration_slots
SET available = available - 1
WHERE slot_id = ? AND available = ?
踩坑记录:初期仅用数据库乐观锁,在春节挂号高峰出现超卖。后来加入Redis预减库存,将QPS从200提升到2000+
4. 典型业务场景实现
4.1 就诊提醒闭环流程
code复制sequenceDiagram
患者->>小程序: 预约成功
小程序->>MQ: 发送预约消息
MQ->>定时任务: 延迟队列(就诊前1天)
定时任务->>微信服务: 推送模板消息
微信服务->>患者: 提醒通知
患者->>小程序: 点击确认
小程序->>后台: 记录确认状态
4.2 医生排班可视化配置
前端采用FullCalendar组件实现:
javascript复制// 排班日历配置
const calendar = new FullCalendar.Calendar(calendarEl, {
initialView: 'timeGridWeek',
slotMinTime: '08:00',
slotMaxTime: '18:00',
events: async function(fetchInfo, successCallback) {
const res = await axios.get(`/api/schedules?doctorId=${doctorId}`)
successCallback(res.data.map(item => ({
id: item.id,
title: `${item.deptName}诊室`,
start: `${item.workDate}T${item.startTime}`,
end: `${item.workDate}T${item.endTime}`,
editable: true,
backgroundColor: getDeptColor(item.deptId)
})))
},
eventDrop: async function(info) {
await axios.put(`/api/schedules/${info.event.id}`, {
startTime: info.event.start.toLocaleTimeString(),
endTime: info.event.end.toLocaleTimeString()
})
}
})
5. 部署与监控方案
5.1 容器化部署实践
Docker Compose编排文件关键配置:
yaml复制version: '3'
services:
app:
image: registry.cn-hangzhou.aliyuncs.com/hospital/app:${TAG}
deploy:
resources:
limits:
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 10s
retries: 3
redis:
image: redis:6-alpine
command: redis-server --requirepass ${REDIS_PASS}
volumes:
- redis_data:/data
volumes:
redis_data:
5.2 监控指标埋点
通过SpringBoot Actuator暴露的指标:
registration.count:每分钟预约量api.latency:接口响应时间error.rate:错误率
Grafana监控看板配置示例:
code复制avg(rate(registration_count[1m])) by (deptId) // 科室预约趋势
histogram_quantile(0.95, sum(rate(api_latency_bucket[1m])) by (le)) // P95延迟
6. 毕业设计扩展建议
- 智能推荐科室:接入NLP服务解析症状描述,匹配最佳科室
- 候诊时间预测:基于实时就诊数据估算等待时长
- 医保对接:实现微信医保支付功能
- 容灾方案:设计数据库故障时的降级策略
我在实现过程中最大的收获是理解了分布式系统的一致性挑战。比如在支付和预约的分布式事务处理上,最终采用了本地消息表+定时任务补偿的方案。建议学弟妹们在开发时一定要提前考虑异常场景,做好日志埋点。
