ARTICLE DETAIL

资讯详情

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

SpringBoot+Vue+MySQL医院挂号就诊系统设计与实现

SpringBoot+Vue+MySQL医院挂号就诊系统设计与实现 医院挂号就诊系统这个题目在计算机毕业设计里属于“常见但永远不过时”的一类。用SpringBootVueMySQL来做的同学尤其多因为技术栈主流、代码量适中、答辩时容易讲清楚。我最近把一套完整的医院挂号就诊系统源码、数据库脚本、论文和部署文档重新整理成可复用的标准版本过程中也陪不少同学排查过运行问题。今天这篇文章不聊虚的直接说清从选题到落地的关键细节为什么选这个技术栈、数据库怎么设计才不容易出现超挂、后端事务怎么处理、前端页面怎么对接、最后怎么部署、怎么写论文。适合正在选毕设题目或者已经定了题目但还没有完整实现思路的同学参考。1. 项目定位与方案选型1.1 为什么选SpringBootVueMySQL先说说技术栈的合理性。SpringBoot 2.x搭配JDK 8是过去几年Java后端开发里最经典的组合。它免掉了大量XML配置内置Tomcatmvn clean package之后打出一个可执行的Jar包服务器上扔一条java -jar命令就能跑起来。Vue用来写前端页面组件化的开发方式非常适合这种多页面系统配合Element Plus或Element UI的表格、表单、日历组件后台管理界面半天就能搭出雏形。MySQL属于关系型数据库医院挂号系统里科室、医生、排班、挂号记录之间都是清晰的一对多关系用关系型表结构来表达最自然。除了技术本身的优势还有一个很务实的理由这套组合在课程设计、实习项目、网上资料里出现频率太高了。你遇到任何报错基本都能搜到现成答案老师也熟悉这套生态答辩时不会因为框架冷门而多问一堆你没准备过的问题。相比SSH框架、JSPServlet这类老方案前后端分离也是现在的主流做法相比SpringCloud微服务单体应用对这个题目的业务复杂度又完全够用。选这套技术不是因为它多高级而是因为它足够稳、足够常规、足够让你把精力集中在真正的业务逻辑上。版本选择上给个建议SpringBoot用2.7.xJDK用1.8MySQL用5.7或8.0都可以。如果本机Node环境比较新前端直接用Vue3 Vite Element Plus如果机器比较旧或者想更稳妥Vue2 vue-cli Element UI也能跑。不要为了追新去选SpringBoot 3它要求JDK 17MyBatis-Plus等适配版本也变了反而容易给自己增加环境成本。1.2 功能范围别把毕设做成商业项目很多同学拿到题目就想着把线上挂号系统做得越全越好支付、短信验证码、在线问诊、排队叫号全都想加进去。我的建议是收着做核心业务跑通比功能堆砌重要得多。这套系统建议做成三个角色患者、医生、管理员。患者端要能注册登录、维护个人信息、查看科室和医生、查看医生排班、选择时间段预约挂号、查看自己的挂号记录以及取消挂号。医生端要能查看自己的排班、看到挂了号的患者列表、填写简单的就诊记录。管理员端负责科室管理、医生账户管理、排班管理、挂号记录查询统计。把这些功能全部做扎实已经是一个完整且工作量饱满的毕业设计了。支付、短信、电子病历报告这些扩展功能除非你技术功底非常强否则先放着。它们不仅会增加大量异常处理的复杂度还容易在答辩时把老师注意力引向“支付安全怎么做”“短信服务怎么配置”这些不好回答的追问上。毕设不是商业投标把预约流程讲清楚把数据库事务和并发问题处理明白已经很出彩。1.3 开发前先画好“地图”我见过很多直接把源码跑起来就开始改代码的同学结果越改越乱。正确顺序应该是先做设计再动手写代码。具体来说先画用例图把三种角色和各自的操作用例列出来。再画ER图和表关系图至少把核心表结构定到第三范式。然后列接口清单比如POST /api/user/login、GET /api/department/list、GET /api/schedule/list?doctorIdxxx、POST /api/registration/submit、POST /api/registration/cancel每个接口的入参出参都写清楚。最后再确定开发顺序搭建前端后端骨架实现登录注册实现科室医生排班的CRUD实现挂号核心业务再做个人中心和后台统计最后联调测试。这套流程走完你对系统的理解已经超过一大半只想着写代码的同学。后面写论文的时候这些设计文档直接就能变成论文里的用例图、功能结构图和接口说明。2. 数据库设计与核心模块拆解2.1 五张核心表把业务串起来数据库是整个系统最值得花时间设计的地方。我见过不少项目把患者和医生塞在一张表里把排班和挂号混在一起后期代码写起来非常痛苦。这套系统建议至少拆出六张核心表用户表、科室表、医生表、排班表、挂号表、就诊记录表。用户表记录公共的账号信息医生也可以注册为一种用户再通过医生表去扩展医生专属字段。这样登录鉴权逻辑只需要写一套。科室表、医生表、排班表、挂号表、就诊记录表的关系如下表名核心字段说明userid, username, password, name, phone, id_card, role患者、医生、管理员共用departmentid, dept_name, dept_desc医院科室doctorid, user_id, dept_id, real_name, title, specialty, intro扩展医生信息scheduleid, doctor_id, work_date, time_slot, total, remaining医生某天的号源registrationid, user_id, schedule_id, order_no, appointment_date, time_slot, status挂号记录status0待就诊1已完成2已取消medical_recordid, registration_id, diagnosis, suggestion就诊记录用户表单独拆出来而不是把医生姓名、工号直接塞进user表是为了让患者和医生都能复用注册登录逻辑。再用doctor表关联user_id和dept_id既保持了范式也方便扩展医生的职称、擅长领域、个人介绍等信息。2.2 表关系与索引设计从表关系上看department和doctor是一对多一个科室有多名医生doctor和schedule是一对多一个医生有多个日期的排班schedule和registration是一对多一个排班可以被多个患者挂号但因为号源限量实际是一条排班对应多条挂号记录user和registration是一对多一个用户可以有多个挂号记录。就诊记录和挂号记录是一对一一个挂号对应一份就诊记录。物理外键要不要加很多企业项目不喜欢加物理外键因为会带来额外的锁开销和删除限制。但毕业设计为了图表好看也可以在表定义时保留外键关系或者在ER图里画出来代码层面用逻辑外键关联。我更推荐逻辑外键加普通索引既不影响演示删除数据时也省去外键约束的麻烦。索引这块要提前设计好。按科室查医生按医生查排班按用户查挂号记录这些都是高频查询。建议给doctor.dept_id、schedule.doctor_id、schedule.work_date、registration.user_id、registration.schedule_id建普通索引。数据量不大时可能感觉不到差别但答辩时能讲出“我在这里建索引是因为这个字段经常出现在WHERE条件里”说明你懂数据库优化。2.3 号源扣减并发问题才是核心预约挂号本质上是一个库存系统。排班表里有total和remaining两个字段total表示该时段总号源remaining表示剩余可挂数量。这里最容易出错的就是多人同时抢最后一个号的场景。错误做法是先查remaining判断大于0后再执行remaining remaining - 1然后插入挂号记录。两个并发请求可能同时读到remaining等于1都认为自己能挂号最后都创建记录号源就超卖了。正确的做法是在事务里直接执行一条条件更新update schedule set remaining remaining - 1 where id ? and work_date curdate() and remaining 0;这条语句满足remaining 0才会扣减成功数据库行锁会保证并发场景下只有一个请求能更新成功。如果受影响行数为1继续创建挂号记录如果为0直接提示“号源不足”。同时为了彻底防止同一个用户对同一个排班重复预约在挂号表上再加唯一约束alter table registration add unique key uk_user_schedule(user_id, schedule_id);这样即使极端并发下两个请求都穿透了扣号逻辑唯一约束也会拦住重复插入。用户取消挂号时要在同一个事务里把挂号状态改成已取消再执行remaining remaining 1把号源释放回去。这些细节写进论文里就是很好的“系统如何保证数据一致性”的体现。3. 后端核心功能实现3.1 工程初始化和项目结构后端建议直接用IDEA的Spring Initializr创建或者去start.spring.io生成。项目名可以叫hospital-backend打包方式选JarJava版本选8。依赖方面Web、MySQL Driver、Lombok直接勾选MyBatis-Plus和JWT的依赖手动加入pom。MyBatis-Plus版本建议用3.5.xJWT用jjwt 0.9.1。application.yml里的数据源配置是很多同学启动失败的集中区直接给一份可用的server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/hospital_db?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: root password: your_password这个连接串里两个容易被忽略的地方是serverTimezone和allowPublicKeyRetrieval。前者解决MySQL 8的时区报错后者解决MySQL 8默认加密插件导致的连接失败。没有这两项项目启动时经常报“The server time zone value”或者“Public Key Retrieval is not allowed”。后端目录结构建议按这种分层来组织config放WebMvcConfig、跨域配置、拦截器配置controller接口层service业务逻辑mapperMyBatis-Plus的Mapper接口entity数据库实体dto/vo入参出参对象common统一返回结果、全局异常处理器、JWT工具类统一返回结果类用ResultT包含code、message、data三个字段。接口成功返回code为0业务失败返回错误码和提示信息。这样前端axios响应拦截器只需要判断code不用每个接口单独处理异常。3.2 登录鉴权与角色控制登录鉴权这块我建议直接用JWT手写一个拦截器不用非要引入Spring Security。Spring Security虽然功能强但配置复杂对毕设来说是个负担。流程是这样用户登录时根据用户名查出用户校验密码这里要强调密码不能明文存储至少用MD5加盐或者直接用Spring Security里的BCryptPasswordEncoder。校验通过后生成tokentoken里放userId和role返回给前端。前端后续请求在请求头带上Authorization: Bearer token。后端写一个HandlerInterceptor拦截所有非白名单请求。白名单一般是/api/user/login、/api/user/register以及前端静态资源。拦截器里解析JWT失败就返回401成功就把userId放进request attribute方便controller里获取当前登录人。管理端接口再额外校验角色简单做法是判断请求路径前缀比如/api/admin/**只允许role为ADMIN的请求通过。这段逻辑不复杂但它是整个系统的安全基础。论文里可以配上时序图展示用户携带token访问接口的完整流程答辩时非常有说服力。3.3 预约挂号业务流实现要点预约挂号是核心业务代码结构一定要清晰。建议在Service层写一个挂号提交方法并用Transactional保证事务性。核心流程可以分几步校验排班是否存在、是否过期。调用Mapper里写的减号源方法执行条件更新。如果更新影响行数为0抛出业务异常提示号源已满。如果更新成功创建挂号记录设置userId、scheduleId、orderNo和状态为待就诊。插入挂号记录。全部做完事务提交。这里的关键是减号源和插入挂号记录必须在同一个事务里。如果把扣号放在一个事务插入记录放在另一个事务一旦插入失败号源已经被扣掉数据就不一致了。使用默认的REQUIRED传播行为就能保证它们在一个事务里。取消挂号类似修改挂号记录状态之前先查询这条挂号记录确认属于当前用户且状态为待就诊然后更新状态为已取消再对排班表执行remaining remaining 1。取消操作同样需要事务保护避免出现状态改了但号源没加回去的情况。业务异常要统一处理。写一个BizException配合RestControllerAdvice的全局异常处理器返回统一的code和message。前端弹出提示时就不用处理各种后端异常结构了。3.4 MyBatis-Plus还是Spring Data JPA我在整理这套系统时接触过不少同学的原始代码有人用JPA有人用MyBatis都能跑通。但如果让我推荐我更倾向于MyBatis-Plus。MyBatis-Plus对单表CRUD非常省事BaseMapper自带了selectById、insert、updateById这些方法完全不用手写SQL。涉及单据查询时用LambdaQueryWrapper就能拼出动态条件。比如按科室查询医生LambdaQueryWrapperDoctor wrapper new LambdaQueryWrapper(); wrapper.eq(Doctor::getDeptId, deptId); return doctorMapper.selectList(wrapper);再比如分页配置一个MybatisPlusInterceptor分页插件查询时传入Page对象就行。整套代码写下来非常直观答辩时也好解释。Spring Data JPA在实体关系上确实写起来优雅但多表动态查询需要组合Specification懒加载在Jackson序列化时也容易出现LazyInitializationException需要额外处理。对毕设这种数据量不大、业务边界清晰的系统MyBatis-Plus的简单直接是更稳定选择。4. Vue前端开发与交互4.1 页面与路由设计前端部分如果是Vue3项目用Vite创建工程UI库选Element Plus状态管理用PiniaHTTP请求用Axios。如果之前一直用的是Vue2继续保持Vue2 Element UI也没问题逻辑是一样的。页面整体分前台和后台两块。前台是患者使用的门户包括登录注册、首页、科室列表、医生列表、医生排班、预约确认、我的挂号记录。后台是管理和医生使用的操作界面包括科室管理、医生管理、排班管理、挂号记录管理。路由建议统一规划例如/login登录/home首页/department科室列表/doctor/:deptId某科室下的医生列表/schedule?doctorIdxxx某医生的排班/appointment/:scheduleId预约确认/my/records我的挂号记录/admin/schedule排班管理路由守卫要做但只能作为前端体验优化。每次跳转前检查localStorage里有没有token没有就跳登录页访问管理端路由时检查用户角色不是管理员就跳回首页。前端守卫无法真正保证安全但能让不合适的用户少做一次无效请求。4.2 axios封装与跨域处理axios封装是前端必做的基础工作。在utils/request.js里创建一个实例设置baseURL: /api请求拦截器自动把token加到请求头响应拦截器统一判断状态码。如果是Vite开发环境在vite.config.js里配代理把/api转发到后端地址server: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } }如果是Vue2的vue-cli区别只是在vue.config.js里配置devServer.proxy。这样做的最大好处是开发时不需要后端单独配置CORS前端请求从页面上看都是同源的避免跨域带来的各种麻烦。后端接口返回统一是Result结构响应拦截器里可以对业务码做统一处理。比如code为401时跳到登录页code为其他业务错误时用ElMessage弹出后端返回的message。前端页面里就不用每个请求都写一遍错误提示逻辑了。4.3 排班日历和挂号表单的交互细节排班页是整个前端交互最复杂的页面。后端提供的接口一般是GET /api/schedule/list?doctorIdxxx返回这个医生未来7天的排班列表字段包括日期、时间段、剩余号数。前端拿到后按日期分组展示用户可以点某个时间段看到剩余号再点“预约”弹出确认对话框。对话框里尽量自动带出当前用户数据比如就诊人姓名、手机号、身份证号这些信息从用户信息接口获取。用户只需要确认医生、日期、时间段减少填写成本。点击提交时要加一个loading状态防止用户连续点击导致重复请求。页面上要处理一个细节已经过去的日期或者剩余号数为0的时间段按钮要置灰或者直接不渲染。前端只是体验优化真正能否挂号以后端校验为准所以前端把按钮禁用了后端仍然要判断work_date curdate()。取消挂号的交互也需要二次确认。点“取消预约”后弹出确认框确认后调用取消接口成功之后刷新列表剩余号数动态更新。注意接口返回后重新拉取排班信息而不是本地给剩余数减一避免状态不一致。5. 部署与常见问题排查5.1 本地环境准备与版本选择部署是很多同学最后卡壳的地方尤其是一些看起来不起眼的环境问题。建议本地环境按照这套配置来统一工具建议版本说明JDK1.8SpringBoot 2.x最佳搭档Maven3.6以上后端依赖管理MySQL5.7.44或8.0.x导入.sql建库Node.js16前端构建需要IDEIDEA开发调试方便安装完先自查一遍版本java -version、node -v、mysql --version、mvn -v都正常再继续。关于MySQL安装如果遇到“Start Service”失败常见原因是3306端口被占用或者data目录没有初始化。可以删除data目录后以管理员身份打开命令行执行mysqld --initialize-insecure然后net start mysql再试。初始化时用了--initialize-insecure默认root密码为空登录后可以用alter user rootlocalhost identified by 你的密码;设置密码。5.2 打包、部署与初始化数据库前端后端分离部署现在很成熟流程可以固定下来先导入数据库。用Navicat或命令行执行hospital.sql注意建库字符集选utf8mb4避免中文乱码。然后改后端application.yml里的数据库账号密码。接着打包后端在hospital-backend目录下执行mvn clean package -DskipTests java -jar target/hospital-backend-0.0.1-SNAPSHOT.jar后端默认跑在8080端口可以先用浏览器访问http://localhost:8080/api/department/list确认接口是否正常。前端打包cd hospital-frontend npm install npm run build打包后生成dist目录。演示部署有两种常见方式。第一种最简单把dist目录里的文件拷贝到Spring Boot项目的resources/static目录下重新打包后端然后直接访问8080端口同一个端口既能访问静态页面也能访问接口。这种方式需要注意前端的路由跳转建议使用hash模式否则刷新页面时后端没有对应的路由映射会出现404。第二种是更正规的Nginx部署。把dist目录放到Nginx的html目录配置反向代理把/api开头的请求转发到后端8080端口location / { root /usr/share/nginx/html; try_files $uri $uri/ /index.html; } location /api { proxy_pass http://127.0.0.1:8080; }如果前端路由用的是history模式try_files那行必不可少它的作用是刷新任意前端路径时都回退到index.html再由前端路由接管。如果你在云服务器上部署记得在安全组放行80或8080端口。MySQL的3306端口不要对公网开放用Navicat做本地连接就够了。5.3 常见问题速查表下面的表格是从我排查过的N多运行问题里整理出来的几乎覆盖了90%的毕设卡壳点。现象原因处理方法后端启动报端口占用本机8080端口被其他程序占用修改application.yml的端口或查占用进程并结束Access denied for user数据库账号密码不对或root用户host限制检查application.yml确认MySQL用户和密码Communications link failureMySQL服务没启动或URL写错启动MySQL服务检查url的host和portPublic Key Retrieval is not allowedMySQL8驱动默认加密插件导致url加allowPublicKeyRetrievaltrueuseSSLfalseThe server time zone value unrecognized连接串缺serverTimezoneurl加serverTimezoneAsia/Shanghai前端请求接口404前端代理没配置或后端路径不匹配检查/api前缀和后端RequestMapping地址刷新页面404前端history路由缺少后端fallback用hash路由或给Nginx配置try_files中文乱码数据库字符集和连接字符集不一致建库用utf8mb4url加characterEncodingutf8前端打开是白屏静态资源路径错误或构建失败重新执行npm run build检查dist目录是否正确排查时记住一个原则看后端日志不要只看最前端的信息重点找Caused by后面的原因。很多同学被一大段堆栈吓住其实真正原因往往只有最后一到两行。还有一点环境变量PATH里如果有多个JDK版本命令行里java -version和IDEA里的JDK版本可能不一致尽量统一版本。6. 毕业论文与答辩准备6.1 论文目录和写作重点论文建议按这个结构来写摘要、Abstract、目录第1章绪论写背景意义、国内外现状、本文主要工作第2章相关技术介绍把SpringBoot、Vue、MySQL、前后端分离分别介绍第3章需求分析写可行性分析、角色分析、功能需求和非功能需求配上用例图第4章总体设计写系统架构图、功能模块图、数据库设计这是重点章节第5章详细设计与实现按登录模块、挂号模块、排班模块来写每个模块先描述业务逻辑再配核心代码和界面截图第6章系统测试设计测试用例表并给出测试结果第7章总结与展望。写的时候注意不要大段大段贴源码。论文是展示设计思路的不是代码阅读材料。每段核心代码控制在二三十行以内配合一两句话说明关键逻辑。数据库表结构要么画表格要么用ER图展示。整个论文里图表质量越高老师越容易觉得你确实做了系统。6.2 图表素材可以这样准备图表工具不要求多专业ProcessOn、draw.io、Visio都可以。用例图、ER图、时序图、功能结构图这四类是论文需要的核心素材。用例图用来表达三种角色和操作范围。ER图用来表达表与表之间的关系你按照第2节里的表关系去画就行。时序图建议画一个“预约挂号流程”从用户请求开始到前端校验、后端校验、扣减号源、创建记录、返回结果一目了然。功能结构图用普通的方框层级表示首页、科室管理、排班管理、挂号管理等模块的分支。界面截图一定要干净。先把浏览器窗口调成固定尺寸比如1366x768登录后截取每个页面不要带书签栏和无关标签页。后台管理页面截图前把示例数据填得整齐一些比如医生姓名、职称、排班日期都使用真实感强的数据不要留个“张三”就交差。截图在论文中要有编号和标题比如“图5-1 患者首页界面”。6.3 答辩被问频率最高的几个问题答辩现场说白了就是检验你是不是真的做了系统。下面几个问题几乎每次都会被问到提前准备答案为什么选用SpringBootVueMySQL直接回答生态成熟、前后端分离、本地部署简单、资料丰富适合快速实现一个业务清晰的系统。这个答案已经足够。挂号并发时怎么保证不超卖把第2节里那条条件更新SQL和唯一约束讲清楚再补充一句“扣号源和创建挂号记录在同一个事务里”这个问题就能拿高分。JWT登录状态是怎么维护的讲登录时生成token前端每次请求携带后端拦截器解析验证管理端接口再校验角色。不要干背概念最好能打开代码页面指着拦截器的逻辑讲。要是被问到“你这里有什么不足吗”不要慌。可以说当前系统没有实现在线支付、消息通知、门急诊叫号等扩展功能原因是毕业设计周期和复杂度控制如果要进一步完善可以往这些方向扩展。这样既回答了问题又显得你有意识。最后提醒一句源码可以借鉴但务必自己动手把关键流程跑一遍。答辩时老师问的都是代码里细节你亲手写过的逻辑和被源码带过的逻辑回答时候的底气完全不一样。我个人觉得这套医院挂号就诊系统最好的地方是它把很多看似独立的知识点串成了一个整体前端路由、后端拦截器、数据库事务、并发控制、打包部署每一样单独拿出来都不难但串起来就是一次完整的项目历练。你按默认配置把它跑通再自己动手把预约流程改一遍、加一个字段比反复看视频教程要管用得多。做毕设最忌讳的是代码还没跑通就开始写论文顺序反了后面所有时间都会耗在返工上。先把这条路完整走一遍你收获的绝不只是一个毕业设计。
返回列表