Spring Boot + Vue + MySQL 医院挂号就诊系统实战解析

发布时间:2026/10/14 22:52:42
Spring Boot + Vue + MySQL 医院挂号就诊系统实战解析
医院挂号就诊系统听着不算起眼但这几年我见过太多人在这类项目上栽跟头。要么在网上找到一份号称“完整源码”的压缩包结果数据库脚本不匹配、前端接口对不上、一启动就报红要么自己从零写一个小demo登录注册没问题一做到挂号、排班、就诊记录这种有业务深度的部分就卡住了。所以看到这个标题——“Spring Boot Vue MySQL可直接运行”——我第一反应不是去看它功能有多全而是想知道它究竟把哪些最容易翻车的环节处理清楚了。这篇博文我会从我实际拆解这个系统的角度出发把技术选型的逻辑、数据库设计的核心、后端关键接口的实现思路、前端页面的对接方式以及“拿到源码后如何快速跑起来”这整个链路完整讲一遍。无论你是准备拿它做课程设计、毕业项目还是想参考它的业务设计做自己的医疗类系统这篇文章都能让你少走不少弯路。1. 为什么这类系统最终选了Spring Boot Vue MySQL这个组合先说一个很现实的问题医院挂号就诊系统这种项目技术栈选择其实没有太多“炫技”空间核心需求是稳定、清晰、容易维护、能快速交付。我在评估这套源码时就是按这个标准去看的。1.1 后端选Spring Boot是权衡过其他方案之后的结果医院挂号系统最敏感的是什么是稳定性和可维护性。这类应用虽然有并发压力但远没到需要微服务那套架构的程度。一个单体应用、打包成jar包就能部署对于绝大多数医院科室或中小型门诊来说已经完全够用。我们拿它和其他方案做个对比如果选SSHStruts Spring Hibernate那套老架构配置繁琐现在招人都不好招如果选Python的Django或者Flask开发效率确实高但常见部署环境的运维习惯、代码规范在很多学校和企业里还是更偏向Java生态如果选Node.js做后端开发和热部署是快但要接Java系的人去维护沟通成本就上来了。Spring Boot的价值在于它把“能用”和“好用”平衡得比较好。内嵌Tomcat不用额外部署容器起步依赖帮你把包版本都对齐避免一堆版本冲突结合MyBatis-Plus操作MySQLCRUD代码量能少掉一半。选择这个组合本质上是选择了一个“后续找人接手也容易”的方案。1.2 前端用Vue是考虑到前后分离之后的可维护性很多老一点的系统是后端渲染模板页面直接写在Java里改个按钮样式都要重新编译打包在真实的医院场景里特别尴尬。这套源码采用的是Vue前端工程和后端完全分离前端开发专心做页面交互后端专心出接口两边只通过JSON数据交互。Vue本身的上手曲线比React平缓很多对新手友好。配上Element UI这套现成的组件库表格、表单、日期选择器、弹窗这些医疗管理系统里高频使用的东西都有现成封装页面能快速成型。更关键的是Vue工程构建产物是一堆静态文件可以丢在任何一台有Nginx或静态服务器的地方不需要额外装node环境这对实际部署非常友好。1.3 MySQL作为数据库免费的可靠的够用的医院挂号系统涉及的数据量单靠一台普通MySQL服务器完全能扛住。MySQL在事务支持InnoDB引擎上做得足够稳挂号、退号、号源扣减这些操作必须保证原子性这一点InnoDB的行级锁和事务机制可以满足。此外这套源码还配了SQL初始化脚本表结构、初始数据一次性导入不用手工建表这在我看来是一个项目是否“走心”的重要标志。2. 数据库建模挂号系统的表设计才是核心中的核心很多人在抄这种系统的时候第一反应是页面长什么样但真正决定系统好不好的是数据库表设计。一个挂号系统如果表建得不合理后面写接口每一步都要别扭。我拆解了一下这套源码的数据模型发现它就七个字围绕“排班挂就诊”展开。2.1 核心表结构拆解用户、科室、医生、排班、挂号、就诊一套完整的医院挂号就诊系统最核心的表大概是这么几张系统用户表存放患者、医生、管理员三类账号用角色字段区分。患者手机号、姓名、密码、性别、年龄这些基本信息都在这张表里。科室表科室编号、科室名称、科室位置、科室介绍、挂号费用。医生表姓名、职称、所属科室、简介医生和科室是多对一关系。排班表医生ID、排班日期、上午或下午时段、剩余号源数、总号源数。挂号单表患者ID、排班ID、就诊日期、就诊时段、挂号时间、订单状态待就诊、已就诊、已取消。就诊记录表挂号单ID、医生ID、患者ID、主诉、诊断结果、医嘱、就诊时间。这个设计的聪明之处在于它把“排班”作为中间枢纽。医生不直接和挂号单挂钩而是通过排班表产生一天某个时段的号源池患者挂号时从号源池里扣减。这样一来一个医生上午放30个号挂了20个还剩10个这个“剩余号源”的统计就非常自然不需要额外做复杂的聚合查询。表关系简要梳理如下表名核心关联字段说明用户表id / role区分患者、医生、管理员科室表id独立字典表医生表user_id / dept_id医生复用系统用户表的账号排班表doctor_id / dept_id一个医生多个排班挂号单表patient_id / schedule_id一次挂号对应一个排班就诊记录表reg_id / doctor_id一个挂号单对应一条就诊记录2.2 设计时值得留意的几个字段细节我在看这套库的时候注意到几个容易被新手忽略的字段设计简单展开说一下。第一个是状态字段。挂号单的status列我建议用tinyint而不是varchar枚举值提前定好注释对应关系比如0待就诊、1已就诊、2已取消。用数字做状态的好处是接口层判断简单不会出现大小写和中文不一致的问题。第二个是时间字段的统一。挂号和排班都涉及日期加时段这套系统用了date字段存日期、tinyint存时段0上午、1下午而不是直接用datetime存时间戳。这样设计的好处是排班查询极其直观输入一个日期查出当天某个医生的所有排班而不会卡在“时间范围模糊匹配”这种坑里。第三个是逻辑删除。带业务数据的表比如挂号单、就诊记录尽量不要物理删除用is_deleted字段做标记。医院场景有审计需求患者挂号后如果因为冲突退号了也需要留下痕迹。MyBatis-Plus里加了TableLogic注解就能自动处理逻辑删除这套源码确实也这么做了。3. 后端核心功能拆解登录、挂号、就诊这条链路怎么落地后端是整套系统的中枢。我看源码时重点跟了一下三个链路登录认证、挂号业务、就诊闭环。这三个环节的业务逻辑密度最高也是判断一套源码“真能用”还是“花架子”的分水岭。3.1 登录认证JWT 拦截器的轻量权限方案这个系统没有引入沉重的Spring Security那一套复杂配置而是选择了JWT 拦截器来实现权限控制。整体逻辑是这样的用户登录成功后后端根据用户ID和角色生成一个token前端把token存进localStorage后续每个请求在请求头里带上token后端通过拦截器解析token识别当前用户是谁、属于什么角色。拦截器这一步处理得比较稳妥。它放行了登录接口、注册接口和一些公开的查询接口其余接口统一进入token校验逻辑。校验通过后把解析出来的用户信息放进ThreadLocal里后续Service层随时可以取到当前操作人。这个手段在电商、办公、医疗这类系统里非常常用既能拿当前用户身份又不需要每个接口都手动传用户ID。核心代码结构大致是这样的public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (!StringUtils.hasText(token)) { throw new BusinessException(401, 未登录或登录已过期); } Claims claims JwtUtils.parseToken(token.replace(Bearer , )); if (claims null) { throw new BusinessException(401, 无效token); } UserHolder.set(JSON.parseObject(claims.getSubject(), LoginUser.class)); return true; } Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { UserHolder.clear(); } }3.2 挂号业务的并发安全设计挂号是整套系统里最需要严谨对待的地方。如果两个患者同时挂同一个医生上午的最后一个号挂在MySQL层面是非常典型的并发写场景。这套源码的处理方式是用数据库的乐观/悲观锁思路在排班表上加一个当前剩余号源数current_num字段挂号时执行先扣减再插入的SQL。具体来说扣减号源时不是先查询剩余数量再判断是否大于0而是直接执行一条带条件的更新SQLUPDATE schedule SET current_num current_num - 1 WHERE id #{scheduleId} AND current_num 0这条SQL是关键核心它通过current_num 0这个条件让数据库在更新时自行判断号源是否可扣减。受影响行数为0说明号源已满直接抛出“该时段号源已满”的异常。然后在这个操作的外层包裹事务一起执行插入挂号单。这样做从源头避免了超卖问题。再来是防止重复挂号。同一个患者在同一排班下只能有一张有效挂号单这个限制是在挂号单表上加了唯一索引patient_id schedule_id is_deleted组合同时插入前再用查询做一次业务校验双保险。唯一索引是兜底业务校验是为了提前给出友好的提示两者缺一不可。3.3 就诊闭环从接诊到生成就诊记录医生端登录后看到自己当天排班对应的挂号列表点击“开始就诊”系统更新挂号单状态为已就诊同时创建一条就诊记录。就诊记录包含主诉、现病史、诊断结果、医嘱建议等典型字段。这个环节的重要性在于它把“挂号”和“就诊”串联起来形成了一个完整的业务闭环。很多学习项目做到挂号模块就停了没有后面这一层看源码的人也就学不到如何处理一对一的从订单状态到业务单据的转换。这套源码用了一个很经典的模式在Service层通过事务先更新订单表状态再插入就诊记录表两个操作要么都成功、要么都失败保证了核心业务的一致性。3.4 管理端统计几个典型的聚合查询管理后台通常要看今日挂号量、各科室挂号分布、医生工作量这些统计这套源码在统计SQL上用了不少group by和日期函数。比如统计今日每个科室的挂号人数逻辑是关联排班表找到科室ID再按科室分组计数。这类写法在很多报表场景里可以被直接复用。4. Vue前端与接口对接页面结构、请求封装和权限处理前端这块如果我直接说“页面做得很全”那等于没说。我看了实际页面和接口的对接方式后觉得有几处细节值得展开讲讲。4.1 前端工程的整体组织工程是基于Vue CLI构建的标准前后端分离项目目录结构清晰到可以当模板用。src下分了三块api目录放所有接口请求views目录按角色分页面router目录统一管理路由。这里特别值得说的是页面级别的分角色设计。患者端主要看到的是首页、科室列表、排班查询、预约挂号、我的挂号记录医生端是排班查看、接诊列表、填写就诊记录管理端是科室管理、医生管理、排班管理、挂号统计。三者通过路由守卫配合角色字段控制可见范围。4.2 Axios请求封装和token携带这套源码没有在每个页面里直接写axios请求而是统一封装了一个request工具。它在请求拦截器里自动从localStorage取token并加到请求头的Authorization字段在响应拦截器里做统一错误提示比如401跳转登录页、500弹出后端返回的错误消息。前端这一层标准化作用很大。后续想加loading效果、想统一处理超时都只需要改一个文件就行。实际开发时我非常推荐大家沿用这种写法不要在业务页面里裸调axios。service.interceptors.request.use(config { const token localStorage.getItem(token) if (token) { config.headers[Authorization] Bearer token } return config }) service.interceptors.response.use( res { if (res.data.code 401) { router.push(/login) return Promise.reject(new Error(登录过期)) } return res.data }, err { Message.error(err.response?.data?.message || 系统异常) return Promise.reject(err) } )4.3 挂号页面的设计三步走的交互逻辑挂号页面的交互做得比较顺。第一步选择科室第二步选择医生和日期第三步选择上午或下午时段并确认挂号。这三个步骤对应三个不同的后端接口但页面通过一个本地选择状态把流程串起来最终提交时才调用挂号接口。这种分步交互的好处是业务表达清晰患者不会因为信息一步全铺开而觉得操作压力大。而且每步都有对应的Tab或卡片显示当前选择内容即使误操作也能按返回键回退重新选择交互容错做得好。对于模仿学习来说这个页面的状态管理方式值得好好读一读。5. “可直接运行”的秘密环境匹配、配置文件与启动排坑指南标题里“可直接运行”四个字其实是这套源码最核心的卖点。现在网上很多开源项目的通病是下载容易、跑起来难。这套系统能跑通在我看来主要是在“环境匹配”和“初始化数据”这两个点上踩过坑、做好了铺垫。我带你过一遍实际启动时需要准备的环境和容易踩的坑。5.1 环境版本对应关系环境项推荐版本说明JDK1.8或11Spring Boot 2.x系列1.8足够11也可MySQL5.7或8.0两个版本都可以8.0建议注意时区配置Node.js14至16Vue Cli 4/5兼容性最好Maven3.6以上用于后端依赖下载和打包前端包管理器npm或yarn二选一即可首次启动先把MySQL里建一个hospital_db数据库执行项目里根目录的init.sql脚本。这个脚本承担了“建表 初始数据”双重重任管理员账号、演示密码、科室数据、部分医生数据都帮你备好了。没有这一步项目能编译但打开页面也看不到内容。5.2 最容易踩的几个启动坑第一个坑是时区问题。MySQL 8.0连接时如果URL里没加serverTimezoneAsia/Shanghai启动时大概率报凌晨时区错误。解决办法是在application.yml的数据源连接串里把时区参数补齐同时确认MySQL服务端的时区设置没有异常偏移。第二个坑是Redis依赖。有些后台系统会顺手把Redis加上做缓存这套源码在看下来时没有强制依赖Redis但如果你的版本或扩展里引入了Redis相关starter记得本地要有可连接的Redis服务或者直接把配置关掉。启动前扫一眼有没有redis相关配置能省掉很多麻烦。第三个坑是前端依赖安装慢或报错。前端目录下执行npm install前建议先设置npm镜像地址到国内源不然node-sass这类包如果用到很容易卡住。锁定版本也很重要别在这个项目里用最新版Vue去跑Vue 3和Vue 2的API差异在实战中是能拆掉一整天时间的大坑。第四个坑是跨域配置。前后端分离开发时前端地址是localhost:8080后端是localhost:8081除非在Vue的vue.config.js里配好了代理否则接口请求会被浏览器拦截。这套源码里用了devServer的proxy方式把/api前缀代理到后端地址如果在自己的电脑上跑不通优先检查代理配置是否指向了正确的后端端口。5.3 启动顺序和验证步骤推荐的启动顺序是这样的第一启动MySQL导入init.sql第二启动后端Spring Boot看控制台输出端口为8081且没有报数据源错误第三前端目录执行npm install然后npm run serve看到浏览器自动打开登录页。验证系统是否真的跑通我的习惯是用三个动作串一遍用管理员登录后台创建一条新的排班退出后用患者账号登录到该科室挂号再用医生账号登录看到这条挂号单并点击“开始就诊”。整个流程走下来这条系统的主链路就算真正闭环了后面再怎么深挖细节都有底。从项目源码里真正值得带走的不只是代码本身最后再说一点个人体会。这套系统拿下来之后逐行去看登录、挂号、就诊这几段核心流程时有一个感触很多项目之所以“可运行”并不是它用了多复杂的技术而是它把边界问题处理得足够细致。比如数据库时区、逻辑删除、并发扣减号源、角色路由守卫——任何一个环节没考虑到位整个系统的体验就会崩。如果你也是边学边做这类系统我建议你不要只满足于把页面跑起来而是重点去推演一遍“两个患者同时挂号”这样的并发场景想明白背后的锁与事务设计。这才是这个源码作为学习样例真正的价值所在。