news 2026/10/21 16:33:23

医院挂号就诊系统全栈实战:SpringBoot+Vue+MySQL毕设指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
医院挂号就诊系统全栈实战:SpringBoot+Vue+MySQL毕设指南

1. 这个选题为什么值得做:先搞清楚它解决什么问题

很多人在挑毕业设计题目的时候,第一反应是往“高大上”的方向冲——图像识别、推荐算法、语音交互。结果呢,算法原理讲不明白,工程实现做不出来,最后只能到处找现成代码硬糊,答辩的时候被问两句就露馅。我在帮人改毕设的这几年里,见过太多这种情况了。

“医院挂号就诊系统”这个选题看起来不起眼,但它是一个非常典型的全栈工程类项目,对普通本科学生来说,性价比其实很高。它不需要多高深的算法,也不需要多复杂的数学基础,但它把企业级开发里最常见的那套东西串起来了:SpringBoot做后端接口、Vue做前端页面、MySQL存业务数据,再加上登录鉴权、权限区分、表格分页、状态流转、部署上线这些真实项目中的高频场景。

这个题目的核心价值在于:它是一套完整闭环的业务系统。挂号、排班、医生接诊、患者就诊、收费、药品管理、后台看板,每一个环节都有明确的数据流动和状态变化。你在做需求分析的时候能讲清楚“患者—医生—管理员”三个角色的边界,在设计表结构的时候能讲明白“号源怎么锁、排班怎么排、订单怎么跟”,在写接口的时候能练到“怎么写RESTful风格、怎么处理跨域、怎么统一返回结构体”。这些能力,恰恰是毕业后找Java后端或者全栈开发岗时面试官最看重的。

从项目完成度来说,这个系统涉及到的代码量、数据表数量、页面数量都处在一个“半年内能做完”的合理范围内,不会像一般的小工具一样三张表就结束,也不会像大型商城项目那样拖到答辩前还收不了尾。对某个学院的信息管理与信息系统专业来说,我见过至少三个人用它拿过不错的分数。

那这个系统到底长什么样?简单说:患者端是一个面向公众的挂号平台,能够按科室、按日期、按医生查排班、挂号、取消号、看候诊状态,还附带个人中心里查历史挂号记录;医生端是一个接诊工作台,看到当天的候诊列表,完成签到、开检查单、开处方、写诊断;管理端是给院内管理人员用的,负责科室管理、医生排班管理、号源池配置、用户管理、数据看板等。

在整个技术栈里,SpringBoot负责提供RESTful接口和数据访问层,Vue负责把接口数据渲染成用户能点击、能填写、能实时反馈的页面,MySQL负责持久化保存所有业务数据。前后端分离的架构也让代码的耦合度大幅降低——前端改样式不会碰坏后端逻辑,后端改接口不影响前端页面打包,分工明确,非常贴近真正的工作场景。

这篇文章我会从架构设计、数据库设计、核心功能拆解、部署落地、论文写作、答辩指引这几个角度,完整地讲清楚这个项目里每个关键细节是怎么做的。文中的工程路径、命令、代码片段我都按实操来写,标题里提到的“源码+数据库+论文+部署文档”四件套,我会穿插着说明它们在我日常开发中各自承担什么角色。

2. 技术选型背后的权衡:为什么是SpringBoot+Vue+MySQL

2.1 后端选型:SpringBoot带来的低门槛和生态红利

先说后端。国内的SpringBoot能成为毕业生项目默认选项不是没有原因的,它最核心的优点是极大降低了配置成本。传统Spring项目那一大堆XML配置是很多初学者的噩梦,而SpringBoot的自动配置机制把这些常见的“组装过程”全垫好了,你只需要在application.yml里写几行数据源信息,它就帮你把内嵌Tomcat、MyBatis或MyBatis-Plus、拦截器、全局异常处理都准备好。

以我比较常用的组合为例,后端pom.xml里核心依赖大概是这些:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>

