1. 项目背景与需求分析
医院挂号系统作为医疗信息化建设的基础环节,其效率直接影响着患者的就医体验。传统挂号方式存在几个典型痛点:患者需要提前到医院排队,高峰期等待时间可能超过2小时;号源信息不透明导致"黄牛"倒号现象;人工登记效率低下且易出错。我们开发的这套系统正是为了解决这些实际问题。
从技术层面看,系统需要满足三方面核心需求:
- 高并发处理能力:三甲医院日门诊量通常在5000-10000人次,挂号时段集中产生巨大流量
- 数据强一致性:同一号源在同一时刻只能被一个患者成功预约
- 系统高可用性:医疗系统故障会直接影响患者就诊,全年停机时间需控制在5分钟以内
2. 技术架构设计
2.1 整体架构方案
采用前后端分离的微服务架构,主要基于以下考虑:
- 前端使用Vue.js + ElementUI实现响应式布局,适配PC、平板和手机多种终端
- 后端采用SpringBoot 2.7 + MyBatis-Plus框架组合
- 数据库使用MySQL 8.0集群部署,配合Redis缓存提升查询性能
- 通过Nginx实现负载均衡和静态资源加速
2.2 关键技术选型解析
SpringBoot的优势体现:
- 自动配置机制大幅简化了SSM框架整合过程
- 内置Tomcat容器支持快速部署
- Actuator端点提供系统健康监控
- 与Spring Security天然集成实现权限控制
Vue.js的实践价值:
- 组件化开发使界面模块复用率提升60%
- Vuex状态管理解决跨组件数据共享问题
- Axios拦截器统一处理HTTP请求和响应
- 动态路由配合导航守卫实现权限过滤
3. 数据库详细设计
3.1 核心表结构优化
患者表(patient)的字段设计技巧:
sql复制CREATE TABLE `patient` (
`patient_id` BIGINT NOT NULL COMMENT '雪花算法生成ID',
`id_card` VARCHAR(18) NOT NULL COMMENT '身份证号加密存储',
`phone` VARCHAR(20) NOT NULL COMMENT '手机号需验证',
`real_name` VARCHAR(50) NOT NULL COMMENT '姓名脱敏显示',
`gender` CHAR(1) NOT NULL COMMENT 'M-男 F-女',
`birth_date` DATE COMMENT '用于年龄计算',
`allergy_history` TEXT COMMENT '过敏史文本',
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
`update_time` DATETIME ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`patient_id`),
UNIQUE KEY `uk_idcard` (`id_card`),
KEY `idx_phone` (`phone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
医生排班表(schedule)的关键设计:
- 采用分表策略:按科室ID哈希分片存储
- 设置最大接诊数阈值防止超负荷
- 使用复合索引提升查询效率:
sql复制ALTER TABLE `schedule` ADD INDEX `idx_dept_date` (`department_id`, `work_date`);
3.2 事务处理方案
挂号业务涉及多表操作,采用分布式事务保证数据一致性:
java复制@Transactional(rollbackFor = Exception.class)
public RegistrationResult register(RegistrationDTO dto) {
// 1. 检查号源库存
Schedule schedule = scheduleMapper.selectForUpdate(dto.getScheduleId());
if (schedule.getRegistered() >= schedule.getMaxPatients()) {
throw new BusinessException("该时段号源已满");
}
// 2. 扣减号源
scheduleMapper.updateRegistered(schedule.getId(), 1);
// 3. 创建挂号记录
Registration registration = new Registration();
BeanUtils.copyProperties(dto, registration);
registration.setStatus(0); // 待就诊
registrationMapper.insert(registration);
// 4. 记录操作日志
operationLogService.logRegistration(dto.getPatientId(), schedule.getId());
return RegistrationResult.success(registration.getId());
}
4. 核心功能实现
4.1 号源库存管理
采用Redis+Lua脚本实现高并发下的号源扣减:
lua复制-- KEYS[1] 排班ID
-- ARGV[1] 最大接诊数
local remain = tonumber(redis.call('GET', KEYS[1]))
if remain and remain > 0 then
redis.call('DECR', KEYS[1])
return 1
else
return 0
end
Java调用示例:
java复制public boolean deductStock(Long scheduleId) {
String script = "lua脚本内容";
RedisScript<Long> redisScript = RedisScript.of(script, Long.class);
Long result = redisTemplate.execute(redisScript,
Collections.singletonList("schedule:" + scheduleId),
maxPatients);
return result == 1;
}
4.2 支付对接方案
系统支持多种支付方式接入:
- 微信支付:使用官方SDK对接JSAPI支付
- 支付宝:采用RSA2签名方式
- 医保对接:通过医保中间件实现实时结算
支付状态机设计:
code复制待支付 -> 支付成功 -> 已核销
↘ 支付失败
↘ 已超时
5. 安全防护措施
5.1 敏感数据保护
- 身份证号加密存储:
java复制public String encryptIdCard(String idCard) {
return AESUtil.encrypt(idCard, secretKey);
}
- 接口参数签名验证:
java复制@Around("@annotation(apiSecurity)")
public Object checkSign(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String sign = request.getHeader("X-SIGN");
// 验证签名逻辑...
}
5.2 权限控制体系
基于RBAC模型设计五类角色:
- 超级管理员:系统全局管理
- 科室管理员:管理本科室资源
- 医生:查看排班和患者信息
- 护士:执行分诊操作
- 患者:预约挂号权限
Spring Security配置示例:
java复制@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/doctor/**").hasAnyRole("DOCTOR", "ADMIN")
.antMatchers("/api/**").permitAll()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()));
}
6. 性能优化实践
6.1 缓存策略设计
采用多级缓存架构:
- 热点数据:Redis缓存号源余量
- 静态数据:Caffeine本地缓存科室信息
- 查询结果:MyBatis二级缓存
缓存更新策略:
java复制@CacheEvict(value = "schedules", key = "#schedule.departmentId")
public void updateSchedule(Schedule schedule) {
scheduleMapper.updateById(schedule);
}
6.2 数据库优化
- 索引优化:为高频查询字段建立组合索引
- SQL调优:避免全表扫描和使用临时表
- 连接池配置:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 20
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
7. 部署方案
7.1 容器化部署
Docker Compose编排示例:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
volumes:
- ./mysql/data:/var/lib/mysql
redis:
image: redis:6
ports:
- "6379:6379"
backend:
build: ./hospital-backend
ports:
- "8080:8080"
depends_on:
- mysql
- redis
7.2 监控方案
- Prometheus + Grafana监控体系
- ELK日志收集系统
- SkyWalking分布式追踪
关键监控指标:
- 接口响应时间P99 < 500ms
- 数据库连接池使用率 < 80%
- JVM内存使用率 < 70%
8. 典型问题解决方案
8.1 超卖问题处理
采用分布式锁保证库存准确性:
java复制public boolean lockStock(Long scheduleId) {
String lockKey = "lock:schedule:" + scheduleId;
return redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
}
8.2 定时任务设计
每日凌晨自动生成排班:
java复制@Scheduled(cron = "0 0 2 * * ?")
public void generateSchedules() {
// 获取所有医生
List<Doctor> doctors = doctorMapper.selectList(null);
// 生成未来7天排班
LocalDate today = LocalDate.now();
for (int i = 1; i <= 7; i++) {
LocalDate date = today.plusDays(i);
doctors.forEach(doctor -> {
Schedule schedule = new Schedule();
// 排班信息设置...
scheduleMapper.insert(schedule);
});
}
}
9. 扩展功能设计
9.1 智能分诊系统
基于症状关键词匹配科室:
java复制public List<Department> matchDepartments(String symptoms) {
// 分词处理
List<String> keywords = textAnalyzer.analyze(symptoms);
// 查询匹配科室
return departmentMapper.selectByKeywords(keywords);
}
9.2 候诊队列管理
实时候诊队列实现方案:
- WebSocket推送队列变化
- Redis ZSET维护排队顺序
- 看板大屏展示当前叫号
10. 测试方案
10.1 压力测试指标
使用JMeter模拟测试场景:
- 1000并发用户挂号操作
- API响应时间 < 1秒
- 错误率 < 0.1%
- 系统吞吐量 > 800TPS
10.2 自动化测试
集成测试框架:
java复制@SpringBootTest
class RegistrationServiceTest {
@Autowired
private RegistrationService registrationService;
@Test
void testRegister() {
RegistrationDTO dto = new RegistrationDTO();
// 构造测试数据...
RegistrationResult result = registrationService.register(dto);
assertEquals(0, result.getCode());
}
}
11. 项目演进路线
- 第一阶段(1.0版):实现基础挂号功能
- 第二阶段(2.0版):接入医保支付
- 第三阶段(3.0版):增加互联网问诊模块
- 第四阶段(4.0版):对接智能硬件设备
在数据库连接池配置实践中,我们发现HikariCP的默认配置需要针对医疗场景特别优化。实际测试表明,将连接超时时间设置为30秒、空闲连接存活时间调整为10分钟时,系统在突发流量下表现最为稳定。这个经验来自我们处理某三甲医院早高峰挂号请求时的实际调优过程。