SpringBoot网上预约挂号系统毕设全解析:从表设计到防超卖机制

发布时间:2026/10/1 4:55:59
SpringBoot网上预约挂号系统毕设全解析:从表设计到防超卖机制 想做计算机毕设的朋友应该对“网上预约挂号系统”这个题目不陌生。它是Java Web方向非常经典的选题业务场景清晰技术栈主流既不像“图书管理系统”那样烂大街到答辩没亮点又比“电商秒杀”这类高并发项目更适合本科生驾驭。这几年我带过的学生里选这个题目的不少真正做完、做顺、答辩不慌的基本都抓住了几个关键点业务闭环要完整、表结构设计要合理、核心预约逻辑要讲清楚数据一致性。这篇文章我就以Java SpringBoot Web为技术底座完整拆解一个医院网上预约挂号平台怎么做。从选题逻辑、系统架构、数据库设计到核心预约业务的代码实现再到开发中一定会踩的坑一次性讲透。无论是正在选题犹豫不决还是已经开工写到一半卡住这篇都能给你一份可以直接“抄作业”的参考方案。1. 需求分析与系统整体设计思路1.1 为什么说这个选题是“性价比之王”毕设选题有个潜规则题目要让人一听就知道你做了什么但又要有足够的复杂度和区分度。“图书管理”“学生信息管理”这类纯CRUD题目技术上没有难点答辩老师随便问两句“你怎么处理并发”“你的权限怎么控制”就答不上来分数自然不高。反过来如果选“秒杀系统”“分布式电商”这种题目技术深度是够了但工作量巨大尤其是想自己一行行写出来本科生很难在一个学期内完成。网上预约挂号系统正好卡在中间。它的核心业务是“预约”这意味着你必须考虑几个真实业务问题同一个医生同一个时间段不能挂出两张号。同一个患者不能重复挂同一个医生的同一个时段。号源是有限的必须防止超挂。挂号后有取消、有退号号源要能释放。这些问题往深处说就是“数据一致性”和“并发控制”正好是SpringBoot后端开发里最有含金量的知识点。你说清楚“怎么用数据库唯一索引 事务控制 乐观锁来防止重复预约”答辩老师基本就满意了。1.2 系统角色与业务闭环预约挂号系统不是一个简单的“个人中心”它必须覆盖三种角色的完整业务流程。患者端注册登录、浏览科室和医生、查看排班、选择时间段预约、支付或免支付、查看预约记录、取消预约。医生端查看自己的排班、查看被预约的患者列表、标记接诊/完成就诊。管理员端科室管理增删改查、医生管理、排班管理给医生设置出诊时间和号源数量、统计报表某科室某天的预约量、系统公告管理。一句话概括业务闭环管理员维护基础数据 → 医生有排班 → 患者看到排班并预约 → 医生接诊 → 数据沉淀为统计报表。这里我特别提醒一点如果时间紧张医生端可以砍掉一部分但排班和预约这个核心闭环不能砍。因为“有排班才能预约”是整个系统的存在前提如果只是做个“患者随便选个医生提交预约”那和普通的表单提交没区别毫无业务价值。1.3 技术选型为什么是SpringBoot现在Java生态里做Web项目SpringBoot基本是事实标准。原因很简单内置Tomcat不用单独部署服务器打包即运行。自动配置大幅减少XML配置适合快速开发。生态成熟Spring Data JPA、MyBatis-Plus、Spring Security都有大量现成方案。面试和工作中使用广泛做毕设的同时等于提前熟悉了企业级开发框架。前端方面有两种路线一种是传统方案用Thymeleaf模板引擎渲染服务端页面另一种是前后端分离Vue SpringBoot后端只提供JSON接口。我不建议你在毕设里强行上前后端分离。原因很现实工作量直接翻倍你得同时写后端接口和前端页面还要处理跨域、Token鉴权等问题。如果前端功底一般很容易在联调阶段卡死。用Thymeleaf做服务端渲染一套代码搞定页面和接口专注把核心业务做好反而更容易出彩。我的习惯是如果项目要求了“前后端分离”那我就会明确区分如果没有要求默认用服务端渲染方案把主力精力放在预约流程、数据一致性和后台管理上。2. 数据库设计预约系统的地基2.1 核心表结构与关键字段数据库设计直接决定业务逻辑能不能写顺。我见过太多人把预约记录表设计得过于简单只有一个“患者ID 医生ID 预约时间”结果后面想扩展排班、想校验冲突全都无从下手。一个合格的预约挂号系统至少需要下面这几张表表名用途关键字段user用户表患者、医生、管理员共用的角色表id, username, password, real_name, role, phone, id_carddepartment科室表id, dept_name, description, sort_orderdoctor医生信息表id, user_id关联用户表, dept_id, title职称, intro, avatarschedule医生排班表id, doctor_id, dept_id, work_date, time_slot上午/下午, total_count, remain_count, statusappointment预约记录表id, patient_id, doctor_id, schedule_id, appoint_date, time_slot, status, create_timemedical_record就诊记录表可选如果医生端要做接诊id, appointment_id, diagnosis, prescription, create_time这里的核心设计点是排班表会存一个remain_count剩余号源数预约的动作本质上是“先查排班再扣减号源最后生成预约记录”——这是一个典型的库存扣减模型。2.2 防重复预约的表结构保证防止同一患者重复预约同一时段最简单有效的手段是在表结构层面加唯一约束。在appointment表中针对(patient_id, schedule_id)建立唯一索引。这样即使代码逻辑有漏洞数据库层面也会兜底拒绝重复插入。ALTER TABLE appointment ADD UNIQUE KEY uk_patient_schedule (patient_id, schedule_id);这个设计可以说是整个系统的“安全锁”。我在实际开发时哪怕业务逻辑里已经写了重复校验也一定会加这层约束因为并发请求下代码里的查重可能失效但数据库唯一索引是绝对可靠的。2.3 号源扣减与超卖问题号源扣减是预约系统最核心的坑。“超卖”指的是100个号源卖出去了101张。SpringBoot默认情况下多个用户同时发起预约请求如果采用“先查剩余号数判断是否大于0再减1”的逻辑在高并发下一定会出问题。解决这个问题有三种常见方案数据库乐观锁在排班表的remain_count字段上使用版本号控制UPDATE时检查version。条件更新用一条SQL完成“判断剩余号数大于0并且扣减”的操作。分布式锁用Redis锁控制同一排班的预约请求串行化。毕设场景下最推荐的是条件更新因为实现简单、SQL一条搞定、无额外依赖Modifying Query(UPDATE Schedule s SET s.remainCount s.remainCount - 1 WHERE s.id :scheduleId AND s.remainCount 0) int deductStock(Param(scheduleId) Long scheduleId);这个update方法返回int如果返回值是1说明扣减成功返回0说明号源已经为0预约失败。配合事务控制同一时刻即使来了100个请求数据库行锁会让他们排队执行只有前100个能成功扣减。这一招一定写进你的毕业设计说明书也是答辩时最能讲清楚的亮点。3. 核心业务实现从搭建到预约闭环3.1 SpringBoot项目搭建与目录结构无论用IDEA还是Eclipse创建SpringBoot项目都建议走Spring Initializr直接在IDEA里选Spring Initializr然后勾选依赖。需要注意的依赖有这么几个Spring Web提供Web能力Spring Data JPA 或 MyBatis-Plus操作数据库MySQL Driver连接MySQLThymeleaf服务端模板引擎Lombok简化实体类代码Validation后端参数校验项目搭建完成后目录结构按照SpringBoot常规规范来分com.example.hospital ├── controller // 控制层接收请求 ├── service // 业务层核心逻辑 │ └── impl ├── repository // 数据访问层JPA或MyBatis-Plus的Mapper ├── entity // 数据库实体类 ├── dto // 数据传输对象接收前端参数 ├── vo // 视图对象返回前端数据 ├── config // 配置类拦截器、跨域等 ├── common // 通用类结果封装、异常处理、常量 └── utils // 工具类这个结构不是随便分的它的核心思想是分层解耦。Controller只负责接收参数和返回结果Service只写业务逻辑Repository只做数据库操作。答辩时老师问你“为什么这么分层”你要能说出“降低耦合度、便于维护和测试”这种标准答案。3.2 用户登录与角色权限控制预约挂号系统至少有两种角色患者和管理员加上医生的话就是三种。SpringBoot里做权限控制有两种常用方式Spring Security安全框架和HandlerInterceptor拦截器。如果时间紧用拦截器就够了。我通常的做法是登录成功后把用户信息存入Session。自定义一个LoginInterceptor拦截所有请求。在拦截器里检查Session是否已有登录用户如果没有重定向到登录页。对于管理员专属的URL比如/admin/**校验role字段是否为admin。核心代码public class LoginInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { User user (User) request.getSession().getAttribute(loginUser); if (user null) { response.sendRedirect(/login); return false; } // 对管理员接口做强校验 String uri request.getRequestURI(); if (uri.startsWith(/admin) !admin.equals(user.getRole())) { response.setStatus(403); return false; } return true; } }这个方案的好处是不引入额外依赖代码量少逻辑清晰而且完全满足毕设需求。答辩时还可以顺手提一句“生产环境中一般会用Spring Security或Sa-Token但毕设场景拦截器更直观、更容易讲清楚”。3.3 预约挂号的完整业务逻辑这是整个系统的核心思路必须无比清晰。我按步骤拆解第一步患者进入医生详情页选择一个排班时段发起预约请求。请求携带两个参数scheduleId排班ID和当前登录用户的userId。第二步校验阶段。这一步要检查三件事排班是否存在且状态为“可预约”。当前时间是否超过该排班的截止预约时间比如当天上午的号10点后不能再预约。当前时间是否晚于排班的就诊日期。第三步查重。查询appointment表确认该患者没有预约过这个排班。第四步扣减号源。执行上面提到的条件更新SQL判断返回结果是否为1。第五步生成预约记录状态设为“已预约”。第六步提交事务。任何一步失败整体回滚。这六步必须在同一个事务里执行。我习惯在Service方法上直接加Transactional注解Transactional(rollbackFor Exception.class) public Appointment bookAppointment(Long scheduleId, Long patientId) { // 1. 查找排班 Schedule schedule scheduleRepository.findById(scheduleId) .orElseThrow(() - new BizException(排班不存在)); // 2. 校验时间 if (schedule.getStatus() ! ScheduleStatus.AVAILABLE) { throw new BizException(该排班已不可预约); } // 3. 查重 if (appointmentRepository.existsByPatientIdAndScheduleId(patientId, scheduleId)) { throw new BizException(您已预约过该时段请勿重复预约); } // 4. 扣减号源 int result scheduleRepository.deductStock(scheduleId); if (result 0) { throw new BizException(号源已满预约失败); } // 5. 生成预约记录 Appointment appointment new Appointment(); appointment.setPatientId(patientId); appointment.setScheduleId(scheduleId); appointment.setStatus(AppointmentStatus.BOOKED); return appointmentRepository.save(appointment); }这里有一个非常容易被忽略的点事务注解的rollbackFor属性一定要写。Spring默认只对RuntimeException回滚如果业务代码里抛的是自定义的Exception不加rollbackFor事务就不会回滚会出现号源扣了但预约记录没生成的情况。这是新手最容易踩的坑之一。3.4 取消预约与号源释放有预约自然有取消。取消预约的逻辑相对简单但也要注意两点只有状态为“已预约”的记录才能取消。取消后要释放号源也就是把排班表的remain_count加回1。同样要放在一个事务里否则会出现“预约状态改了但号源没释放”的问题。很多人在这一步会漏掉导致系统运行一段时间后号源越来越少最后变成“永远满号”——这个问题答辩时被问到就很尴尬。4. 页面展示与管理端功能要点4.1 患者端的页面流转服务端渲染方案下页面用Thymeleaf写。页面不多我建议按这个节奏来首页展示科室列表和重点医生推荐导航栏有登录/注册入口。医生列表页支持按科室筛选、按职称排序展示医生头像、简介、剩余号源情况。医生详情页展示医生介绍、本周排班表每个时段显示剩余号数。预约确认页展示预约信息确认后提交。个人中心我的预约列表可以对“未就诊”的预约发起取消。页面上需要特别注意的是排班表的展示逻辑。医生一周有7天每天可能有上午、下午两个时段每个时段是一个排班记录。展示的时候需要先按日期分组再按时段显示剩余号数。剩余为0的时段要置灰并提示“已约满”这样患者体验才合理。4.2 管理端的核心功能清单管理端的核心职能是“维护系统基础数据和查看运营数据”。如果做得太粗糙会让整个项目显得不够完整。我建议最低限度包含这些功能科室管理列表、新增、编辑、删除。删除前要校验该科室下是否有医生有的话提示不能删除。医生管理列表关联科室、职称、新增医生同时创建登录账号、编辑、停用。排班管理选择医生、选择日期、设置时段和号源总数生成排班。预约查询按日期、医生、状态筛选预约列表处理“爽约”或“完成”操作。数据统计按科室统计近7天预约量按医生统计接诊量用柱状图展示。这里有一个注意点批量生成排班功能。如果排班只能一条一条手工添加管理员创建一个月的排班会累死。好的做法是管理员选好医生和一个日期范围系统自动为该时间段内的每一天生成上下午排班。这个功能实现不难但很能体现你做项目的思考深度。4.3 Bootstrap或Tailwind选一个就行服务端渲染的页面不推荐写原生的CSS来布局效率太低。直接用Bootstrap 5或Tailwind CSS的CDN引入组件现成、响应式适配也好。如果想让页面有“医疗系统”的感觉可以在配色上用蓝色或蓝绿色系避免大红大紫。整体布局参考常见的“顶部导航 主体内容”结构管理端用“左侧侧边栏 右侧内容区”的后台框架布局。页面样式这块不用追求花哨干净、整齐、信息层次清晰才是关键。5. 常见问题、排坑经验与答辩要点5.1 开发期必踩的几个坑这些坑在我带学生做项目的过程中反复出现提前排掉能省很多时间。时间格式问题。排班日期和时段前端提交的是字符串后端直接收会报错或者格式不对。在实体类的日期字段上加上DateTimeFormat(pattern yyyy-MM-dd)同时前端表单里固定用typedate或datetime-local的输入框。另外用LocalDate而不是java.util.Date来存日期可以避免大量时区和格式化烦恼。Lombok和实体类toString的坑。如果用Lombok的Data注解生成toString实体类里的关联对象比如医生类里有关联的科室对象会在toString时产生循环调用导致栈溢出。解决办法一是用ToString.Exclude排除关联字段二是建议手动控制需要输出的字段。IDEA里改代码但不生效。检查是否开了热部署。如果没开每次改了后端代码都建议手动重启一下。如果用Thymeleaf模板改了页面但没生效检查application.yml里的缓存配置spring: thymeleaf: cache: false跨域问题。如果你最后还是选择了前后端分离一定要在SpringBoot里配置CorsFilter或者用CrossOrigin注解。否则前端页面调接口会报CORS错误在浏览器里看起来像是后端崩溃了其实是跨域被拦。5.2 数据一致性验证的方法项目做完后建议做一个简单的并发测试验证防超挂是否真的有效。方法也不复杂把某个排班的号源总数设为1。用两个浏览器窗口分别登录两个不同的患者账号。同时点击预约这个排班的按钮。如果系统正确一个成功另一个提示“号源已满”。如果你能力强一点用JMeter开10个线程同时请求预约接口观察最终预约成功的数量有没有超过号源总数。这个测试结果截图放进论文里是很有说服力的。5.3 答辩时要主动展示的亮点答辩时间通常只有5到10分钟老师没有时间去细看你的全部代码。你要在有限时间内主动把最有含金量的几个点讲出来表结构设计为什么要给预约记录加唯一索引为了数据库层面的兜底。号源扣减怎么防止超卖条件更新SQL一条语句完成判断和扣减。事务控制预约和取消预约为什么必须加事务避免脏数据和号源泄漏。角色权限拦截器怎么控制不同角色的访问路径。讲这些的时候不要背概念要用“我在实现中发现了一个什么问题然后怎么解决的”这种叙事方式。比如“我一开始用先查后减的写法结果模拟并发的时候出现了超卖后来改成一条SQL条件更新再测试就稳定了。”这种表达比背理论高出一个档次。5.4 在线演示前的心态准备毕设答辩时大概率会用你自己电脑在线演示。演示前务必准备好确认MySQL已经启动数据库导入脚本执行过。确认项目是启动状态不是写好了没跑。准备一个演示账号管理员一个患者账号。演示路径要提前走一遍登录 → 查看科室 → 查看医生 → 查看排班 → 预约 → 个人中心确认 → 取消 → 管理端查看数据变化。如果现场出现意外比如数据库连不上或者页面报错不要慌。直接说“这个环境之前是可以的我重启一下服务”。临场解决问题的能力本身就是答辩评分的一部分。为了万无一失可以提前在本地把打包好的jar文件也跑一遍熟悉一下从jar包启动的流程。用java -jar命令启动项目后用浏览器访问这套流程跑通了演示就基本没大问题。写在最后的经验我在实际开发和指导学生的过程中最大的感受是毕设项目的分数高低不全取决于代码量大小更多取决于你有没有把核心业务讲清楚、关键问题有没有解决方案。预约挂号系统这个题目天生自带“防重复预约”“号源防超卖”“事务一致性”这些高质量话题你只要把一个点做扎实了就已经超越了大量只会CRUD的同学。如果你现在正好在做这个题目我的建议是先把排班表和预约记录表这两张表吃透把预约和取消预约这两段业务代码写顺然后再去补页面和管理功能。骨架立住了剩下的都是锦上添花。开发过程中遇到具体报错多用控制台日志和断点调试定位问题别急着改代码先搞清楚为什么错。这种排查过程其实就是答辩时你能讲出“故事”的素材。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询