ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SpringBoot+Vue+MySQL医院挂号就诊系统:设计、部署与答辩攻略

SpringBoot+Vue+MySQL医院挂号就诊系统:设计、部署与答辩攻略 最近这半年几乎每隔两三天就有同学私信我同一个问题毕设想做一个医院挂号就诊系统SpringBoot Vue MySQL 这套组合到底该怎么落地后台有哪些角色数据库表怎么设计前端页面从哪下手今天我把一个可移植、可答辩、能跑完整业务流程的医院挂号就诊系统方案的完整思路和实操细节梳理一遍。这套项目定位很明确面向患者提供在线预约挂号、订单查询和就诊记录查看面向医生提供排班管理、待就诊列表和病历录入面向管理员提供科室、医生、排班维护以及挂号统计。适合正在准备毕业设计、又不想把项目做成普通增删改查模板的同学参考也适合照着这套思路自己复现一遍。很多人的误区是想先写代码等代码写完再补论文。我建议反过来先把业务流程理清楚、把表设计好代码只是把设计落到具体实现上。医院挂号系统最大的学习价值不是 CRUD而是“号源扣减、重复预约控制、权限分离、业务状态流转”这些可以在答辩时拿出来讲的东西。这篇文章会从设计、数据库、后端、前端、部署、论文和答辩七个方面把整套逻辑讲清楚所有步骤都是可以直接照着操作的方案。1. 整体设计思路与选型逻辑1.1 为什么用SpringBoot和Vue这套组合先聊选型。医院挂号就诊系统属于典型的企业级业务系统需要面向多角色、有清晰权限边界、数据关系复杂同时界面还要有一定可展示性。SpringBoot的优势在于自动配置、内嵌Tomcat、生态成熟写接口的效率比传统SSH高很多。Vue作为前端框架组件化和路由机制能很好承担多页面切换、表单交互和数据展示。MySQL则是这套系统里最自然的关系型数据库选择表结构清晰事务支持可靠当前网上所有毕设参考资料也基本以这三者为主。这里有一个很关键的坑SpringBoot的版本选择直接决定你能不能顺利跑起来。目前学校环境最稳妥的是Spring Boot 2.7.x搭配JDK 8代码里用javax开头的包MyBatis-Plus用3.5.3左右兼容性最稳。如果你从网上下了一套源码里面用的是Spring Boot 3.x那JDK必须在17以上包名也要从javax改成jakartaMyBatis-Plus必须升级到适配版本。很多同学拿到源码跑不起来原因就是版本错位后面部署环节我会专门列出来。另一个容易忽略的点是为什么选用前后端分离而不是老式JSP。前后端分离的项目结构更丰富答辩时你可以说清楚前端路由、接口规范、跨域处理这些知识点。更重要的是Vue的组件化写法让页面维护成本降低比如医生排班、挂号表单、统计图表都是独立组件改一个不影响其他页面。缺点是部署时多了动静资源整合的步骤但我后面会给出一种把前端打包进后端的简易方案演示时非常不容易翻车。1.2 系统角色与业务闭环一个完整的医院挂号系统至少要有三个角色这三个角色构成了业务闭环。患者端注册登录、查看科室列表、查看医生排班、选择日期和时段提交挂号、模拟支付、取消挂号、查看自己的挂号记录和医生填写的就诊记录。医生端查看自己的排班、查看某一天的待就诊患者列表、点击开始看诊、录入主诉、现病史、诊断结果和医嘱建议完成看诊后该就诊状态变为已完成。管理员端维护科室信息、维护医生信息、为医生生成排班、设置号源总数和挂号费、用图表查看各科室各日期挂号量。很多网上的系统只有患者和管理员两个角色这样的项目答辩时会被评委追问医生怎么工作非常尴尬。加了医生端之后挂号、就诊、病历形成完整闭环也意味着数据库表之间有了真实业务关联挂号订单关联排班排班关联医生就诊记录关联挂号订单。这种关联关系写进论文的数据流图里非常加分。为什么我坚持要把“取消挂号”和“就诊完成”做进去因为状态变化是评委判断你有没有思考业务细节的重要依据。挂号订单不是加进去就结束的患者可能临时取消医生可能放号后不出诊就诊后需要回写结果。把这些状态整理清楚比堆功能更管用。1.3 交付物清单与代码结构完整的毕设项目交付物包括四块源码、数据库SQL脚本、论文、部署文档。源码部分建议分成两个目录后端hospital-backend和前端hospital-frontend。数据库脚本就是hospital.sql包含建库、建表、初始数据。部署文档按“环境要求、本地运行步骤、打包发布步骤、常见问题”四段来写篇幅不用长但每一步都要写清楚尤其是数据库密码修改和前端启动命令。我看过不少同学的目录乱成一锅粥后端代码不分包、前端组件全部堆在views里。一个逻辑清晰的结构规划应该是这样的。后端按照controller、service、mapper、entity、config、common、utils分包controller只负责接收请求和返回结果业务逻辑全部放在service层数据库操作放mapper层。前端按照views、components、router、api、store、utils分包api目录单独管理所有后端接口请求不要在页面上满天飞地调方法。2. 数据库设计把业务拆成一张张表2.1 核心表结构与字段解析医院挂号系统的表不用设计太多能跑通闭环的有七张就够了用户表、科室表、医生表、排班表、挂号订单表、就诊记录表、管理员可以和用户表合并通过角色字段区分。我实际做这套系统时最关注的是排班表和挂号订单表。先看用户表。字段有id、username、password、real_name、phone、rolerole用patient、doctor、admin区分。密码不要存明文用BCrypt加密这是答辩时一定会被问到的高频点表达清楚“即使数据库泄露也无法直接看到明文密码”这一点就能得分。排班表是整个系统的核心一张排班记录代表某个医生在某个日期的某个时段出诊。字段包括id、doctor_id、work_date、period、visit_fee、total_count、remain_count、status、version。period用tinyint表示上午还是下午visit_fee是当次挂号费remain_count是剩余号源version用于乐观锁控制并发。这里为什么把同一天的上午和下午拆成两条记录而不是用一个字段存因为数据库要求每条记录可独立判断状态和扣减号源拆开之后上午挂满不影响下午继续挂号。挂号订单表我一般这样设计id、order_no、user_id、schedule_id、visit_date、period、status、pay_status、create_time。order_no用时间戳加随机数生成避免订单号重复。status字段表示挂号状态比如1已预约、2已取消、3已完成。pay_status表示支付状态0未支付、1已支付。关键是给user_id和schedule_id加一个联合唯一索引这样才能保证同一个患者不会在同一个排班记录里重复挂号。科室表、医生表、就诊记录表相对常规。科室表有dept_id、dept_name、intro。医生表有doctor_id、dept_id、name、title、intro。就诊记录表有id、registration_id、chief_complaint、current_history、diagnosis、suggest、create_time。就诊记录通过registration_id关联回挂号订单这样患者端查就诊记录时只需要join一张表。2.2 号源扣减与超卖问题号源扣减是整个系统里最值得在答辩时展开的技术点。如果直接先查询remain_count是否大于0然后再执行update在高并发下可能出现两个请求同时查到剩余号为1然后同时执行更新最后超卖。解决思路不是加复杂的分布式锁而是在SQL层面做原子条件更新。我的做法是写一条update语句把判断数量和扣减放到同一个SQL里执行update schedule set remain_count remain_count - 1, version version 1 where id #{scheduleId} and remain_count 0MyBatis的Mapper方法返回值是受影响行数。如果返回值是0说明当前排班号源已经为0或者排班不存在这时候直接在service层抛出“号源已被抢完”的异常。数据库行锁保证同一时刻只有一个事务能成功更新这条记录所以不会超卖。很多同学会用“先select判断再update”的写法我建议趁早改掉这就是答辩时拉开差距的细节。2.3 状态字段与字典约定业务状态不要用魔法值散落在代码里建议在项目里定义一个常量类或枚举类把挂号状态、支付状态、排班状态集中管理。比如RegistrationStatus枚举里有BOOKED、CANCELED、FINISHED三个值。前端展示时根据状态值映射成中文“已预约”“已取消”“已完成”并且用不同颜色标签渲染。这样做的直接好处是前后端约定明确不会出现公司里常见的“状态字段到底什么含义”之争。数据库设计还有一个细节容易被忽略所有表建议都加上create_time和update_time字段并使用MyBatis-Plus的自动填充功能。这样开发时不需要在业务代码里手写时间赋值论文里还可以写“通过自动填充机制减少重复代码”。初始数据也很重要在SQL脚本里预置一个管理员账号、几个科室、几个医生和一两天的排班数据演示时不用临时新增登录就能直接看到排班表页面有数据。3. 后端核心SpringBoot分层与权限控制3.1 后端包结构与统一返回后端的包结构直接决定代码的可读性和维护性。我推荐一个绝对够用的骨架controller放接口service放业务mapper放数据库操作entity放数据表实体dto放前端传参对象config放配置类common放统一返回结果和异常处理utils放JWT工具类等通用方法。统一返回结果类用泛型设计所有接口都返回相同结构。public class ResultT { private Integer code; private String message; private T data; public static T ResultT success(T data) { ResultT result new Result(); result.code 200; result.message success; result.data data; return result; } public static T ResultT error(Integer code, String message) { ResultT result new Result(); result.code code; result.message message; return result; } }这样前端axios拦截器里只需要判断code是否为200就能统一处理错误提示不用每个接口单独写异常分支。加上全局异常处理之后业务代码里任何一处抛出运行时异常都会被统一捕获并转换成Result返回给前端不会出现堆栈信息直接裸奔到浏览器的情况。这是专业项目与练习项目的明显分界线。3.2 JWT登录与拦截器配置医院挂号系统涉及三个角色登录后必须拿到当前用户身份和角色。传统做法是Session但前后端分离项目我更推荐JWT。登录成功时后端生成一个token返回给前端前端存在localStorage里之后每次请求在请求头加上Authorization字段。token里可以只放userId和role不存放敏感信息。后端处理token的核心是拦截器。在SpringBoot里实现HandlerInterceptorpreHandle方法中获取请求头中的token调用JWT工具类解析解析成功就把userId放入request的attribute然后放行。注册拦截器的时候要排除登录、注册、获取科室列表这些不需要认证的接口同时把管理员接口单独做一层角色校验。Configuration public class WebConfig implements WebMvcConfigurer { Resource private JwtInterceptor jwtInterceptor; Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(jwtInterceptor) .addPathPatterns(/**) .excludePathPatterns(/api/auth/login, /api/auth/register, /api/dept/list); } }这里我说一下为什么要区分拦截器和角色校验。拦截器只负责验证“你是否登录”登录之后再看“你有没有权限访问这个接口”。最简单的角色校验可以在Controller方法上自己用request的attribute判断但要更专业一点可以自定义一个RequireRole注解配合拦截器实现。不过毕设阶段在service或controller里通过当前用户角色判断也完全够用讲清楚思路即可。3.3 接口设计与业务编排后端接口设计建议统一加上/api前缀并且按业务模块命名。认证模块是/api/auth/login、/api/auth/register科室模块是/api/dept/list、/api/dept/add、/api/dept/update、/api/dept/delete医生模块是/api/doctor/list、/api/doctor/add排班模块是/api/schedule/page、/api/schedule/add挂号模块是/api/registration/submit、/api/registration/cancel、/api/registration/list看诊模块是/api/diagnosis/create。尤其注意挂号模块的service层编排顺序。提交挂号时要完成五件事校验排班状态和号源、检查用户是否重复挂号、执行扣减SQL、创建挂号订单、返回订单号。这五步要在同一个事务里执行加入Transactional注解否则扣减成功但订单创建失败数据库会留下脏数据。真正做项目时我发现事务是新手最容易忽略的一个方法里两次写库操作之间抛异常前面成功了后面失败了整个业务就不完整了。4. 前端核心Vue环境搭建与页面落地4.1 Vue环境准备前端环境第一步是Node.js版本这里有个很重要的经验Vue CLI项目在Node 16环境下最省心Node版本太高或太低都会出现依赖安装异常。如果你拿到的是Vue3项目Node 18以上也可以跑但老项目建议固定在Node 16。命令行里先检查node -v和npm -v确认版本再开始装依赖。创建项目我用Vue CLI而不是Vite因为毕设生态里的Element UI组件库和Vue2配合最成熟参考资料也多。命令是vue create hospital-frontend选择Manually select features勾选Vue Router其余选项保持默认。安装依赖的环节经常有人卡在node-sass上我的建议是不要用node-sass直接使用sass包也就是Dart Sass安装快而且不依赖编译环境。前端目录结构要提前规划清楚。views按角色建三个子目录patient、doctor、admin每个目录放对应页面。components放可复用组件比如排班日历、状态标签。api目录放接口封装文件一个模块一个文件。router目录统一管理路由。utils目录放token存取、日期格式化等工具方法。这样一个结构写进论文的“系统实现”章节也显得规范。4.2 前端路由与登录守卫路由设计直接关系到权限控制。前端路由分三类公共路由如首页、登录页、注册页患者路由如选择科室、选择排班、我的挂号医生路由如我的排班、待就诊列表管理员路由如科室管理、医生管理、排班管理、统计报表。我的做法是在路由meta里标注roles字段前端路由守卫里做跳转判断。router.beforeEach((to, from, next) { const token localStorage.getItem(token) const role localStorage.getItem(role) if (to.meta.requiresAuth !token) { next(/login) } else if (to.meta.roles !to.meta.roles.includes(role)) { next(/403) } else { next() } })这一步把前端路由和后端接口做了双重权限控制。前端控制的是用户看到的页面后端控制的是用户调用的接口面上一套、数据一套答辩时把这两层逻辑分开说就非常清楚。很多同学的毕设只在后端做了限制前端菜单还全部显示演示时切换账号能看到不属于自己的菜单观感很差。4.3 Axios封装与跨域方案不要在每个页面里直接调用axios建议在api目录封装一个request.js统一管理。核心是配置baseURL、请求超时时间、请求拦截器和响应拦截器。请求拦截器里从localStorage取出token放到请求头Authorization字段响应拦截器里判断Result的code非200统一弹出错误提示同时处理后端返回401时跳转登录页。跨域问题在前后端分离开发阶段无法避免。我推荐最简单可靠的方式在后端单独写一个跨域配置类允许所有来源访问接口并且在SpringBoot配置中放行OPTIONS请求。前端开发环境不需要额外做接口转发配置。生产环境部署时如果前后端放在同一个服务器上可以直接把前端打包后的dist目录复制到后端静态资源目录用同一端口访问彻底绕开跨域。Configuration public class CorsConfig implements WebMvcConfigurer { Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping(/**) .allowedOriginPatterns(*) .allowedMethods(GET, POST, PUT, DELETE, OPTIONS) .allowedHeaders(*); } }开发时前端请求路径写成http://localhost:8080/api开头只要后端允许跨域axios的baseURL写成/api再加后端完整地址。部署时所有请求走同一域名不需要额外的转发规则这是我认为毕设阶段最省心的一套方案。4.4 关键页面交互实现重点说三个页面。第一个是排班列表页页面需要根据日期筛选出当天所有出诊医生和剩余号源。前端用el-table展示剩余号源为0时禁用挂号按钮。这个页面的难点在于日期选择后要重新请求接口所以后端接口要支持按日期查询返回医生姓名、科室、时间段、费用、剩余号源。第二个是挂号确认页用户选择时段后进入确认页需要展示医院名称、科室、医生、日期、时段和挂号费用。提交时先调用后端挂号接口成功后模拟支付把订单状态改成已支付。模拟支付的逻辑是后端再提供一个支付接口或者挂号接口里直接默认已支付用订单号去关联。第三个是医生看诊页这是体现系统业务闭环的核心页面。医生登录后看到今天自己的排班和待就诊患者列表点击某个患者进入看诊详情。页面顶部显示患者姓名和挂号信息中间是病历表单医生填写主诉、现病史、诊断结果最后提交。提交成功后后端把挂号订单状态改为已完成同时写入就诊记录。患者端刷新个人中心就能看到这次就诊记录。5. 本地运行与打包部署实操5.1 本地快速跑通整套系统一套毕设项目落到本地要经过四个步骤每一步我都会详细说明。第一步是准备环境JDK 8、Maven 3.6以上、MySQL 5.7或8.0、Node 16。我建议MySQL直接用安装包版配置root密码时全过程录屏后续部署文档里能用上。第二步导入数据库新建一个hospital数据库字符集选utf8mb4通过Navicat或命令行导入hospital.sql导入完成后打开表确认科室、医生、排班等初始数据都在。第三步修改后端配置。打开application.yml文件重点是修改datasource里的url、username、password。如果MySQL是8.0版本url里要加时区参数spring: datasource: url: jdbc:mysql://localhost:3306/hospital?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8 username: root password: 你的密码第四步启动前后端。后端在项目根目录执行mvn spring-boot:run前端在hospital-frontend目录执行npm run serve。看到沟后端启动日志里的Tomcat started on port 8080和前端编译成功提示整个系统就通了。浏览器访问localhost:8080后端、localhost:8081前端这个流程我建议在演示前完整走一遍因为这是使用频率最高的启动方式。5.2 部署打包的两种方案答辩演示最怕的就是现场环境崩。我最推荐的是把前后端合并成一个包这样只要保证8080端口可用打开浏览器就能演示。后端打包前先执行mvn package命令生成jar包。前端执行npm run build构建完成后dist目录里是静态网页文件。把dist目录里的所有内容复制到后端项目的src/main/resources/static目录下然后重新执行mvn package最后用java -jar命令启动新的jar包。访问http://localhost:8080就是完整的系统前端页面和后端接口都在同一端口不存在跨域问题。这种部署方式非常适合答辩演示也适合打包发给老师评审。如果导师要求前后端分开部署方案则是后端jar包放服务器前端dist目录单独放前端服务器上把/api开头的请求转发到后端地址。此时要注意把前端api封装文件里的baseURL从/api改成后端实际地址或者在后端保持跨域开放。两种方案我会在部署文档里都写但我的建议是用打成一个jar的方式减少变量。5.3 版本兼容性三大坑我还是要强调版本问题因为太多人挂在版本兼容上。第一个坑是JDK版本与SpringBoot版本不匹配。SpringBoot 2.7配JDK 8不要升级SpringBoot 3.x必须用JDK 17否则启动直接报错。第二个坑是MySQL驱动。MySQL 8需要com.mysql.cj.jdbc.Driver写法是driverClassNameMySQL 5.7用com.mysql.jdbc.Driver。如果驱动写错启动时会报ClassNotFoundException。第三个坑是MyBatis-Plus版本。适配SpringBoot 2.x的是3.5.3或3.5.4如果pom里的版本是3.5.5以上且SpringBoot是2.x启动时可能报SqlSessionFactory创建失败。遇到这种问题优先检查pom依赖版本而不是浪费时间改代码。前端方面最常见的坑是Element UI版本和Vue版本不匹配Vue2配element-uiVue3配element-plus混用会导致页面空白并且控制台报错。这些坑在部署文档里提前写明能省掉大量自己排查的时间。6. 高频问题排查与答辩准备6.1 各环节故障速查运行过程中我把最常见的故障整理成了一张表按照后端、前端、数据库三种场景分类遇到问题直接按表排查。现象原因解决办法后端启动失败端口被占用8080端口已被其他进程占用命令行执行netstat -ano找到占用进程结束进程后重新启动数据库连接失败Access denied数据库密码与application.yml不一致核对datasource的用户名密码确认连接的是本机端口3306前端npm install卡住或报错Node版本与依赖不兼容卸载重装Node 16删除node_modules后重新执行npm install登录接口报401未授权拦截器排除了登录接口但token为空或失效检查前端请求拦截器是否将token放到了Authorization请求头数据库中文乱码数据库字符集不是utf8mb4修改数据库字符集重新导入SQL导入前确认字符集设置前端请求404后端接口路径错误或未启动检查后端启动日志直接浏览器访问该接口URL验证后端是否通项目打不开提示找不到主类IDEA未正确识别Maven项目或JDK配置错误重新执行mvn clean install核对Project Structure里的JDK版本我用这套表排查问题的场景很多核心思路是先确定是前端问题、后端问题还是数据库问题。最忌讳的是看到报错就来回改代码先缩小范围比如后端接口用浏览器直接访问如果同一个URL浏览器能返回JSON那问题就出在前端请求上这样排错效率高很多。6.2 答辩高频问题速答医院挂号系统在答辩时被问得最多的问题有七类我把回答思路整理在这里。为什么选择SpringBoot而不是Spring MVC回答方向是SpringBoot自动配置减少XML配置内嵌Tomcat便于独立运行配合Spring生态做接口开发效率更高。为什么用JWT不用Session回答方向是前后端分离架构下Session不便于跨端共享JWT无状态、扩展性好适合接口鉴权。号源超卖怎么解决的回答方向是SQL条件更新加事务用剩余号数大于0作为更新条件DB行锁保证原子性。同一个患者重复挂号怎么控制回答方向是用户ID和排班ID联合唯一索引插入时冲突会抛异常再在service层做业务提示。密码怎么存储回答方向是BCrypt加盐哈希数据库不存明文。系统如何做权限控制回答方向是前端路由守卫控制页面可见性后端JWT拦截器加角色判断控制接口访问。如果并发量很大你会怎么做回答方向是加Redis做计数缓存、消息队列削峰、数据库主从分离表明你理解这些技术的大致作用即可。这些问题都不需要背长篇答案关键是把设计思路讲清楚尤其是超卖和重复挂号这两个问题和数据库设计2.2小节里的内容完全对得上评委一听就知道是你自己做过的。如果你的系统里用了SpringBoot自动填充时间之类的细节也可以主动提一句引导评委往你熟悉的方面问。6.3 论文章节组织与演示脚本论文结构直接决定老师的第一印象建议按标准软件工程文档顺序写。第一章绪论讲研究背景、国内外现状、研究内容。背景部分不要空谈国家政策要写“传统人工挂号排队效率低、信息不透明”这种贴近实际的问题。第二章需求分析写可行性分析和用例图把三类角色的功能点全部列出来使用用例表格。第三章讲技术选型每项技术都要写出对比比如为什么选Vue而不选React。第四章系统设计是最重要的章节包含总体架构图、功能模块图、数据库ER图和主要表结构。数据库部分把七张核心表的字段含义写全重点描述排班表的设计思路和唯一索引约束。第五章系统实现每一个模块配一张运行截图和一段关键代码代码不用贴全但一定要贴有技术含量的部分比如号源扣减SQL、JWT拦截器、Vue路由守卫。第六章系统测试写出测试用例表和测试结果覆盖三类角色主要功能。最后是总结、参考文献和致谢。答辩演示脚本一定要提前写好并按顺序排练。我的建议脚本是第一步管理员登录演示科室列表和医生管理新增一个科室第二步进入排班管理给医生添加一个明天的排班第三步退出管理员注册一个患者账号第四步以患者身份选择科室、医生、日期和时段挂号并模拟支付第五步退出患者用医生账号登录看到待就诊列表点击开始看诊并填写病历第六步退出医生用患者账号查看就诊记录第七步切回管理员查看挂号统计。每一步的截图都要提前准备现场操作万一出现问题用截图兜底。写在最后在医院挂号就诊系统这个题目上自己从零做一遍最大的收获不是“会用了SpringBoot”而是明白一个业务闭环需要哪些角色、哪些状态、哪些约束共同支撑。做项目遇到卡点的时候比如号源扣除、重复预约、跨域、打包部署先去想业务上该怎么办再去想技术怎么实现思路会清晰得多。这套项目跑通之后往里面加排队叫号、加号退号、短信提醒、Excel导出都是顺手就能做到的事。最后提醒一句答辩前特意在一台干净环境的机器上把启动命令完整跑一遍比背很多演示话术都管用。
返回列表