这里我想特别说下为什么用MyBatis-Plus而不是Spring Data JPA。虽然两者都能实现数据库访问,但MyBatis-Plus更贴近国内开发者的思维习惯:SQL放在Mapper层写在XML文件里,你可以清晰地看到每一条操作的数据库语句;它的BaseMapper内置了insert、update、selectById这些基础方法,代码比JPA的抽象风格更直白;分页查询只要配一个拦截器再加一个Page对象就能搞定,贼顺手。

2.2 前端选型:Vue为什么比JSP时代先进了一整个世代

老一代的“课程设计系统”很多还是JSP+Servlet直接渲染页面,那种做法最大的问题是前后端耦合死重——后端要操心页面逻辑,前端要懂Java语法,改一个按钮都要重启服务器。Vue的设计思路完全不一样,它把“数据驱动视图”做到了极致:你在script里定义一个数组,页面上的表格会自动渲染出这些数据;用户点一下按钮,触发的是Vue实例里的方法,方法再去调后端的接口,接口返回了数据,视图自动更新。

对于医院挂号系统这个场景,前后端分离还带来了一个隐形好处:调试效率高。后端接口写完可以直接用Postman测出参入参,不需要先写页面再来验证接口有没有通;前端页面布局可以用本地Mock数据去调,不用等后台开发完才能推进。学生做项目的节奏本来就紧,前后端并行开发能省下大量排队等待的时间。

前端部分的核心依赖配置,我通常会放在package.json里:

{ "dependencies": { "axios": "^1.3.0", "element-ui": "^2.15.13", "vue": "^2.6.14", "vue-router": "^3.5.2", "vuex": "^3.6.2" } }

组件库选Element-UI而不是Ant Design Vue,原因很简单:对新手友好。它的表单校验、表格分页组件、日期选择器、弹出框,很多功能只要给标签加一个属性就能用,对后端起家的人特别顺手。而且Element-UI的文档和示例非常多,照着抄一抄就能出比较规整的界面。

2.3 数据库选型:MySQL为什么是这类项目的定海神针

数据库没什么好纠结的,MySQL几乎是这个量级项目的标准答案。它的InnoDB引擎支持事务和外键约束,这对于挂号就诊系统的核心业务——挂号和退号、备药和扣库存、开单和收费——是非常关键的,因为这些操作必须保证“要么全成功要么全回滚”。如果哪次操作中途失败了、部分数据却有残留,后面业务流转就全乱套了。

还有一点容易被忽视的是MySQL的运维成本几乎为零。装好一个MySQL服务,导入一份SQL脚本,设置好账号密码,整个开发周期就不用再操心数据库这层。配合Navicat或DataGrip这种可视化工具,建表、看数据、执行查询都很直观,哪怕数据库接触不多的同学,半天时间也能熟练起来。

2.4 用户权限怎么设计:三种角色背后的思路

医院系统天然分角色,这是该毕设的一个亮点。通常我们设置三种角色:患者(普通用户)、医生、管理员。数据库里不一定非要建三张独立的用户表,更常见的做法是一张用户表加一个role字段区分角色,再根据需要建对应的医生信息扩展表和患者信息扩展表。

登录后端的处理逻辑一般是:前端把用户名密码交给/login接口,后端查库做校验,如果通过就返回一个token,并把当前角色的基本信息一并回传。前端拿到token后存到本地或Vuex里,后续每一次请求都带着这个token;后端用一个拦截器或者过滤器去验token,验过了才知道“这次请求是谁发来的、他有没有权限调这个接口”。这一整套的“无状态登录”模式,也正是现在主流前后端分离项目的标准做法。

3. 表结构设计是整个系统的地基,别急着写代码

我接触过不少急着写接口的同学,上来就建表,两张表就开干,结果没过两天就开始加字段、删字段、重新造数据,白白浪费掉很多时间,还容易埋下一堆数据隐患。这个项目的表结构,我真建议你先在本子上画一画再落到SQL里。

3.1 核心表:用户、科室、医生、排班、号源、挂号单

一张完整的医院挂号就诊系统,表结构至少应该覆盖这些核心表。我梳理一份实际工程中比较常见的建表清单:

