每年一到毕设季,"医院预约挂号系统"这种题目就会准时出现在各种选题清单里。今年我又接到了好几个朋友的咨询,都是同一句话:学长,这个基于 Spring Boot 和小程序的医院预约挂号系统到底怎么做才能顺利过审?说实话,这个题目确实是经典中的经典——业务场景贴近真实生活、需求逻辑清晰、前后端都能完整展示,工作量对本科生来说不大不小,刚好够一个毕设的体量。但正因为做的人多,导师和答辩老师对这类项目的期待值也水涨船高。我见过不少同学代码量堆得不少,页面画得也挺漂亮,但一问到"并发情况下号源超卖怎么处理""预约状态怎么流转""token过期怎么刷"就卡壳了。这套项目真正的价值不在于把页面跑起来,而在于把预约业务背后的数据模型、状态机、并发控制和接口设计讲清楚。
这篇文章不是给你一个"照着敲就能过"的代码仓库而已,而是把整个项目的开发链路拆开揉碎,从选题逻辑、技术选型、数据库设计、核心接口实现,到联调踩坑、毕设文档撰写、答辩准备,每一环我都会告诉你"为什么这么做"和"当时在这里犯了什么错"。我前前后后帮人调试过六七套这种预约挂号系统,也带过两个学生拿这个题目评优,下面这些内容基本覆盖了一个项目从零到答辩的全过程。不管你是打算自己从头写,还是拿到了别人的源码想做二次改造,只要沿着这套思路走,项目都不会做歪。
1. 项目定位与技术选型:为什么是 Spring Boot + 小程序
1.1 医院预约挂号系统的核心场景拆解
医院预约挂号这个需求听起来简单,就是"患者选医生、选时间、挂号",但把它拆开就会发现,一条完整业务链条远比想象中复杂。一个用户进入系统后要经历:浏览科室列表,查看某个科室下的医生信息,选择某个医生查看排班,选择某个号的时段,确认挂号,支付(或到院支付),到院签到就诊,就诊后评价。每一个环节都对应至少一张数据表和一组接口,整条链路串起来之后,系统才真正"完整"。
另外一个很容易被忽略的点是权限和角色。这类系统至少涉及三种角色:患者用户、医生、系统管理员。患者在小程序端完成注册登录和挂号;医生要能查看自己的排班和已预约患者;管理员在管理后台维护科室、医生、号源基础数据,还要看预约统计报表。很多同学做的版本只有用户端和管理后台,医生角色砍掉,直接在管理后台统一维护排班。这样做当然也能用,但答辩的时候很容易被老师追问"医生如何查看自己的患者名单",答不上来就很尴尬。所以我的建议是哪怕简化,也要保留一个医生端的只读查询入口,逻辑不复杂,但角色就完整了。
从毕设评分角度看,"角色划分清晰、业务流程闭环、异常情况有兜底"这三条是评审老师最在意的点。你不需要做一个功能多得吓人的系统,但做出来的每个模块都必须逻辑自洽,能让数据在各个环节里流转起来。比如用户取消预约后,号源要释放回可预约数量,这个细节如果遗漏了,老师演示时一测就能测出来,印象分直接扣掉。
1.2 后端选型:Spring Boot 的优势与版本建议
后端选 Spring Boot 基本上是绝大多数毕设的首选。原因很现实:一是生态成熟,网上资料丰富,遇到任何问题一搜就有答案,非常适合独立开发的学生;二是 Spring Boot 的自动配置机制让你不需要处理繁重的 XML 配置,一个启动类就能跑起来,学习和使用成本都低;三是就业市场上 Java 职位比例最高,用 Spring Boot 做毕设,后续写简历、面试聊项目也顺理成章。
版本选择上,我建议用 Spring Boot 2.7.x 配合 JDK 8 或 JDK 11。可能有的同学觉得非要用最新的 Spring Boot 3.x 才有面子,但实际工程里还要考虑 MyBatis、Druid 连接池、第三方工具类的兼容性,版本越新坑越多。3.x 里用的是 Jakarta EE 规范,包名从 javax 变成了 jakarta,有些老教程里的代码直接复制过来会编译报错,对不熟悉生态的新手很不友好。所以除非导师明确要求,否则我强烈推荐稳妥的 2.7.x,这也是目前无数毕设项目验证过最稳的组合。
持久层框架方面,MyBatis-Plus 是当前做毕设的主流选择,几乎没有之一。它几乎能覆盖你所有简单 CRUD 需求,单表操作不用写 SQL,Wrapper 条件构造器也非常直观,内置的分页插件更是省了不少事。复杂关联查询再用注解或 XML 写自定义 SQL,两种方式结合,开发的爽快感完全不一样。ORM 固然也有它的优势,但对于毕设这种中小规模项目,MyBatis-Plus 的灵活性和可控性更好,遇到问题也更容易定位。数据库就选 MySQL,开源免费、资料多、可视化工具如 Navicat 或 DataGrip 也都非常成熟。如果需要更省事,嵌入式数据库 H2 也可以用来做本地演示,但考虑到数据和复杂度,还是建议老老实实装一个 MySQL 8.0 或者 5.7。
1.3 前端选型:小程序的优势与局限
前端选微信小程序而不是 H5 网页或者 App,是考虑到几个因素。首先,小程序不需要用户下载安装,扫码或者搜索就能打开,更符合预约类工具的使用场景,也方便答辩时用手机或者开发者工具现场演示。其次,小程序的前端开发门槛相对低,WXML 和 WXSS 近似于 HTML 和 CSS 的用法,JavaScript 语法基本沿用,只要会写网页的人很快就能上手。最后,微信生态给小程序提供了现成的登录能力、支付能力和用户授权体系,省去了自己搞账号系统和支付集成的麻烦,这对毕设来说是非常大的简化。
不过小程序也有它自己的局限,最明显的就是接口请求时的域名限制。开发阶段你可以勾选开发者工具里的"不校验合法域名"来绕过问题,但一旦涉及真机预览,就需要后端接口配置 HTTPS 域名,或者使用内网穿透工具做临时调试。很多同学在开发环境跑得欢,一到真机演示就白屏,就是因为没处理这个域名校验问题。另一个局限是小程序的页面栈管理逻辑和传统 Web 路由不太一样,需要花一点时间理解 navigateTo、redirectTo、switchTab 这些 API 的使用场景,做预约流程时如果路由跳转顺序写错,就会出现返回按钮跳回首页之类的诡异问题。
那为什么不用 uni-app 或者原生 Vue + Web 端呢?我的观点是,如果已经有 Vue 基础,用 uni-app 开发小程序可以复用 Vue 语法,是一个不错的替代方案。但对于大多数只学过 JavaScript 基础、没系统接触过 Vue 的同学来说,原生小程序语法比 uni-app 少一层框架抽象,排查问题更直接,配套教程也更多。毕设的第一目标永远是"做出来、能跑、能讲清楚",所以从稳妥角度出发,原生小程序开发是性价比最高的选择。
1.4 系统角色与功能边界
明确了技术栈之后,下一步就是确定系统的功能边界。这步直接决定你后面要写多少代码、建多少张表。我见过一个同学把功能清单列了两页 A4 纸,结果做了两个月还没做完,最后草草交了一个半成品。功能边界不是越多越好,而是要和毕设工作量匹配。
按我的经验,一套标准的预约挂号系统功能可以划分为三个角色视角。
患者端(小程序)需要:注册与登录(微信授权手机号)、浏览科室与医生列表、查看医生详情与排班、预约挂号、取消预约、查看我的预约记录、查看就诊状态、发表评价。这是最核心的链路,缺一不可。
医生端(小程序或者简单 H5 页面)需要:查看本周排班、查看已预约患者列表、标记患者就诊状态(部分系统会做)。功能不用多,重点是角色存在。
管理端(Web 后台)需要:科室管理(增删改查)、医生管理(增删改查、关联科室)、排班管理(为医生添加出诊安排、设置号源总数)、预约记录管理、基本的仪表盘统计(今日预约量、各科室预约量曲线)。
再把高频的异常处理场景列出来:用户取消预约后号源回收、同一时段同一医生号源约满、未支付订单超时自动关闭、微信登录凭证过期。把这些场景在功能设计阶段就写清楚,后面写代码时不会跑偏,写论文时需求分析章节也有东西可写。
2. 数据库设计与接口约定:系统的地基怎么打
2.1 核心数据表与字段设计
数据库设计是这套系统的命根子,表建不好,后面全乱。我直接给出我觉得最精简又能覆盖完整业务链路的表结构方案,然后逐个解释关键字段的设计原因。
第一张是用户表,字段包括主键 id、手机号 phone、微信 openid、昵称 nickname、头像 avatar、创建时间 create_time。特别说一下 openid 和手机的取舍:用户首次登录时通过微信 code 换 openid,这是唯一且不可变的用户标识,应该建唯一索引。手机号作为选填信息,可以用于消息通知或者后续查询,但如果系统不做登录二次校验,手机号就不一定要强绑定。
第二张是科室表,字段为 id、科室名称 name、科室介绍 description、排序 sort。科室信息简单,但它是科室列表页、医生归属、管理端维护三者之间的纽带,所以务必在 ER 图上把关系画清楚。
第三张是医生表,字段包括 id、姓名 name、所属科室 department_id、职称 title、擅长领域 specialty、简介 intro、头像头像字段、状态 status。这里 department_id 是外键关联科室表,一对一的关系:一个医生只属于一个科室,一个科室下有多个医生。职称字段建议用统一枚举,如主任医师、副主任医师、主治医师、住院医师,方便列表按条件筛选。
第四张是排班表,这应该是整个系统里设计最关键的物理表了。核心字段包括 id、医生 doctor_id、出诊日期 work_date、时间段类型 shift_type、号源总数 total_number、剩余号源 remain_number、状态 status。shift_type 可以根据医院实际需求定义为上午和下午,也可以精确到具体时间点,比如 09:00-09:30 一个号段。号源字段需要用 int 表示数量,普通预约场景不需要为每一个号段单独建一张号位表,用"总数减去已约数"来计算剩余可约号数,简单高效。这也是后面做并发扣减时必须重点关注的字段。
第五张是预约记录表,就是整个系统的核心业务表。我一般设置字段为 id、预约单号 order_no、用户 user_id、排班 schedule_id、医生 doctor_id(冗余字段)、科室 department_id(冗余字段)、预约日期 order_date、预约时段 shift_type、状态 status、预约时间 create_time、就诊确认时间 confirm_time、取消时间 cancel_time。这里特意冗余了医生和科室 ID,是为了一次性联表查询时少关联两张表,提高列表页性能,在毕设这种中小数据量下收益非常明显。
第六张表是评价表,字段包括 id、预约记录 appointment_id、用户 user_id、医生 doctor_id、评分 score、内容 content、创建时间 create_time。评价和预约是一对一的关系,通过预约记录能确保只有真正就诊过的用户才能评价,防止刷评。
整套表设计就这六张核心表。也可以加一张管理员表,不过我通常建议直接在后端配置初始化一个 admin 账号,不需要单独建表,降低一些建表复杂度。数据库表之间的 ER 关系用大白话来说就是:科室一对多医生、医生一对多排班、排班一对多预约、用户一对多预约、预约一对一评价。
2.2 预约状态机设计:必须想清楚的业务核心
预约状态是答辩时一定会被问到的内容。我建议用整数类型来表示状态值,用一个字段维护整个生命周期,这样在代码里通过 switch 或者判断就行,数据库查询也高效。状态定义如下:
- 0:待支付。用户提交预约但还没有确认支付(如果系统不做线上支付,就直接进入待就诊状态)
- 1:已预约待就诊。支付完成或免支付情况下预约成功,等待就诊
- 2:已完成。医生确认患者已就诊,或者就诊日期已过且未取消
- 3:已取消。用户主动取消,或管理端取消
- 4:已过期。就诊日已过,但用户没有取消也没有就诊
状态流转的完整路径是:待支付 -> 已预约待就诊 -> 已完成;待支付或已预约待就诊 -> 已取消;已预约待就诊 -> 已过期。有了这个状态机,代码中每个修改状态的操作都能对照流程来写,不会出现"用户取消了一个已完成订单"这种逻辑漏洞。写论文的时候,把这幅状态流转图画出来,是需求分析章节里最大的亮点之一。
这里最重要的一个场景是:取消预约后要释放号源。如果用户在就诊前一天取消预约,那排班表的剩余号源要加一,否则这个号就永久浪费了。这个放号操作必须和取消预约的状态更新放在同一个事务里,这是逻辑闭环的关键。
2.3 接口设计与前后端约定
接口设计用 RESTful 风格,给毕设来说最合适。统一返回结构类 Result,包含 code、message、data 三个字段。code 为 0 表示成功,非 0 表示业务错误码,例如 401 表示未登录,500 表示系统异常。下面是我推荐的基础接口清单:
- POST /api/user/login 微信登录,入参为 code,后端调用微信接口换取 openid,返回自定义 token
- GET /api/department/list 获取科室列表
- GET /api/doctor/list 获取医生列表,支持按科室筛选
- GET /api/doctor/detail 获取医生详情
- GET /api/schedule/list 获取医生排班列表,支持按日期筛选
- POST /api/appointment/create 提交预约,入参为 scheduleId
- POST /api/appointment/cancel 取消预约,入参为 appointmentId
- GET /api/appointment/list 获取当前用户的预约记录列表
- POST /api/evaluation/create 提交评价
管理端接口不做详细展开,但基本模式就是增删改查 + 一个统计接口。
拦截器方面,建议写一个 LoginInterceptor,对非 /api/user/login 的接口统一校验 token 是否存在和是否过期。毕设阶段的 token 可以不用搞多精细的机制,存储用数据库表或者 Redis 都行,最简单的方案是生成一个 UUID 存入 Redis 并设置过期时间,请求时从 Header 的 token 字段获取,去 Redis 查一下有没有。在我调试过的项目里,内存 Map 存 token 也出现过,但服务一重启用户就掉线,体验很差。所以如果条件允许,还是建议引入 Redis,Spring Boot 集成 Redis 也非常快,仅仅几分钟的配置量。
小程序端所有请求都要带 Authorization 头,拦截器解析这个 Header 获取用户身份。这里有一个很多新手容易忘的细节:小程序 wx.request 里自定义 Header 的名字不要用带下划线的字段,有部分后端容器处理起来可能有问题,一般我们统一叫 Authorization,这正好也和 HTTP 规范的鉴权头名称一致。
3. 核心业务逻辑与关键实现:并发扣减与状态流转
3.1 排班生成的实现策略
排班模块是整个系统的数据源泉,没有排班,用户什么都约不了。排班生成的方式有几种,我推荐的管理员操作流程是这样的:管理员在管理端选择一个医生,选择出诊日期和时间段,填写当日号源总数,点击生成。后端服务收到请求后,检查该医生在同一个日期和时段是否已经有排班,如果存在就提示冲突,否则插入一条排班记录,初始状态为启用,剩余号源等于总数。
在实际项目中,我还见过按周批量生成排班的实现,就是一个星期排班循环生成七天,再按需临时停诊。这个功能做起来也不复杂,一个接口批量循环插入就好,但要注意事务范围和排重判断。如果老师在答辩时问"排班怎么保证医生一周不出诊两次",这就是展示你提前考虑过业务约束的好机会。
并发控制的核心在预约接口而不是排班接口,排班本身的冲突可以通过数据库唯一索引约束。这里有一个实战技巧:在排班表上建立 (doctor_id, work_date, shift_type) 唯一索引,数据库层面直接挡住同一医生同一时段重复排班的情况,比代码里的判断更可靠。
3.2 预约接口的并发扣减实现
预约接口是系统的技术核心,也是最容易在答辩时被老师追问的地方。"两个用户同时抢最后一个号,会不会超卖?"这个问题的标准答案值得你提前准备好。错误的实现方式是:先查剩余号源,判断是否大于零,然后执行 update 操作。两个请求同时查到剩余数为 1,一个执行扣减后剩余为 0,另一个也执行扣减,导致数据库里出现负数——这就是超卖。
正确的实现方式是使用乐观锁思想,把查询和扣减合并为一条原子 SQL:UPDATE schedule SET remain_number = remain_number - 1 WHERE id = ? AND remain_number > 0。这条 SQL 中条件 remain_number > 0 会约束数据库在并发情况下只让一个更新生效,受影响行数如果是 1 才说明扣减成功,是 0 则说明号源已被抢完。代码里判断这个返回值就能决定是返回"预约成功"还是"号源已约满"。这个是我强烈鼓励你在论文和答辩时拿出来讲的方案,因为它足够简单,同时思路完全正确。
扣减号源之后还要在同一事务里创建预约记录。把创建预约记录和扣减号源的逻辑放在一个 @Transactional 方法里,任何一个失败就整体回滚,不会出现"号源扣了但预约记录没生成"的数据不一致。注意 @Transactional 在同类内部方法调用时可能会失效,比如 Controller 调用 Service 的 A 方法,然后 A 方法内部调 this.b(),b 的事务注解就失效了,这一点文档里不容易查到,实际开发中要刻意避免。
3.3 微信登录与用户身份识别
小程序端的登录流程是 wx.login 获取临时 code,传输到后端,后端再用这个 code 调用微信官方接口换回 openid 和 session_key。这个流程不需要理解太深的微信开放平台原理,但你要能准确说出 code 是一次性的,有效期几分钟,后端拿到 openid 后去用户表查一下,如果已经存在就直接返回 token,不存在就自动注册一个新用户。另外 session_key 千万不要返回到前端,它是微信端用于解密手机号、获取敏感信息的凭证,不具备业务鉴权价值。
后端 token 我建议用 UUID 即可,不必在毕设里引入 JWT。UUID 方案就是一个随机字符串,存入 Redis 并设置过期时间,用户每次请求时在拦截器里校验。虽然 JWT 听起来更高大上,但涉及密钥管理、过期续期等一堆细节,对毕设来说反而增加了复杂度。答辩老师如果问"为什么不用 JWT",你可以说:项目做的是小程序场景,用户长期在线、需要频繁访问,JWT 的主动失效逻辑比较麻烦,而 Redis 管理 token 的方式实现简单、可控性强、退出登录直接删除 key 即可,更适合当前场景。这个回答既体现了你思考过,又站得住脚。
3.4 定时任务与过期订单处理
预约订单的过期处理是另一个容易被忽视的功能。场景是这样的:用户提交了预约,但是没有支付(或者系统走了免支付流程但用户一直没确认),号源一直被占用,其他人就看不到了。实际上在真实医院系统中,这种"锁号"行为只会在很短时间内被允许。所以在毕设中也要实现一个定时清理逻辑:使用 Spring 自带的 @Scheduled 注解,每五分钟扫描一次预约表,把处于待支付状态且创建时间超过十分钟的记录状态修改为已取消,同时把对应排班的剩余号源加回去。
写这段逻辑时有三个细节值得留意:状态条件过滤必须用 status=待支付 和 create_time < 当前时间减十分钟,不能只靠创建时间判断;释放号源时必须按主键定位排班,更新语句照旧加上剩余号源的处理;定时任务本身要加上 try-catch 防止单条异常影响整个扫描批次。在这类业务里,状态条件判断多一个字段,往往就能避免把已取消的订单再次置为失约,这种细节非常加分。
4. 开发实战:从搭建到联调的完整过程
4.1 后端项目搭建的关键步骤
我按实际开发流程走一遍,给还没动手的同学一个坐标参考。第一步是用 IDEA 新建 Spring Initializr 项目,选好 Maven、Java 8、Spring Boot 2.7.x,然后勾选 Spring Web、MyBatis Framework、MySQL Driver、Lombok。Lombok 在毕设里非常好用,@Data 注解直接生成 getter/setter,代码量明显减少,IDEA 装一下 Lombok 插件就行,这个前提很多人因为不知道而走了弯路。
依赖配置完成后,要把 application.yml 改好,核心配置包括数据库连接、端口、日志级别。尤其要注意时区参数:spring.datasource.url 里的 serverTimezone=Asia/Shanghai 必须加上,否则数据库连接时区对不上会直接报错。Redis 的连接配置也要一并写上,后面 token 存储就会用到。日志级别建议把 SQL 打印打开,在开发阶段能看到每条 SQL 语句和参数,排查数据问题时效率会高非常多。
代码分层结构我沿用行业标准的 Controller-Service-Mapper 三层。Controller 层只负责接收参数、调用 Service、返回统一 Result,所有业务逻辑都放 Service 层,Mapper 层(在 MyBatis-Plus 里是 BaseMapper 接口)只做数据访问。每张表对应一个实体类,用 @TableName 指定表名,用 @TableId 标注主键,字段名尽量保持和数据库列名一致,驼峰命名转下划线命名 MyBatis-Plus 会自动处理,这一点比原生 MyBatis 省心很多。
4.2 小程序端的页面与逻辑划分
小程序开发工具创建一个项目,AppID 用测试号就行,不影响开发。页面结构我建议这样划分:pages/index/index 是首页,可以放轮播图、通知栏、快捷入口;pages/dept/dept 是科室列表页;pages/doctor/doctor 是医生列表页;pages/doctorDetail/doctorDetail 是医生详情页;pages/schedule/schedule 是根据排班选择号源的页面;pages/order/order 是预约确认页;pages/orders/orders 是我的预约列表;pages/login/login 处理登录授权。这样一个预约流程下来,页面与页面之间的跳转逻辑非常顺,业务、交互与路由关系一目了然。
小程序端所有请求统一封装在一个 request.js 文件里,封装时要注意几点:请求前从 storage 里取 token 放入 Header;请求返回后先判断业务码,非零统一 toast 跳转到错误提示;网络错误要有统一的 loading 和提示。这套封装写一遍之后,所有页面都只用调用一行方法,体验和代码可维护性都会好很多。如果项目做到了这个程度,答辩时讲"模块化封装思想"就是随手拈来的加分点。
开发时最常踩的一个坑是 localhost 问题。小程序开发者工具里,如果你直接在后端接口地址填 http://localhost:8080,而电脑本地服务是正常的,开发者工具可能仍然报"无法连接",这是因为工具默认不会把 localhost 解析到电脑本机,尤其是 Windows 环境下有些代理配置会导致这种情况。解决方案有两种:要么勾选详情-本地设置-不校验合法域名,同时把请求地址改成 http://127.0.0.1:8080;要么直接运行到真机预览时,把电脑局域网 IP 填进去,确保手机和电脑在同一 WiFi 下。这些细节虽然不起眼,但卡住不少新手一整天。
4.3 前后端联调中的典型问题
联调是整个项目里最耗时但也是成长最快的阶段。我先列几个我调试中反复遇到的问题。跨域问题在前后端分离项目里非常经典:小程序端本质是 webview 发请求,也会触发跨域,需要在后端配置 CORS。一个简单的处理方式是写一个 WebMvcConfigurer 配置类,重写 addCorsMappings 方法,允许所有来源、所有请求头、所有方法。如果集群式部署涉及多个服务,还会碰到 Nginx 转发跨域问题,那就在 Nginx 层统一加 CORS 头,毕设阶段一般用不到,但知道有这么一回事会让你的应对更从容。
第二个典型问题是时间格式不一致。MySQL 里存的是 datetime,后端返回的 JSON 时间可能是 2024-05-20T16:30:00.000+08:00 这样的带 T 格式,小程序端直接展示就很丑。解决方法是后端在实体类的日期字段上加 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8"),返回给前端的字符串就会变成标准的 2024-05-20 16:30:00。这个看似简单的问题,我在帮人排查时遇到不下五次。
第三个问题是微信 code 重复使用导致登录失败。每次 wx.login 都会生成新的 code,后端拿 code 换取 openid 时,如果同一个 code 被反复使用,微信接口会报 code been used。有时候是开发者工具缓存了旧 code,或者是前端登录逻辑没有判断当前是否已登录就重复请求。解决方案很简单:前端在 app.js 里做统一的登录初始化,如果 storage 里已经有 token 且未过期,就直接跳过 wx.login 流程,只在 token 不存在或请求返回 401 时才重新拉起登录。
4.4 管理后台的快速搭建方案
管理后台不必从零写,这会拖慢整体进度。我推荐三种方案,各自取舍一下:第一种是使用 Vue Element Admin 这类现成的后台模板改造,页面风格统一、组件齐全,但需要学习和理解模板的代码结构,前期成本不小;第二种是直接用 Spring Boot 自带模板引擎(如 Thymeleaf)做一个极简管理端,后端渲染 HTML,写法朴素、容易理解、不需要单独开一个前端工程,对后端不熟的同学来说其实更友好;第三种是后端只提供管理接口,管理端页面做最简单的一个 HTML 页面直接调接口,适合时间极其紧张的情况。
从我实际经验看,大部分拿到这个题目的人后端基础一般,前端也不强,所以我倾向于第二种方案,即用 Thymeleaf 做一个能看能用的管理后台。它不需要 Node.js 环境,不需要构建打包,直接在 Spring Boot 项目里加依赖、写模板就能跑。科室管理、医生管理、排班管理这些业务场景用表格加表单就能实现,整点样式也不用太花哨,功能齐整、数据能维护就够用了。这也把前后端工程数量控制在了一个,降低联调和部署的复杂度,是性价比最高的选择。
5. 毕设文档、演示与答辩的实战经验
5.1 毕设说明文档(LW)的写作框架
做完项目后,论文的撰写往往是让很多人头疼的环节。医院预约挂号系统这类题目的论文结构已经高度成熟,照着一个清晰框架走就不会跑偏。绪论部分写研究背景、国内外现状、研究内容和意义;相关技术介绍部分写 Spring Boot、MyBatis-Plus、微信小程序这些技术的特点和优势;需求分析章节从可行性分析和功能需求两块展开,功能需求按角色梳理;系统设计章节放总体架构图、功能模块图、数据库 ER 图和表设计;系统实现章节按模块展示页面截图和核心代码片段;系统测试章节用测试用例表写功能测试结果。
写论文时有几个套路能让你的论文明显提档。一个是所有图全部重画,不要直接用别人图床上的截图,可以用画图工具或者绘图网站画规范的功能结构图和 ER 图。一个是数据库表设计章节不只要列出字段,还要给每个字段注明含义、类型、是否为空、是否主键外键,这会让老师觉得你对数据层掌控很扎实。还有一个是核心代码只放精华片段,比如并发扣减号源的那条 SQL、状态流转的 switch 逻辑,不要贴大段大段的完整类代码,否则答辩时老师会问你对代码的熟悉程度,你反而答不上来。
5.2 演示环节的准备与常见翻车现场
演示环节真的是翻车重灾区。我建议在答辩前至少完整走三遍演示流程,并且用文字脚本写好每一步操作。脚本可以这样写:打开小程序,首页展示医院和科室信息;点击挂号,选择科室,选择医生,看到医生详情和排班;选择一个可预约号段,确认预约,看到预约成功;进入我的记录,看到预约记录状态;取消预约,返回并刷新,看到号源恢复;切到管理后台,添加一个新科室,再添加一个新医生并排班,最后看到后台统计数字变化。
翻车场景一般集中在这几类:现场网络不稳定,小程序请求超时;演示账号是旧的,token 已过期,所有接口报 401;测试数据是脏数据,预约列表看着很乱;管理后台加数据时表单校验没过,但又没提示原因。为了避免这些情况,建议准备一个全新的演示账号,把数据库里的测试数据清理干净,所有演示操作都从空数据开始,按脚本走就能顺顺利利。另外,一定要准备一份数据脚本,能在演示之前一键重置数据库状态,万一中途搞乱了,恢复现场只需要几十秒。
5.3 答辩常见追问与回答思路
答辩环节老师最常问的问题我整理成了一份清单,提前准备好策略就好。第一个问"为什么选 Spring Boot 这个小程序组合"——回答要点是 Spring Boot 生态成熟、开发和部署效率高,小程序覆盖用户广、使用门槛低,两者结合能快速落地一个真实场景的应用。第二个问"号源并发超卖怎么保证"——这个必须把那条 update 语句的原子性讲清楚,再说我们通过受影响行数判断是否扣减成功,避免用先查询后更新的方案。第三个问"用户身份安全性怎么保证"——从 token 机制、登录凭证、接口鉴权三个方面讲,顺便提一下敏感信息不返回前端的原则。
还有一些不太难但容易被问到的,比如"预约状态有哪些、各状态如何转换""取消预约号源如何释放""如果排班状态停诊了,已预约用户怎么处理"。最后一个问题你可以在设计中提前考虑一个字段:排班表的 status 字段可以标记为停诊,取消预约的逻辑中,如果排班被设置为停诊状态,可以支持批量联系已经预约的用户。哪怕实现不完整,只要你脑子里有方案,答辩时能说出一套处理思路,老师的疑虑就基本能被打消。
6. 常见问题速查表与避坑清单
我把这几年调试预约挂号系统遇到的高频问题整理成了速查表,开发时对照着排查能省不少时间。
| 问题现象 | 根本原因 | 处理方式 |
|---|---|---|
| 小程序请求后端超时 | localhost 无法解析或未勾选不校验合法域名 | 改用 127.0.0.1 或局域网 IP,勾选不校验合法域名 |
| 后端报日期格式错误 | MySQL 连接 URL 缺少 serverTimezone 参数 | 在连接 URL 加上 serverTimezone=Asia/Shanghai |
| 接口全部返回 401 | 用户 token 过期或未存到请求 Header | 重新登录,检查请求封装是否携带 token |
| 号源被扣成负数 | 用了先查询后更新的并发扣减逻辑 | 改为 UPDATE SET remain_number=remain_number-1 WHERE id=? AND remain_number>0 |
| 取消预约后号源没恢复 | 取消逻辑没有在事务里释放号源 | 把状态更新和号源加一放在同一个事务方法 |
| 用户重复提交预约 | 缺少同一排班同一用户重复预约的校验 | 对 (user_id, schedule_id, 状态) 做查重或加唯一索引 |
| 微信 code 登录报错 | code 被重复使用或过期 | 前端做登录态判断,后端捕获 code 使用异常 |
| 管理后台无法新增排班 | 存在相同医生相同日期相同时段的记录 | 建唯一索引,并在 Service 层做业务提示 |
| 定时任务不执行 | 启动类缺少 @EnableScheduling 注解 | 在启动类上加 @EnableScheduling |
还有几条比较隐蔽的实战经验,放在这里属于常规教程里很难学到的。数据库里所有金额类型的字段不要用 double,用 decimal 更安全,但毕设预约系统如果没有支付环节就基本用不到。代码里所有接口入参都需要做非空校验和长度校验,不能信任前端传来的任何值,否则数据很容易被搞脏。管理后台统一设置一个异常处理器 @RestControllerAdvice,让所有业务异常都返回统一格式,前端处理起来会非常省心,也避免报错堆栈直接暴露给用户。
最后一个很重要但很多人不注意的点:在提交毕设之前,把源码里的敏感信息清理干净。包括数据库密码、Redis 地址、测试环境 IP、自己的微信号、导师信息等,要么覆盖成占位符,要么改成测试环境配置,提交之后不要留着生产环境真实数据。这不是技术问题,但每年都有学生因为这个被扣分。
结语:做完项目只是开始,吃透项目才算数
医院预约挂号这个题目做到最后,你会发现收获最大的不是那几千行代码,而是整套业务系统从需求拆解、数据建模、接口设计、并发控制到部署调试的完整链路思维。我带过的学生里,有个同学做完之后把并发扣减和状态机这部分反复研究了好几遍,后来去面试实习,面试官让他讲一个项目亮点,他就直接拿这套系统里处理号源超卖和取消释放的过程来讲,面试官连问了不少扩展问题,都接住了,最后顺利拿到了实习机会。所以我说,完成了毕设只是第一步,真正把每个设计决策背后的"为什么"想明白,才是这个项目带给你最大的价值。
如果你正在做这个题目,我的建议是:不要急着写代码,先把数据库表和状态流转图在纸上画透,把接口清单列出来,然后再动手。这个习惯能让你后面的开发效率至少翻一倍,也让你写论文时逻辑条理清晰得多。项目跑通之后,再把并发扣减、登录鉴权、定时清理这几个技术点练到能不看代码就能讲出来,答辩的时候你就已经赢了一半。
最后再分享一个小技巧:答辩时如果被问到没准备的问题,不要慌张乱答,沉默几秒组织好思路,然后按"这个问题可以从哪几个方面来看"的结构来回答。对于医院预约系统,几乎任何问题都能归结到数据模型、业务逻辑、安全控制这三个维度,只要你不跑题、说得出理由,老师都会认可。希望这篇拆解对你有用,也祝你的毕设顺利过关。