ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

医院预约挂号系统毕设:Spring Boot与微信小程序的号源并发设计

医院预约挂号系统毕设:Spring Boot与微信小程序的号源并发设计 1. 医院预约挂号系统毕设题目背后真正要解决的问题1.1 为什么这个题目每年都有人选却每年都有人做砸医院预约挂号系统几乎每个计算机专业的毕业设计选题列表里都有。原因很简单技术上不超前但麻雀虽小五脏俱全Spring Boot 微信小程序这一组合既能体现后端功底又能展示完整的移动端业务闭环。可正因为人人都能做答辩时就特别容易拉不开差距。我带过的学生里最常见的翻车方式是把预约挂号做成了课程表——选个科室、选个医生、点一下预约后台能查到订单然后就没了。答辩老师问一句两个用户同时抢最后一个号源怎么办当场卡壳。为什么卡壳因为很多人在做这个项目时根本没有把预约当成一个真实的业务去看待而是当成一个 CRUD 练习。要真正把这个题目做扎实首先得清楚它到底在解决什么问题。去医院挂过号的人都知道传统模式的痛点集中在三处清晨窗口排长队、到了医院发现专家号已经放完、医生临时停诊却没人通知患者。线上预约挂号系统的价值就是把这三点拆掉患者通过微信小程序提前选择科室、医生和时段号源以排班表形式投放预约成功后通过订阅消息通知结果医生停诊则通过后台取消并释放号源。这个题目适合三类人第一类是后端基础一般、但想通过一个完整项目补齐 Spring Boot 实战经验的同学第二类是已经会写增删改查、但对并发状态机接口设计没有系统认知的同学第三类是纯粹想要一个能顺利通过答辩、文档代码都能拿得出手的稳妥方案的人。无论哪类我都会建议你先想清楚业务再动手写代码这也是本篇接下来要展开的核心。1.2 一个合格的毕设业务闭环应该做到什么程度毕业设计不是商业项目但也不能只是个 Demo。我的判断标准很简单用户端能走完登录 - 绑就诊人 - 选科室 - 选医生 - 选时段 - 支付/确认 - 查看预约记录 - 取消预约这条完整链路医院端能走完排班管理 - 号源投放 - 预约确认 - 就诊完成这条管理链路系统就算立住了。很多同学会把重心放在页面好看、按钮多上我觉得这是本末倒置。医院预约挂号系统的核心资产是号源数据而不是界面。你有没有想过一个医生上午的号源投放了 30 个第 30 个人预约成功之后第 31 个人应该看到什么现实中的答案是上午号已满请选择其他时段。这个行为背后是号源池的消耗逻辑不是简单的已约人数 1。另外还需要注意预约与支付的时序问题。真正的医院系统里挂号费支付和号源锁定往往不是同一个动作。用户点了预约但没付款号源要不要锁如果锁了多久释放如果不锁用户付款时号源被抢走了怎么办毕业设计不要求你做出黑产级别的风控但至少在论文里要把这个逻辑讲清楚——我建议采用先锁定后支付、超时释放的方案这在第四章会详细展开。2. 从号源池到预约单核心业务链路拆解2.1 一个完整预约流程里涉及了多少个业务对象先从用户视角走一遍完整流程。用户打开小程序第一眼看到的是医院首页和科室入口。点击某个科室后进入医生列表医生列表的每条记录上会展示医生姓名、职称、擅长领域以及近期排班信息。选中医师后进入排班页这里会按日期列出号源时段每个时段显示剩余号量用户选定时段确认就诊人提交预约系统生成预约单同时扣减号源。这个流程听起来不复杂但涉及数据表之间的关联远超想象。我一般会把核心业务对象拆成六个维度用户微信用户、就诊人患者信息、科室、医生、排班医生在某天的出诊计划、号源时段某排班下的具体可约间隙、预约单。如果还要接入支付那就有订单和支付流水两个额外对象。很多新手最常犯的错是让预约单和排班直接耦合排班表里写死已约了多少人预约单删掉就改回数字。这样当然也能跑但一旦出现医生停诊换号用户爽约号源释放这些场景代码会变得非常绕。正确做法是把号源池作为独立概念让排班只描述某医生某天出诊让号源时段表来描述具体几点到几点的号还能不能约预约单则关联到号源时段上。2.2 号源池、排班规则和状态机设计排班规则是这一节的重点。过去很多毕业设计用一张 schedule 表就解决了排班字段包含 doctor_id、work_date、start_time、end_time、total_slots、booked_slots。这种做法不是不能用但它把一个最核心的并发热点裸露在了所有预约操作面前——所有人都在写同一行记录。我更建议把它拆成两层。第一层是排班表doctor_schedule记录某医生某天是否出诊、上午还是下午、总号源数第二层是号源时段表schedule_slot往细里拆成具体时间段比如 8:00-8:30、8:30-9:00每条时段记录自己的总额度和已占额度。用户预约时锁的是 schedule_slot 这条记录而不是整张排班。这样做的好处是并发粒度变细了医院也更接近真实业务——因为现实里一个医生上午并不是一个连续大号段而是按 5 到 10 分钟一个号段来的。预约单的状态机是另一个值得花时间设计的地方。很多人只设计了已预约/已取消两个状态可一旦加上支付和爽约场景就不够用了。我建议至少包含五个状态待支付、已预约、已完成、已取消、已过期。状态断言要写在 Service 层而不是让前端传什么就改成什么。比如只有待支付或已预约状态的预约单才允许取消已完成和已过期不能取消已取消不能重复取消。这一套状态约束写下来你会发现不仅代码稳了论文里画状态图也有内容了。2.3 取消预约和停诊换号号源如何安全释放取消预约看起来只是改一个状态实际上是对号源的归还操作。一个用户在就诊前一天取消了一个 9:00-9:30 的号这个号源应该重新回到号源池让其他用户可以看到并预约。如果只是把预约单状态改成已取消而号源时段表的已占额度没减回去就会造成号源凭空蒸发。归还号源时还有一个边界情况很多人没注意到如果预约已经处于已完成状态或者已经过了就诊时间前端应该直接禁止取消操作按钮如果允许后端接到了取消请求Service 层也要先校验当前时间与就诊时间的关系。比如就诊开始前 2 小时允许自助取消之后只能现场取消这条规则不一定要做得很深但至少要有否则答辩老师会揪着问你患者前一天 23:59 取消第二天 8:00 的号放出来还有谁来得及挂——这种问题非常现实。停诊换号就更复杂了属于医院端的操作。医生临时停诊后系统需要把该医生某天所有未使用的号源时段全部释放同时给已预约的患者发送停诊通知。这里我建议不要直接物理删除排班数据而是给排班加状态字段正常/停诊/已结束预约单对应加一个停诊取消的流转路径这样能保留审计记录论文的测试章节也能多写一个用例。3. Spring Boot的核心实现号源扣减、微信登录与接口规范3.1 数据库表设计的关键细节Spring Boot 项目的数据持久层新手基本都会选 MyBatis-Plus我也不例外。但表结构设计这个环节很多人会偷懒直接按页面字段反推。我把核心表结构梳理成下面这样值得抄作业表名关键字段说明userid, openid, nickname, avatar, phone, create_time微信用户表登录后自动创建patientid, user_id, name, id_card, phone, relation就诊人表一个用户可绑定多个departmentid, name, intro科室表doctorid, department_id, name, title, intro医生表doctor_scheduleid, doctor_id, work_date, period_type, total_slots排班表总号源数schedule_slotid, schedule_id, start_time, end_time, booked_slots, version号源时段表version 用于乐观锁appointmentid, appointment_no, user_id, patient_id, doctor_id, schedule_slot_id, status, appointment_date, period预约主表有两个细节我会反复提醒。第一所有业务表都要带 create_time 和 update_time最好用 MyBatis-Plus 的自动填充注解统一处理答辩时老师看到规范的时间字段会很加分。第二预约单需要生成唯一业务编号不要直接用数据库自增 id建议用业务前缀 日期 随机数的方式比如 APPOINT 20250108 001234这样演示时能看到有意义的编号也方便后续接入消息推送时做关联。3.2 号源扣减乐观锁方案与 Redis 方案的取舍这是整个系统技术含量最高、答辩时最容易被追问的地方。前面说过最笨的做法是直接 update schedule_slot set booked_slots booked_slots 1 where id ?。这个 SQL 在单条连接下没问题但并发时会出现两个事务都读到剩余 1 个号各自加 1最终都提示成功的经典超卖问题。我的方案是乐观锁扣减。在 schedule_slot 表里加一个 version 字段每次扣减时执行update schedule_slot set booked_slots booked_slots 1, version version 1 where id #{slotId} and version #{version}执行后检查影响行数。如果返回 1说明当前没有其他请求抢先修改预约成功如果返回 0说明版本号已被别人改过号源已经被抢占直接返回号源已满。这个方法不需要引入 Redis代码逻辑也简单做毕设完全够用。Redis 预减号源方案不是不能用它适合高并发场景——先把剩余号量放到 Redis用 decr 命令原子扣减扣到负数就拒绝。但随之而来的问题是 Redis 和 MySQL 的最终一致性。你扣了 Redis 之后异步同步到 MySQL 的过程中服务重启了或者用户支付成功后异步订单丢了都会让两边数据不一致。答辩老师只要顺着这个点深挖很多同学就会露馅。所以我的结论是毕业设计用乐观锁打底就够Redis 可以作为加分项在论文系统优化章节里提出但不要在答辩现场强行演示——除非你有把握把一致性讲明白。3.3 微信登录与手机号授权的现状现在做微信小程序登录逻辑跟几年前差别很大。以前一个 wx.getUserInfo 就能拿昵称头像现在头像昵称填写能力已经回收真正唯一可靠的是 wx.login 拿到的 code后端用 code 去微信的 jscode2session 接口换回 openid 和 session_key。openid 作为用户在这个小程序下的唯一标识落到 user 表里去关联业务数据。手机号授权是另一个容易被误导的地方。很多同学还在搜微信开放平台有 API 能拿到微信授权后的用户手机号码吗答案是有能力调但不是前端直接拿。现在的手机号快速验证组件前端用 getPhoneNumber 拿到一个 code后端拿 code 再调微信接口换取真实手机号而且前提是小程序主体必须是企业/组织类型个人主体很多权限都开不了。这对毕设来说是个现实门槛。我的建议是不要死磕真实手机号验证在小程序端做手动输入手机号 短信验证码mock 输出到控制台的流程就够了。论文里注释一句生产环境可接入微信手机号快速验证组件反而显得你懂行。3.4 后端接口规范与统一响应预约挂号系统涉及的接口不少但如果每写一个接口就随手 return 一个 Map后面小程序端接入时就会非常痛苦。我建议从头就统一三层结构Result 对象code业务状态码、message、data全局异常处理RestControllerAdvice 捕获业务异常统一封装返回拦截器统一校验 token核心接口我列一下接口方法作用/api/auth/loginPOST小程序 code 换登录态 token/api/departmentsGET获取科室列表/api/doctorsGET按科室获取医生列表/api/schedulesGET按医生加日期获取排班与号源/api/appointmentsPOST创建预约锁定号源/api/appointments/{id}/cancelPOST取消预约释放号源/api/appointments/listGET查询我的预约记录接口返回要统一时间格式我踩过坑所以特别敏感后端 LocalDateTime 默认序列化出来是 2025-01-08T10:30:00 这种带 T 的 ISO 格式小程序端 new Date 解析时在部分 Android 机型上会直接变 NaN。我在统一配置里加了 Jackson 格式化输出 yyyy-MM-dd HH:mm:ss前端只做展示不解析省掉一整天调试时间。4. 微信小程序端页面流转、登录态与交互细节4.1 原生小程序结构设计与页面栈控制小程序端选型我的建议是别想太多直接用原生微信小程序除非学校有跨端要求。原生开发工具链成熟、文档齐全、真机调试快毕设时间本来就不宽裕不要为了炫技引入 uniapp 再加一层编译调试成本。页面结构我建议这样划分首页index负责医院介绍和功能入口科室页department展示科室列表医生页doctor展示医生的排班概况排班页schedule展示某医生某天的号源时段确认页confirm选择就诊人并提交预约记录页appointments展示我的预约列表个人中心profile管理就诊人和登录状态。页面层级有一个非常实际的坑小程序页面栈最多只能堆十层。如果你让用户从首页一路走到确认页层级其实只有四五层但加上科室 - 医生 - 排班 - 详情 - 确认这种链条再来回跳几次就容易超出限制。我的做法是预约流程这条主链路上的页面尽量平铺符合条件时用 wx.navigateBack 而不是继续 navigateTo让用户能原路返回而不是无限下钻。4.2 登录态管理静默登录而不是弹窗轰炸很多毕设小程序一到首页就弹授权登录框这种交互既烦人又容易被微信审核打回。正确做法是静默登录页面 onLoad 时先检查本地 storage 里有没有 token没有就调 wx.login 拿 code发给后端换 token拿到后存起来。整个过程中用户无感知直到需要绑就诊人或提交预约时如果 token 失效才提示重新登录。请求层我习惯在 utils/request.js 里封装 wx.request统一带上 header token响应后统一解析 Result 结构。这里有个细节如果后端返回 code 表示 token 过期应该清掉本地 token 并重新 wx.login然后自动把刚才失败的请求重放一遍。这个重放逻辑看起来高大上但写起来非常简单——队列里存住回调重新登录成功后逐个执行。这个小功能在答辩演示时几乎遇不到但若老师要看代码能成为亮点。4.3 排班号的交互呈现置灰、防重复与本地状态排班页是整个小程序交互最关键的地方。每个号源时段是一个小格子大概像宫格布局显示8:00-8:30和剩余 3 号剩余量 0 的格子要置灰禁止点击。点击格子后格子进入选中态用户点击确认预约跳到确认页。这里有个很实用的小技巧不要在用户点击确认预约后才向后端做余额校验应该在进入排班页时就把号源时段数据取回来前端用实时的剩余量渲染。同时前端要做一个防重复提交提交按钮点击后立即进入 loading 状态并禁用避免弱网条件下用户连点两次产生重复预约。虽然后端乐观锁能兜底但前端挡一道用户体验会好很多。4.4 订阅消息与支付旧模板消息已下线别再走弯路预约成功后给用户发微信通知用的不是以前那个模板消息老接口早就下线了。现在要用订阅消息小程序端先调用 wx.requestSubscribeMessage让用户授权一次后端在订单确认后通过 access_token 调接口推送。要注意一次性订阅消息的特性授权一次只能推一次所以最合理的时机是用户点提交预约之前就先请求订阅授权这样预约成功后的通知才能发出。支付方面我的建议是区分开发环境和论文描述。真实微信支付需要商户号个人主体开不了毕设阶段可以用一个 mock 开关后端配置 mockPaytrue 时创建预约后自动把订单置为已支付同时锁定号源论文里写生产环境可接入微信支付原生收银台附上 wx.requestPayment 的调用代码和预支付参数流程即可。千万不要为了这个再花时间去申请商户资质那是一个漫长的商务流程不是技术问题。5. 论文写作与答辩把程序变成能通过的毕设5.1 论文结构怎么排最不容易被导师拦项目做完了论文写不出来同样很难受。我的建议是论文结构跟着系统架构走不要按开发时间线写。标准顺序是绪论、相关技术介绍、需求分析、系统设计、系统实现、系统测试、总结展望。相关技术介绍这一章是水重灾区很多同学直接大段抄 Spring Boot 官方文档导师一眼就能看出来。正确写法是每项技术都点出为什么在这个项目里用它。比如 Spring Boot 因为简化配置、内嵌 Tomcat 所以部署方便微信小程序因为免安装、微信内直接打开所以患者使用门槛低MyBatis-Plus 因为代码生成器和条件构造器能减少大量样板代码。系统设计章节里要包含总体架构图、功能模块图、数据库 E-R 图和关键接口设计。这里提醒一句画图工具不重要但图与实现代码必须一致有些同学的图里画了短信服务模块代码里根本没有答辩时被指出来非常尴尬。宁可图少而准不要图多而虚。5.2 测试章节要有说服力模拟并发抢号的实测结果系统测试章节不能只写点击按钮功能正常。尤其是号源并发这个点一定要有测试数据支撑。我建议用 JMeter 或 Postman Runner 做一次简单的并发测试把某个号源时段的剩余号量设为 1然后一次发起 50 个并发预约请求最终断言预约成功的只有 1 条其余全部返回号源已满。把测试截图和结果数据放进论文效果会比任何文字都有说服力。我当时带学生做的时候测试结果通常是这样的50 个并发请求成功 1 条失败 49 条失败原因全部是号源已被抢约平均响应时间在 300ms 以内。这一页足以证明你不只是会写 CRUD还考虑了并发边界。5.3 答辩前要准备的追问弹药库答辩老师很少从头到尾看代码他们更习惯从项目里挑看起来像业务要害的地方问。医院预约挂号系统里高频追问基本集中在四个点号源并发怎么控制——用乐观锁 version 字段更新影响行数为 0 就返回已满。取消预约时号源怎么释放——在事务里更新预约单状态同时减少 schedule_slot 的 booked_slots。为什么用微信小程序而不用 App——小程序免安装、微信生态天然触达对不擅长下载 App 的中老年患者更友好。手机号怎么保证安全——后端对手机号做脱敏展示如 138****1234身份证号加密存储日志不打印敏感字段。这些回答一定要做到两句话能说清、细问能展开。训练方法就是对着镜子用大白话把整个预约流程从头讲一遍能讲顺了答辩就稳了。6. 踩坑复盘小程序审核、时区、部署与号源表的优先级6.1 上架不是必选项别在资质上浪费毕设时间很多同学做完项目就想上架微信小程序但我建议在动手申请之前先问自己学校要求的是上架还是演示如果是演示开发版/体验版完全够用。医院类小程序如果要正式发布通常需要提供医疗机构执业许可证等资质在校生基本没有。强行找第三方挂靠更是风险极高完全没有必要。好好利用微信开发者工具的体验版功能把体验版二维码发给答辩老师扫码老师手机微信里就能打开小程序这种演示效果一点也不差。6.2 时区、日期格式化与时间比较的坑我前面提过 LocalDateTime 序列化问题这里再补一个更隐蔽的坑如果后端部署的云服务器时区是 UTC而 MySQL 连接时区也是 UTC前端看到的预约时间可能比北京时间少了 8 小时。解决方式是在 JDBC 连接串里指定 serverTimezoneAsia/ShanghaiSpring Boot 配置文件里设置 jackson 的 time-zone 为 GMT8。一个小配置能省一个通宵。还有一个判断逻辑要注意取消预约的时限判断比如就诊前两小时可自助取消一定要用后端系统时间不能依赖前端传时间。因为前端时钟可以被用户本地设置影响而后端 ServerTime 才是可信的裁判。6.3 环境部署别在答辩现场等 Spring Boot 启动我最怕看到的情景是答辩时打开 IDEA等 Maven 下载依赖再等 Spring Boot 启动然后数据库连接失败。这不是技术问题是现场管理问题。答辩前至少提前两周准备好一套可独立运行的环境。最稳妥的方案是买一台最低配云服务器装上 MySQL、Redis把 Spring Boot 项目打成 jar 包丢上去跑小程序端把 request 域名指向服务器公网 IP开发环境不校验合法域名本地调试就用不校验合法域名选项。如果你想让论文多一个加分项可以用 Docker Compose 编排 MySQL、Redis 和后端服务一键 docker-compose up。运维痕迹不多但写进系统部署章节会很提气。6.4 最后的提醒宁可少做页面别把号源表做糊在做这个题目的所有环节里我见过最多的返工都出在同一个地方号源相关的表设计。用户表做简单了没关系科室表少两个字段也没关系唯独号源时段和预约单的关系必须一开始就想清楚。因为后面所有的并发控制、排班展示、取消释放、停诊处理全部压在这两张表的设计上。表设计一旦糊了后面整个 Service 层都要重写而且越改越乱。我个人的经验是花一个下午把预约生命周期画清楚——从选择号源到锁定从支付到确认从取消到释放从爽约到过期——再动手建表。这张图你后面写代码、写文档、准备答辩全都会用到是一笔稳赚不赔的时间投资。另一个实际体会是Spring Boot 项目本身的工程化习惯比功能更影响评分。统一的 Result 返回、全局异常处理、明确的业务异常码、分页查询、参数校验注解这些东西单看都是常规操作但它们集中出现时答辩老师对你的代码评价会上一整个台阶。医院预约挂号系统本身并不难真正拉开差距的是你有没有按一个真实业务系统的标准去要求自己。
返回列表