表名职责说明关键字段
sys_user系统用户表,统一存放所有角色的登录账号id, username, password, role, real_name, phone
department科室表id, dept_name, description, sort
doctor_info医生信息表,关联sys_user和departmentid, user_id, dept_id, title, intro, avatar
schedule医生排班表id, doctor_id, work_date, time_slot, total_count, balance_count
patient_info患者信息扩展表id, user_id, id_card, medical_card_no, address
registration_order挂号订单表id, patient_id, schedule_id, order_no, status, create_time
diagnosis_record诊断记录表(就诊记录)id, order_id, doctor_id, symptom, diagnosis, advice
prescription处方表id, diagnosis_id, drug_id, dosage, usage, amount
drug_info药品信息表id, drug_name, specification, stock_count, price
payment_record收费记录表id, order_id, pay_amount, pay_status, pay_time

这十张表基本上就把这个系统的业务闭环串起来了。用户登录→选择科室→查看医生排班→锁定号源④创建挂号订单→医生查看候诊→填写诊断→开处方→患者缴费。每一步都有对应的表去承接数据,任何一环的数据都“有迹可循”。

3.2 号源设计是整个系统的灵魂,账号越用越需要谨慎

很多人第一次设计排班表的时候容易犯一个错误:用“医生上班的一天”作为最小粒度建一条记录。比如医生周一全天出诊,就在schedule表里建一条“周一 00:00-24:00”,然后挂号数直接挂在医生上。这个设计在学生项目里看着能用,但一到真实场景就露馅了——现实中医院是要分时段的:早上的号、下午的号、甚至精确到半小时一个号源。

我比较推荐的是用“时段排班”的思想:一个医生一天可能有上午/下午两个时段,甚至上午又被拆成8:00-9:00、9:00-10:00这样的时间片,每个时段生成一条排班记录,记录里带有该时段的总号数、剩余号数。患者挂号的时候,选择了某一个具体时段,对应号数的剩余量减1;退号时再加回来。这样既好实现,又方便在论文里讲“我对号源进行了细粒度管控”。

CREATE TABLE schedule ( id BIGINT PRIMARY KEY AUTO_INCREMENT, doctor_id BIGINT NOT NULL COMMENT '医生ID', work_date DATE NOT NULL COMMENT '出诊日期', time_slot VARCHAR(50) NOT NULL COMMENT '时段,如 MORNING / AFTERNOON 或具体时间片', total_count INT NOT NULL COMMENT '总号数', balance_count INT NOT NULL COMMENT '剩余号数', status TINYINT DEFAULT 1 COMMENT '0停诊 1正常', UNIQUE KEY uk_doctor_date_slot (doctor_id, work_date, time_slot) ) COMMENT '医生排班表';

这个表中的唯一索引uk_doctor_date_slot是很有用的设计:它能防止同一个医生在同一天同一时段生成重复排班。并且,当患者发起挂号的时候,不应该直接去UPDATE这个表,而应该使用一个带条件的原子操作:

UPDATE schedule SET balance_count = balance_count - 1 WHERE id = #{scheduleId} AND balance_count > 0;

如果你做成“先查余额→判断>0→再减一”,那在高并发场景下一定会出现超挂。虽然毕设答辩不一定会问到并发,但你能把这个“原子扣减”的原理讲出来,那绝对是加分项。

3.3 挂号单的状态流转:逻辑别写得像一锅粥

挂号单的状态是设计里最容易乱的地方。我建议用一张状态机图把流转画明白了再动手。我通常习惯用数字表示状态:

状态值含义说明
0待就诊已挂号成功,患者尚未就诊
1就诊中医生开始接诊,可能填写了部分诊断信息
2已完成诊断记录、诊断报告已经填完
3已取消患者主动退号或超时未就诊被系统取消
4已完成待评价如果系统支持评价功能,可增加该状态

