ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringBoot+微信小程序医院预约挂号系统开发实践

SpringBoot+微信小程序医院预约挂号系统开发实践 1. 项目概述作为一名有10年开发经验的Java全栈工程师我最近完成了一个基于SpringBoot微信小程序的医院预约挂号系统。这个项目不仅适合作为计算机相关专业的毕业设计选题也完全可以作为实际医院门诊系统的原型进行二次开发。这个系统采用了当前主流的B/S架构前端使用微信小程序Vue.js实现移动端应用后端基于SpringBoot框架开发数据库选用MySQL。系统实现了完整的预约挂号流程包括用户注册登录、医生排班管理、号源管理、预约挂号、订单支付、就诊记录查询等功能模块。在实际开发过程中我遇到了不少技术难点比如微信小程序与后端API的对接、高并发场景下的号源锁定机制、分布式事务处理等。通过这个项目我积累了很多宝贵的实战经验下面就来详细分享这个系统的设计与实现过程。2. 系统架构设计2.1 技术栈选型在项目启动阶段我经过多方比较最终确定了以下技术栈后端技术栈Spring Boot 2.7.x简化配置快速构建微服务Spring Security认证与授权管理MyBatis-Plus简化数据库操作Redis缓存热点数据提高系统响应速度RabbitMQ异步处理预约消息削峰填谷前端技术栈微信小程序原生开发适配移动端Vue.js 3.x管理后台前端框架Element PlusUI组件库数据库MySQL 8.0关系型数据库Redis 6.x缓存数据库选择这些技术主要基于以下几点考虑Spring Boot生态成熟社区支持好遇到问题容易找到解决方案微信小程序用户基数大无需安装使用方便Vue.jsElement Plus组合开发管理后台效率高MySQLRedis的组合可以满足大部分医院场景的数据存储需求2.2 系统架构设计系统采用典型的分层架构设计┌───────────────────────────────────────┐ │ 微信小程序客户端 │ └───────────────────────────────────────┘ ▲ │ HTTP/HTTPS ▼ ┌───────────────────────────────────────┐ │ API Gateway │ │ (路由、限流、认证、日志、监控等) │ └───────────────────────────────────────┘ ▲ │ ▼ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 用户服务 │ │ 预约服务 │ │ 支付服务 │ └─────────────┘ └─────────────┘ └─────────────┘ ▲ ▲ ▲ │ │ │ ▼ ▼ ▼ ┌───────────────────────────────────────┐ │ MySQL集群 │ └───────────────────────────────────────┘ ▲ ▲ ▲ │ │ │ ▼ ▼ ▼ ┌───────────────────────────────────────┐ │ Redis集群 │ └───────────────────────────────────────┘这种架构设计具有以下优势前后端完全分离便于独立开发和部署微服务架构各服务职责单一便于扩展引入API网关统一处理跨域、认证、限流等问题数据库读写分离提高系统吞吐量3. 核心功能模块实现3.1 用户认证模块用户认证是系统的第一个门槛我采用了JWT(JSON Web Token) 微信小程序登录的方案// 微信小程序登录接口示例 PostMapping(/wxLogin) public Result wxLogin(RequestBody WxLoginDTO dto) { // 1. 调用微信接口获取openid String openid wxService.getOpenid(dto.getCode()); // 2. 查询或创建用户 User user userService.findOrCreateByOpenid(openid); // 3. 生成JWT token String token JwtUtil.generateToken(user.getId(), user.getRole()); // 4. 返回token和用户基本信息 return Result.success(new LoginVO(token, user)); }关键点说明微信小程序前端调用wx.login()获取临时code后端用code向微信服务器换取openid根据openid查询用户不存在则自动注册使用JWT生成token返回给客户端安全考虑token设置合理过期时间(如2小时)敏感接口需要校验token和用户角色记录登录日志防范恶意请求3.2 号源管理模块号源管理是系统的核心功能需要考虑医生排班、号源生成、号源状态变更等场景// 生成未来7天的号源 Scheduled(cron 0 0 0 * * ?) // 每天凌晨执行 public void generateSchedule() { // 1. 获取所有医生 ListDoctor doctors doctorMapper.selectList(null); // 2. 为每个医生生成未来7天的排班 for (Doctor doctor : doctors) { for (int i 1; i 7; i) { LocalDate date LocalDate.now().plusDays(i); // 3. 检查是否是医生的休息日 if (!doctor.getWorkDays().contains(date.getDayOfWeek().getValue())) { continue; } // 4. 生成上午和下午的号源 generateTimeSlot(doctor, date, 08:00-12:00, 30); generateTimeSlot(doctor, date, 14:00-18:00, 30); } } } private void generateTimeSlot(Doctor doctor, LocalDate date, String period, int total) { Schedule schedule new Schedule(); schedule.setDoctorId(doctor.getId()); schedule.setWorkDate(date); schedule.setWorkPeriod(period); schedule.setTotalNumber(total); schedule.setAvailableNumber(total); scheduleMapper.insert(schedule); }关键业务逻辑使用定时任务每天自动生成未来7天的号源考虑医生的工作日设置(如每周三休息)每个时段(上午/下午)设置合理的号源数量支持手动调整号源(如临时停诊)3.3 预约挂号模块预约挂号需要考虑高并发场景下的数据一致性问题我采用了Redis分布式锁乐观锁的方案Transactional public Result makeAppointment(AppointmentDTO dto) { // 1. 获取分布式锁 String lockKey lock:schedule: dto.getScheduleId(); boolean locked redisTemplate.opsForValue() .setIfAbsent(lockKey, 1, 10, TimeUnit.SECONDS); if (!locked) { return Result.fail(当前号源紧张请稍后再试); } try { // 2. 查询号源信息 Schedule schedule scheduleMapper.selectById(dto.getScheduleId()); if (schedule null || schedule.getAvailableNumber() 0) { return Result.fail(号源已约满); } // 3. 使用乐观锁更新号源 int updated scheduleMapper.decreaseAvailableNumber( dto.getScheduleId(), schedule.getVersion()); if (updated 0) { return Result.fail(号源已被其他用户预约); } // 4. 创建预约记录 Appointment appointment new Appointment(); // 设置预约信息... appointmentMapper.insert(appointment); // 5. 发送MQ消息异步处理后续流程 rabbitTemplate.convertAndSend( appointment.exchange, appointment.create, appointment.getId()); return Result.success(预约成功); } finally { // 释放锁 redisTemplate.delete(lockKey); } }并发控制策略使用Redis分布式锁防止超卖数据库乐观锁确保数据一致性异步处理非核心流程(如发送通知)合理设置锁的超时时间避免死锁4. 数据库设计4.1 主要表结构用户表(user)CREATE TABLE user ( id bigint NOT NULL AUTO_INCREMENT, openid varchar(64) DEFAULT NULL COMMENT 微信openid, username varchar(32) NOT NULL COMMENT 用户名, password varchar(64) DEFAULT NULL COMMENT 密码, phone varchar(11) DEFAULT NULL COMMENT 手机号, avatar varchar(255) DEFAULT NULL COMMENT 头像, gender tinyint DEFAULT 0 COMMENT 性别(0未知 1男 2女), birthday date DEFAULT NULL COMMENT 生日, status tinyint DEFAULT 1 COMMENT 状态(0禁用 1正常), create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY idx_openid (openid), UNIQUE KEY idx_phone (phone) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT用户表;医生表(doctor)CREATE TABLE doctor ( id bigint NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL COMMENT 医生姓名, title varchar(32) DEFAULT NULL COMMENT 职称, department_id bigint NOT NULL COMMENT 科室ID, specialty varchar(255) DEFAULT NULL COMMENT 专长, introduction text COMMENT 简介, photo varchar(255) DEFAULT NULL COMMENT 照片, work_days varchar(32) DEFAULT 1,2,3,4,5 COMMENT 工作日(1-7), status tinyint DEFAULT 1 COMMENT 状态(0停诊 1正常), create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY idx_department (department_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT医生表;排班表(schedule)CREATE TABLE schedule ( id bigint NOT NULL AUTO_INCREMENT, doctor_id bigint NOT NULL COMMENT 医生ID, work_date date NOT NULL COMMENT 出诊日期, work_period varchar(20) NOT NULL COMMENT 时段(上午/下午), total_number int NOT NULL COMMENT 总号源数, available_number int NOT NULL COMMENT 可用号源数, version int NOT NULL DEFAULT 0 COMMENT 乐观锁版本号, create_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, update_time datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_doctor_date_period (doctor_id,work_date,work_period), KEY idx_work_date (work_date) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT排班表;4.2 索引优化为了提高查询性能我在以下字段上创建了索引用户表的openid和phone字段 - 用于快速查找用户医生表的department_id字段 - 用于按科室筛选医生排班表的(doctor_id, work_date, work_period)组合唯一索引 - 防止重复排班排班表的work_date字段 - 用于按日期查询排班5. 系统部署与性能优化5.1 部署架构生产环境建议采用以下部署方案┌─────────────────┐ ┌─────────────────┐ │ Nginx LB │ │ Nginx LB │ └────────┬────────┘ └────────┬────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ API Gateway │ │ API Gateway │ └────────┬────────┘ └────────┬────────┘ │ │ ▼ ▼ ┌─────────────────┐ ┌─────────────────┐ │ 用户服务 │ │ 预约服务 │ └────────┬────────┘ └────────┬────────┘ │ │ ▼ ▼ ┌───────────────────────────────────────┐ │ MySQL集群 │ │ (主从复制读写分离) │ └───────────────────────────────────────┘ ▲ │ ▼ ┌───────────────────────────────────────┐ │ Redis集群 │ │ (哨兵模式自动故障转移) │ └───────────────────────────────────────┘5.2 性能优化措施缓存策略使用Redis缓存热点数据(如医生信息、科室信息)实现多级缓存本地缓存(Caffeine) 分布式缓存(Redis)合理设置缓存过期时间避免脏数据数据库优化主从分离读多写少的场景使用从库对大表进行分表(如按月份分表存储预约记录)合理使用索引避免全表扫描接口优化使用Hystrix实现服务熔断降级对耗时的操作(如生成报表)异步处理接口限流防止恶意请求前端优化小程序使用分包加载图片等静态资源使用CDN加速合理使用本地存储减少网络请求6. 常见问题与解决方案6.1 微信小程序登录失败问题现象调用wx.login获取code后后端无法换取openid排查步骤检查小程序appid和secret是否正确确认小程序后台配置的服务器域名包含当前域名检查微信接口返回的错误信息解决方案// 正确的微信接口调用示例 public String getOpenid(String code) throws WxErrorException { WxMaService wxService WxMaConfiguration.getWxMaService(); WxMaJscode2SessionResult session wxService.getUserService() .getSessionInfo(code); return session.getOpenid(); }6.2 预约超卖问题问题现象同一号源被多个用户同时预约成功原因分析高并发场景下多个请求同时通过库存检查解决方案使用分布式锁控制并发数据库使用乐观锁前端限制频繁点击// 使用Redis分布式锁数据库乐观锁 public boolean lockSchedule(Long scheduleId) { String key lock:schedule: scheduleId; return redisTemplate.opsForValue() .setIfAbsent(key, 1, 10, TimeUnit.SECONDS); } public int decreaseAvailableWithVersion(Long scheduleId, int version) { return scheduleMapper.decreaseAvailableNumber(scheduleId, version); }6.3 定时任务重复执行问题现象集群环境下定时任务在多台服务器上重复执行解决方案使用Redis分布式锁控制任务执行Scheduled(cron 0 0 0 * * ?) public void generateScheduleTask() { String lockKey task:generateSchedule; boolean locked redisTemplate.opsForValue() .setIfAbsent(lockKey, 1, 5, TimeUnit.MINUTES); if (!locked) { return; } try { generateSchedule(); } finally { redisTemplate.delete(lockKey); } }7. 项目扩展方向这个基础版本完成后还可以考虑以下扩展方向智能推荐基于用户历史就诊记录推荐相关科室和医生在线问诊集成即时通讯功能支持图文问诊检查报告对接医院LIS/PACS系统查看检查结果医保对接与医保系统对接支持医保在线结算大数据分析分析就诊数据辅助医院管理决策在实际开发这个项目的过程中我深刻体会到医疗系统的严谨性和复杂性。每个功能点都需要考虑各种边界条件和异常情况比如医生临时停诊如何处理、预约超时未支付怎么回收号源等。这些细节的处理往往比核心功能的实现更耗费时间但也正是这些细节决定了一个系统的可靠性和用户体验。
返回列表