1. 项目背景与核心需求分析
医疗预约系统作为医疗机构数字化转型的关键环节,正在全国各级医院快速普及。这个基于Java的毕业设计项目,瞄准了当前医疗资源分配不均、患者挂号难等痛点问题。我在三甲医院信息科实习期间,亲眼目睹了传统窗口挂号模式下,患者凌晨排队却挂不上号的困境。
系统需要实现的核心功能包括:
- 患者端:科室查询、医生排班查看、在线预约、预约记录管理
- 医生端:排班管理、患者预约查看、停诊设置
- 管理员端:用户管理、科室管理、号源分配、数据统计
关键设计考量:系统必须保证在高并发场景下的稳定性,特别是每天放号时段可能出现的瞬时流量高峰。同时要符合《医疗机构信息系统应用水平分级评价标准》中对预约系统的数据安全要求。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术选型与架构设计
2.1 后端技术栈
采用Spring Boot 2.7 + MyBatis Plus组合,这是经过多个医疗项目验证的稳定方案:
- Spring Boot:简化配置,内置Tomcat容器
- MyBatis Plus:增强的ORM框架,减少90%的常规SQL编写
- Redis:缓存科室列表、医生排班等热点数据
- RabbitMQ:异步处理预约短信通知
java复制// 典型控制器示例
@RestController
@RequestMapping("/api/appointment")
public class AppointmentController {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@GetMapping("/departments")
public Result<List<Department>> getActiveDepartments() {
// 先从Redis获取,不存在则查数据库
}
}
2.2 数据库设计
遵循医疗行业数据库设计规范,核心表包括:
- 患者表(patient):身份证号加密存储
- 医生表(doctor):关联科室和职称
- 排班表(schedule):包含出诊日期、时段、号源总数
- 预约表(appointment):状态字段区分"待就诊"/"已取消"
特别注意:预约表需要建立(患者ID, 排班ID)的唯一索引,防止重复预约。同时要添加就诊日期字段的索引,便于统计查询。
3. 核心业务逻辑实现
3.1 预约流程的并发控制
采用Redis分布式锁解决超卖问题:
java复制public Result makeAppointment(Long scheduleId, Long patientId) {
String lockKey = "lock:appointment:" + scheduleId;
try {
// 获取分布式锁(设置3秒过期防止死锁)
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 3, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 1. 查询剩余号源
// 2. 如果>0则创建预约记录
// 3. 扣减剩余号源
return Result.success();
}
return Result.fail("当前预约人数过多,请重试");
} finally {
redisTemplate.delete(lockKey);
}
}
3.2 排班规则的灵活配置
通过策略模式实现不同科室的差异化排班:
- 普通科室:按周固定排班
- 专家门诊:按月手动设置
- 急诊科:自动生成24小时排班
java复制public interface ScheduleStrategy {
List<Schedule> generateSchedules(Doctor doctor, LocalDate startDate, LocalDate endDate);
}
@Service
@Qualifier("weeklyStrategy")
public class WeeklyScheduleStrategy implements ScheduleStrategy {
// 实现每周固定时间排班
}
4. 系统安全与合规实现
4.1 敏感数据保护
- 患者身份证号:AES加密存储
- 数据库连接:使用Jasypt加密配置
- 接口权限:Spring Security + JWT实现RBAC
yaml复制# application-security.yml
security:
jwt:
secret: ${JWT_SECRET}
expiration: 86400000 # 24小时
4.2 审计日志
所有关键操作记录审计日志:
- 谁在什么时间执行了什么操作
- 修改前后的数据快照
- 操作IP和设备信息
java复制@Aspect
@Component
public class AuditLogAspect {
@AfterReturning(pointcut = "@annotation(auditable)", returning = "result")
public void afterAuditableMethod(JoinPoint jp, Auditable auditable, Object result) {
// 记录审计日志
}
}
5. 项目部署与测试
5.1 压力测试方案
使用JMeter模拟高峰场景:
- 1000并发用户抢50个号源
- 测试接口响应时间和成功率
- 监控服务器资源占用
测试关键指标:
- 平均响应时间 < 500ms
- 错误率 < 0.1%
- CPU利用率 < 70%
5.2 容器化部署
Docker Compose编排服务:
yaml复制version: '3'
services:
app:
image: hospital-booking:1.0
ports:
- "8080:8080"
depends_on:
- redis
- mysql
redis:
image: redis:6
ports:
- "6379:6379"
6. 毕设答辩常见问题
-
如何防止黄牛刷号?
- 验证码+设备指纹识别
- 同一身份证号每日限约次数
- 异常行为监控(如毫秒级重复请求)
-
系统如何保证数据一致性?
- 分布式事务(Seata)
- 定时对账任务
- 异常预约人工审核机制
-
与医院HIS系统如何对接?
- 通过WebService接口
- 定时同步基础数据
- 双系统患者ID映射
我在实际开发中遇到最棘手的问题是Redis缓存穿透。当查询不存在的排班ID时,会导致大量请求直接打到数据库。最终通过布隆过滤器+空值缓存解决了这个问题。具体实现是在查询前先用布隆过滤器判断排班ID是否存在,如果不存在直接返回;对于确实不存在的ID,也在Redis设置一个短暂的空值标记。