另一种常见设定是用字符串枚举,比如“WAIT”、“DONE”、“CANCELED”,看着直白但比较容易被写出一条飘在外面的非法数据。数字的好处是排序和分页查询更灵便,坏处是可读性差。所以我们通常在实体类里写常量类去映射,比如:

public class OrderStatus { public static final Integer WAIT = 0; public static final Integer CONSULTING = 1; public static final Integer FINISHED = 2; public static final Integer CANCELED = 3; }

这样在代码里写order.setStatus(OrderStatus.CANCELED),别人读代码的时候不会看天书。

4. 环境配置常常是最容易让人绝望的环节,逐一击破

4.1 本地开发环境的黄金版本

我在帮别人排查毕业设计问题的时候发现,大量报错根本不是代码问题,而是环境版本不匹配。我列一个踩了多年坑后总结出来的稳定组合,直接抄作业基本不会出什么幺蛾子:

组件版本选择说明
JDK1.8 或 11选1.8更稳妥,兼容性最好,绝大多数教程基于此
Maven3.6.x配合JDK8完美,不要选太新的Maven,避免插件不兼容
MySQL5.7 或 8.0推荐8.0,连接驱动用8.0+,注意url加时区和编码参数
Node.js14.x 或 16.x对应前端工程,太新的Node可能导致node-sass编译失败
npm/yarnnpm 6+ / yarn 1.x想省心用yarn,安装依赖更稳定

这里有一条非常常见的报错需要单拎出来说:MySQL connection error。如果你用的MySQL是8.0,那么application.yml里的url最好写成:

url: jdbc:mysql://localhost:3306/hospital?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true

serverTimezone不写就很容易报时区错误;allowPublicKeyRetrieval=true是MySQL 8.0连接时的老坑,不写的话IDEA里有时连不上。这一个配置值,就能救回很多人的命。

4.2 数据库导入的四步速成法

标题里的“数据库”指的是数据库脚本文件,一般是一个.sql文件。拿到手后要做的不是双击,而是先建一个空库,再导入。我用命令行说一下这个流程:

mysql -u root -p > CREATE DATABASE hospital DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; > USE hospital; > SOURCE D:/path/to/hospital.sql; > SHOW TABLES;

如果你用的是Navicat,直接“新建数据库”然后把字段命名改一改再“运行SQL文件”同样可以。导入后一定要SHOW TABLES确认表都进来了,同时抽查一两张表的数据量,不然空库跑起来,页面白花花的什么都显示不出来,到时候我还得从头排一次。

4.3 前端Proxy跨域:一个配置就能解决开发环境90%的接口不通

前后端分离开发时有一个很常见的现象:前端启动在8080端口,后端启动在8081或8888端口,你直接从浏览器访问前端页面,让页面去请求后端的接口,结果控制台报错:

Access to XMLHttpRequest at 'http://localhost:8081/api/login' from origin 'http://localhost:8080' has been blocked by CORS policy

很多人第一反应是“后端加@CrossOrigin注解”,确实能解决,但那只是临时解决。更推荐的方式是在Vue前端工程里配置代理:让前端页面先请求自己的同源接口,然后由开发服务器把请求转发给后端服务器。这一层“中转”把所有跨域问题消化掉了。

在Vue项目根目录创建vue.config.js(或修改已有配置):

module.exports = { devServer: { port: 8080, proxy: { '/api': { target: 'http://localhost:8081', changeOrigin: true, pathRewrite: { '^/api': '' } } } } };

这样前端请求/api/login,会被开发服务器转发成http://localhost:8081/login。前端代码里所有接口路径保持/api/xxx前缀即可,后端也无需到处加@CrossOrigin注解。这个配置我要划重点:很多毕设项目在演示时接口不通,十有八九是没做这一步。

配置好之后,记得重启前端开发服务器,不能只改文件不重启,配置文件的生效依赖重启加载。

5. 接口设计是怎么组织的:从登录到就诊全链路拆解

5.1 返回结构的统一,是一切好接口的第一个标准

接口好不好用,首先要看返回数据结构是否统一。很多学生项目每个接口出的数据结构都随心所欲,有的直接返回一个Map,有的把数据包在一个json里,有的成功失败共用同一个数据结构,前端对接起来苦不堪言。合理的做法是定义一个统一返回对象:

