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

发布时间:2026/11/8 19:51:51

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系统查看检查结果医保对接与医保系统对接支持医保在线结算大数据分析分析就诊数据辅助医院管理决策在实际开发这个项目的过程中我深刻体会到医疗系统的严谨性和复杂性。每个功能点都需要考虑各种边界条件和异常情况比如医生临时停诊如何处理、预约超时未支付怎么回收号源等。这些细节的处理往往比核心功能的实现更耗费时间但也正是这些细节决定了一个系统的可靠性和用户体验。
延伸阅读

更多相关文章

2026/11/8 19:51:51

光模块:AI算力时代的物理层核心器件

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/6 19:18:18

YOLOv8模型改进实战:Backbone/Neck/Head优化与剪枝避坑指南

1. 这不是“YOLOv11”,但你必须先搞懂它才能真正改进模型先说一句大实话:目前官方并没有发布YOLOv11。Ultralytics官网最新稳定版本仍是YOLOv8,v9和v10均未正式开源(截至2024年中),所谓“YOLOv11”在主流学…

2026/11/8 15:32:04

制造业智能化转型:AI技术落地与挑战解析

1. 制造业智能化转型的时代背景过去五年间,全球制造业正经历一场由数据驱动的深刻变革。根据麦肯锡全球研究院报告,采用智能化技术的制造企业平均生产效率提升可达30%-50%,而我国东部沿海地区率先开启了这场转型浪潮。作为工业大省&#xff0…

2026/11/8 19:46:55

贵州兴义有办电工证多久拿证别怕考不过白交培训费

贵州兴义有办电工证多久拿证别怕考不过白交培训费 怕考不过白交培训费?别急,贵州兴义有办电工证的拿证时间其实比你想象的短,关键是找对方法和机构。 1. 贵州兴义有办电工证多久能拿证?培训时间要多久?…

2026/11/8 19:46:55

宝安去哪里可以考电工证 低学历也能考吗 在哪考最靠谱

宝安去哪里可以考电工证 低学历也能考吗 在哪考最靠谱 你是不是也在担心,自己学历不高,怕报不了名?其实, 宝安去哪里可以考电工证 这个问题,很多人都有类似的困扰。不过,别急,我来给你说说到底 在哪考…

2026/11/8 19:46:55

常州高压电工证年审良心建议:外省证怎么转过来

常州高压电工证年审良心建议:外省证怎么转过来 之前考的证在外省能不能转过来?这是很多在常州工作的高压电工最关心的问题。如果你也有类似困惑,那这篇 常州高压电工证年审良心建议 就给你讲清楚,别再被培训机构忽悠了。…

2026/11/8 19:41:55

越秀高级电工证多少钱?别再被中介坑了,看这篇就够了

越秀高级电工证多少钱?别再被中介坑了,看这篇就够了 你是不是正愁找不到靠谱的地方报名越秀高级电工证,担心被中介坑钱又拿不到证?别急,今天我就来告诉你怎么避坑,怎么考,还有这证到底值不值得你花这笔钱。…

2026/11/8 0:00:27

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/8 0:00:27

电工证丢失还能补吗?千万别踩坑,丢了证等于失业

电工证丢失还能补吗?千万别踩坑,丢了证等于失业 你正在找工作,但手里的电工证突然丢了,这下怎么办?别急,先别慌, 电工证丢失还能补吗 ?答案是肯定的,但 千万别踩坑 ,补办流程如果不了解,可能会耽误你上岗、甚至影响到你的收入。…

2026/11/7 14:54:47

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/7 14:50:12

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