public class Result<T> { private Integer code; // 200成功,500失败 private String message; // 提示信息 private T data; // 具体数据 }

成功时这样写:return Result.success(data),失败时写:return Result.error("挂号的号源不足")。前端axios拦截器里统一判断response.data.code,如果不是200就弹提示。这样一来,后端的接口是统一的,前端的处理逻辑也是统一的,联调的时候思维负担非常小。

5.2 患者端的核心接口清单

拿患者端来举例,这些接口基本就是系统的门面:

功能点接口路径方法说明
登录注册/api/auth/loginPOST校验账号密码,签发token
注册账号/api/auth/registerPOST创建患者账号
获取科室列表/api/department/listGET查询所有科室
按科室查医生/api/doctor/listByDeptGET根据科室ID查医生
查询排班表/api/schedule/listGET支持按日期、按医生过滤
创建挂号单/api/order/createPOST锁定号源并创建订单
取消挂号/api/order/cancelPOST释放号源并改状态
查询我的挂号/api/order/myOrdersGET分页查询自己的挂号记录

对于“创建挂号单”这个接口,我会建议在Service层里加上@Transactional事务注解,方法内部先做“剩余号数小于等于0就抛异常”,再执行“原子扣减”,最后“插入挂号单”。一旦中间任何一步失败,事务回滚,不会产生“号源扣了但订单没建”这种脏数据。

5.3 医生端的核心接口思路

医生端最核心的接口是“接诊流程”。比较合理的做法是:医生登录后先拉取当天本医生的候诊列表,这个列表数据其实来源于挂号单表,按日期和医生ID去查,过滤掉已取消状态。点击某个患者“接诊”之后,把状态改成“就诊中”,然后就可以填写诊断记录、选择药品、生成处方。处方这块如果要做细,可以让一个诊断记录对应多条处方项,每条处方项关联一个药品和数量,方便后端计算总价,也方便前端展示明细。

还需要注意一个细节:药品库存扣减。医生开处方后,合理的行为是同步扣减药品表的stock_count字段,扣减逻辑同样要强调用带条件的UPDATE,避免超卖。缴费环节可以做得轻量一些——简单记录一条缴费成功记录即可,没有必要去接真的支付SDK,这个复杂度对毕设来说不划算。

5.4 管理端的核心接口思路

管理端主要做资源配置和运营概览。科室的增删改查、医生信息维护、排班生成这些都属于标准CRUD,重点可以放在排班生成的批量操作上:管理员选择医生、选择一周的日期范围、选择时段和号源总数,后端一次性生成多条排班记录。这个功能既体现你考虑到了“效率”,又能成为答辩时的演示亮点。

数据看板是管理端加分项。你可以用几个聚合查询统计,比如:今日挂号量、各科室挂号占比、最近7天挂号趋势、最受欢迎的医生Top5。前端再配一个图表库,比如ECharts,界面瞬间就有质感了,而且这部分的实现难度不算高。

6. 我把“模拟项目X”跑通之后,遇到的三个经典Bug

这部分我想写几个我实际调试过程中踩到的真实坑,都是那种“百度搜不到一模一样、自己排查半天才发现”的问题。希望能帮你少走弯路。

6.1 第一个坑:日期传参格式不对,后端死活收不到正确时间

患者端查排班表,一般会传一个日期,比如“2025-06-15”。如果前端用的是axios,默认会把JS对象序列化成JSON格式,日期类型会被转成一长串时间戳或带T的ISO字符串,比如2025-06-15T00:00:00.000Z。后端用LocalDate接收,经常就解析失败,或者解析成前一天。

解决方案有两种。第一种便宜快捷:前端在传参前手动格式化成字符串,比如dayjs(date).format('YYYY-MM-DD'),后端用@RequestParam("date") String date接收,再用LocalDate.parse(date)转成日期。第二种更稳健:后端在接收日期时使用@DateTimeFormat(pattern = "yyyy-MM-dd")标注:

@GetMapping("/schedule/list") public Result<List<ScheduleVO>> list(@RequestParam @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate date) { // ... }

这个坑不致命,但隔三差五就会遇到,值得提前防范。

6.2 第二个坑:MyBatis-Plus分页查询不生效

很多人在用MyBatis-Plus的分页时,发现selectPage返回的记录数是全量,压根没分页。这个问题的根源基本是:没有配置分页拦截器。MyBatis-Plus的分页功能不是开箱即用的,需要在配置类里注册一个PaginationInnerInterceptor:

@Configuration public class MybatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); return interceptor; } }

没有这个拦截器,分页参数会被静默忽略,最要命的是它不报错,你只会在某一个时刻突然发现数据量不对。所以建议大家在项目刚搭建的时候就先把这个配置写好,别等出问题再补。

6.3 第三个坑:删除科室时外键关联报错,被我用逻辑删除化掉

科室和医生是一对多的关系。如果直接给department表设外键并开启数据库级约束,删除一个还挂着医生的科室,数据库会直接拒绝删除。这种交互方式对用户很不友好,弹一个“外键约束失败”的英文异常,体验非常糟糕。

更符合工程习惯的做法有两个:要么在删除前先检查是否关联了医生,如果关联了,在前端提示“该科室下还有医生,不能删除”;要么引入逻辑删除字段,比如deleted(默认0),删除时只做UPDATE标记,查询时统一过滤。逻辑删除的好处是数据不会物理消失,还能随时恢复,对答辩也更好解释“我考虑到了数据安全问题”。

7. 论文框架该怎么写,老带新带出来的实用结构

标题里特意说了“+论文”,说明这套项目里论文写作也是重头戏。论文写得好不好,直接决定你能不能把系统的设计优势讲出来。很多同学系统做完,论文却拖到最后几天硬憋,结果答辩时被评委连续追问几个“为什么”,就只能尬在那里。我把自己相对满意的论文结构整理一下,你可以直接做个参考:

7.1 第一章绪论定基调

绪论部分不用展开太多,三块说清楚就行:研究背景与意义、国内外研究现状、主要研究内容与章节安排。背景部分可以讲医院排队挂号难、患者就医体验差、信息化的好处;现状部分最好找几篇“医院信息系统”相关的文献简单综述一下,点出“已有系统存在挂号流程繁琐、医生排班不透明、数据统计能力弱”等问题。这是最基础的写法,对非学术大牛来说也足够用了。

7.2 需求分析章:别抄功能列表,要画出用例

需求分析是论文里最容易注水但也最容易出彩的部分。核心要做到三点:画出系统角色图(患者、医生、管理员三个actor),写明每个角色的核心用例(患者可以登录注册、浏览科室、查询排班、在线挂号、取消挂号;医生可以查看候诊患者、填写病历、开处方;管理员可以维护科室与排班)。然后写功能需求记录表,每个功能一行,写明请求来源和处理结果。最后补一小节非功能需求,把系统性能、安全性、易用性说几句,论文的严谨程度一下就上来了。

7.3 系统设计章:结构图是重点

系统总体架构图最常见的画法是把系统分成三层,前端展示层(Vue页面)、后端接口层(SpringBoot提供的Controller/Service/Mapper)、数据存储层(MySQL),用箭头标注请求流向。再画一张功能模块图,把系统分成“患者端模块、医生端模块、管理端模块、公共模块”四个大块,每一块下面列二级功能点。

数据库设计这一章用料最实。每个表的字段和说明列一张表,更重要的是把表之间的关系用ER图画出来。不需要特别复杂的工具,ProcessOn或者PowerDesigner都行。再挑一到两张关键表,比如schedule和registration_order,讲清楚字段含义和业务约束。

7.4 系统实现章:别贴整段代码,讲关键逻辑

系统实现章是很多学生最容易写砸的地方——他们把一整段Controller代码往论文一贴,评委看着满页的注解和if-else,头都大了。正确的做法是只挑两三段“有设计含量”的片段讲透,比如:登录时后端签发token的逻辑、创建挂号单时事务保证号源不超卖的逻辑、MyBatis-Plus分页查询的配置方式。每一段代码后面都要配上文字说明,解释这段代码解决的问题和实现思路。

7.5 系统测试章:别光说“运行正常”,要用测试用例表说话

系统测试部分建议用大量的表把“测试了什么、预期结果是什么、实际结果是什么”记录清楚。比如测试“患者重复点击挂号按钮”,预期结果是只能生成一个有效挂号单;测试“医生停诊后患者再挂号”,预期结果是系统提示该时段排班已停用。有了这种类型的用例,论文的说服力会明显提升。

8. 部署这事没你想得那么难,一套流程反复跑

标题里特意说有“部署文档”,说明这个项目交付时需要考虑把系统跑在服务器上。部署本身不难,但流程比较琐碎,任何一个节点踩坑都会让人抓狂。我一般会建议按以下顺序逐步执行:

8.1 后端部署:打jar包,一条命令搞定

SpringBoot项目最终打成可执行jar包,这是最基本的技能。在项目根目录(包含pom.xml的目录)执行:

mvn clean package -DskipTests

打包完成后,target目录下会多出一个类似hospital-0.0.1-SNAPSHOT.jar的文件。传到服务器后,直接用:

java -jar hospital-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod > /var/log/hospital.log 2>&1 &

这里有个比较常见的坑:打包时如果pom.xml没配置finalName,jar包名有时会不同。建议自己在pom.xml里设一个固定名称,比如:

<build> <finalName>hospital-api</finalName> </build>

这样每次打出来的都是hospital-api.jar,脚本和部署文档里写起来更省事。如果你想让项目在那种行情一般的云服务器上持续运行,可以考虑加个Systemd服务管理器,但这属于锦上添花,不是必须项。

8.2 前端部署:npm run build之后,用Nginx静态托管

前端Vue项目部署比很多人想象中简单,因为它是纯静态资源。在工程根目录执行:

npm run build

生成出一个dist目录,里面是index.html、css、js这些静态文件。把这个目录传到Nginx配置的web根目录下,再让Nginx把/路径指过去就行了。

需要注意的反而是接口地址问题:前端在本地开发时请求的是/api,由vue.config.js的proxy转发;部署到生产环境后,没有这个代理了,那前端打包时就要把接口地址改成后端的实际地址。所以我通常会在前端代码里留一个统一的环境变量文件,比如.env.production:

VUE_APP_BASE_URL=http://your-server-ip:8081/api

然后前端请求统一用axios配上这个baseURL。这一招能避免你把几十个接口路径写死在页面里,打包的时候改一处地方就行。

8.3 Nginx反向代理的反向思路:把接口也一并代理

既然有Nginx了,如果后端还用的是8081这种直出端口,显得没太大质感。更规整的做法是让Nginx统一收口所有访问流量,比如监听80端口,把带/api前缀的请求都转发给后端的8081端口,其余请求都指向前端静态文件。一个非常经典的配置片段是这样:

server { listen 80; server_name _; root /var/www/hospital/dist; index index.html; location /api { proxy_pass http://127.0.0.1:8081; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } location / { try_files $uri $uri/ /index.html; } }

这个配置会让“部署”的内涵变得不太一样:它同时解决了前端路由history模式刷新404的问题(try_files那条)、接口跨域问题(同域名同端口访问)、以及端口暴露的安全问题。把这一套讲清楚,足够在答辩时和面试官聊上一阵子。

9. 排错手册:遇到问题先对照这几条再动手

我把日常帮人排查的频率最高的几类问题做成一张自查表。如果你跑项目跑不动,先沉住气,对照下面这个表格逐项检查,能解决大部分基础问题。

现象可能原因排查方式
后端起不来,提示端口被占用8081端口被其他进程占用netstat -ano | findstr 8081,找到PID后结束进程
前端访问接口跨域报错没配置vue.config.js的proxy,或者没重启检查配置文件,重启dev server
数据库连接失败数据库服务没启动、账号密码错、url配置缺少时区先确保能用Navicat连上,再检查application.yml
前端页面白屏打包后路由模式问题或者资源引用的绝对路径问题如果是history路由,加try_files兜底;publicPath改成相对路径
分页不生效缺少PaginationInnerInterceptor按上文添加配置类
日期字段查不到数据时间格式参数转换失败用@DateTimeFormat或前端格式化字符串

这张表是我个人维护的“毕设急救清单”里的精华开头,如果你遇到其他奇葩问题,核心原则就一条:一步一动,分模块验证。后端单独用Postman调接口,前端单独用Mock数据看渲染,哪一层通了再和哪一层结合,每一步都确认过了,就知道问题停留在哪了。

最后一个心得:做毕设真的不是“拿到源码本地能跑通”就够了,你得把每个模块的关键实现逻辑都梳理一遍,能够用自己的话把代码讲明白。比如问到“号源怎么防止超卖”,你能脱口而出“我用的是条件UPDATE加事务控制”;问到“token怎么鉴权”,你能解释“网关拦截器验证逻辑”。能讲出这些东西,比你把源码背下来有用得多,这才是做这个项目真正的收获。

根据我个人的经验,跑这个项目的过程大约会经历三个阶段:第一个阶段是环境配置地狱,各种依赖兼容性问题让人想摔电脑;第二个阶段是联调大坑,前后端数据对不上、状态不流转,非常磨心态;第三个阶段才是真正体会到“系统跑通”的快感。等你在浏览器里看到患者从挂号到就诊的完整流程流畅走通的那一刻,之前所有的崩溃都会变成成就感。这套系统做完,你逛三甲医院官网的时候心态都会不一样——你大概已经能猜到它背后大概是个什么样的表结构了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 16:33:05

基于SpringAI的在线考试主观题智能阅卷系统设计实践

做在线考试系统&#xff0c;最容易翻车的不是题库也不是组卷&#xff0c;而是阅卷。尤其主观题&#xff0c;一张卷子里有几道论述题和简答题&#xff0c;按传统方式让老师逐份批改&#xff0c;量大、耗时&#xff0c;而且两个老师打出的分可能差出一档。去年我在负责某个高校的…

作者头像 李华
网站建设 2026/10/18 23:31:23

模板代码生成工具:从元数据到可用接口的完整实现

1. 为什么需要模板代码生成工具&#xff1a;一大半重复代码其实不该手写做后端开发的朋友应该都有过这种体验&#xff1a;新项目启动&#xff0c;建表、写实体、写Mapper、写Service接口和实现、写Controller&#xff0c;然后前端再把列表页、表单页、弹窗、状态标签挨个撸一遍…

作者头像 李华
网站建设 2026/10/21 13:48:57

贪心算法实战:从陶陶摘苹果升级版掌握最优选择策略

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 10:19:52

HDU6759 Leading Robots解题精要:上凸包与物理模型的工程实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/19 7:24:56

Vue 3 集成 wangEditor v5 富文本编辑器:避坑指南与最佳实践

1. 为什么在 Vue 项目里选富文本编辑器会让人头疼做过后台管理系统的朋友大概率都碰过这个场景&#xff1a;产品经理甩过来一个需求&#xff0c;说文章发布页要能加粗、能插图片、能调字号、能传视频&#xff0c;最好还能支持表格和代码块。你打开 npm 一搜&#xff0c;富文本编…

作者头像 李华
网站建设 2026/10/21 4:45:57

CAN转WiFi模块选型与配置:工业现场无线化部署实战指南

说实话&#xff0c;干工业通讯这行这么多年&#xff0c;一提到CAN总线&#xff0c;我第一反应不是它多可靠&#xff0c;而是那堆又粗又硬的屏蔽双绞线。CAN总线在设备之间传递数据确实够稳&#xff0c;可控性和抗干扰都是一把好手&#xff0c;可真到了现场&#xff0c;线怎么走…

作者头像 李华