简介:这是一套面向高校计算机专业毕业设计、课程设计及Java全栈学习者的医院急诊系统完整源码,采用Spring Boot后端、Vue前端与MySQL数据库构建,可帮助读者快速搭建医疗类管理系统并理解前后端分离架构。压缩包共852个文件,约17.7MB,涵盖138个Java源文件、50个Vue组件、50个HTML页面、44个CSS样式、153个JS脚本及SQL建表脚本、部署说明文档等,前后端代码与数据库结构一应俱全。项目已通过运行测试,配套说明文档记录了环境要求、部署步骤与常见问题处理,方便在Eclipse或IDEA中导入调试。目前已有68人学习下载,适合需要完整项目参考、想掌握Spring Boot与Vue整合开发、或准备毕业答辩与课程作业的读者,可据此梳理急诊业务流程、复用代码结构并完成二次开发。
1. 急诊系统源码到手之后:先别急着跑,搞清楚这套 SpringBoot + Vue + MySQL 到底能干什么
拿到一份「基于 SpringBoot 的医院急诊系统源代码」压缩包,很多人的第一反应是解压、导入 IDE、点运行。但急诊系统跟普通的增删改查管理系统完全不是一回事——它要处理的是分诊排队、急诊分级、留观床位、抢救记录这些带时间压力和状态流转的业务。如果你只是把它当成一个 SpringBoot 练手项目,那这套源码的价值至少浪费了一半。
这套技术栈的组合逻辑其实很清晰:SpringBoot 负责后端接口和业务逻辑,Vue 负责前端交互和实时刷新,MySQL 存业务数据。急诊场景对响应速度要求高,分诊台护士需要快速录入、医生需要即时看到排队队列,所以前后端分离 + RESTful 接口是合理选择。适合谁看?正在做医疗信息化方向 Java 工程师、需要交付类似系统的外包团队、以及想拿一个真实业务场景练 SpringBoot + Vue 全栈的开发者。下面我从环境搭建一路讲到急诊业务里最容易翻车的地方。
2. 把源码跑起来:JDK、MySQL、Node 三件套的版本对齐与最小启动路径
2.1 先看 pom.xml 和 package.json,别盲目装最新版
源码能不能跑起来,八成的问题出在版本不匹配上。热搜里「springboot版本太高」这个词不是白来的——很多医院急诊系统源码是基于 SpringBoot 2.x 写的,你本地装了 3.x 的 JDK 17 去跑,javax.servlet 包名全变成 jakarta.servlet,编译直接报错。
拿到源码后第一件事,打开pom.xml看三处:
<!-- pom.xml 关键位置 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.6</version> <!-- 记下这个版本号 --> </parent> <properties> <java.version>1.8</java.version> <!-- 决定你装 JDK 8 还是 11 --> </properties>再看前端package.json里的vue版本和node引擎要求。Vue 2 和 Vue 3 的构建工具链差异很大,Vue 2 项目用vue-cli-service,Vue 3 可能用vite。如果package.json里写的是"vue": "^2.6.14",你就别用 Node 18 以上的版本去npm install,node-sass 编译大概率失败。
我一般会先确认这三个版本:JDK 版本跟java.version一致,MySQL 用 5.7 或 8.0(看 JDBC 驱动配置),Node 用 14 或 16 跑 Vue 2 项目。版本对齐了,后面少折腾两小时。
2.2 MySQL 建库与数据导入:字符集和时区是两个必调参数
急诊系统的数据表通常包含患者信息、分诊记录、床位状态等,字段里中文不少。建库时字符集必须用utf8mb4,否则生僻字或者 emoji 会插入失败。
-- 创建数据库,字符集和排序规则都要指定 CREATE DATABASE emergency_db DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; -- 导入源码附带的 sql 文件(假设文件名为 emergency.sql) -- 在命令行执行: -- mysql -u root -p emergency_db < emergency.sql导入完成后检查一下时区配置。急诊系统里「分诊时间」「抢救开始时间」这些字段对时区敏感,如果 MySQL 用的是 UTC 而 Java 应用用的是东八区,时间会差 8 小时。在application.yml里把 JDBC URL 补上时区参数:
spring: datasource: url: jdbc:mysql://localhost:3306/emergency_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false username: root password: your_password driver-class-name: com.mysql.cj.jdbc.DriverserverTimezone=Asia/Shanghai这个参数不加,MySQL 8.0 驱动会报时区错误。useSSL=false在本地开发环境加上,省得控制台一直刷警告。
2.3 后端启动:从 Maven 依赖下载到接口自测
后端启动命令很简单,但依赖下载这一步容易卡住。如果公司网络有限制,配置一下阿里云镜像:
<!-- settings.xml 中 mirror 配置 --> <mirror> <id>aliyunmaven</id> <mirrorOf>*</mirrorOf> <name>阿里云公共仓库</name> <url>https://maven.aliyun.com/repository/public</url> </mirror>然后在项目根目录执行:
# 跳过测试打包,第一次跑建议加 -DskipTests mvn clean package -DskipTests # 启动 SpringBoot 应用 java -jar target/emergency-system-0.0.1-SNAPSHOT.jar启动成功后,先别急着开前端。用 curl 或者 Postman 测一个基础接口,比如分诊列表查询:
curl -X GET "http://localhost:8080/api/triage/list?page=1&size=10" \ -H "Authorization: Bearer your_token"如果返回 401,说明接口需要登录态,先调登录接口拿 token。如果返回 500,看控制台堆栈,大概率是数据库连接或者 MyBatis 映射问题。这一步能过,后端就算通了。
2.4 前端启动:npm install 之后的代理配置
前端目录下执行npm install,然后看vue.config.js或者vite.config.js里的代理配置。前后端分离项目本地开发时,前端跑在 8081,后端跑在 8080,跨域问题靠 devServer 代理解决:
// vue.config.js module.exports = { devServer: { port: 8081, proxy: { '/api': { target: 'http://localhost:8080', // 后端地址 changeOrigin: true, pathRewrite: { '^/api': '/api' } // 根据实际接口前缀调整 } } } }changeOrigin: true必须加,否则后端收到的 Host 头不对,某些安全拦截器会拒绝。配好后npm run serve,浏览器打开http://localhost:8081,能看到登录页就算前端通了。
3. 急诊业务核心链路:分诊排队、分级调度、留观床位在代码里怎么落地
3.1 分诊排队:从挂号到叫号的完整状态机
急诊系统跟普通门诊最大的区别是「分级」。患者来了先到分诊台,护士根据症状体征打一个分级(一级濒危、二级危重、三级急症、四级非急症),然后进入对应队列。这个逻辑在代码里通常是一个状态机。
看后端 Service 层,一般会有类似这样的方法:
// TriageServiceImpl.java 核心逻辑示意 public TriageRecord assignTriageLevel(TriageRequest request) { // 1. 根据评分规则计算分级 int level = calculateLevel(request.getVitalSigns(), request.getSymptoms()); // 2. 生成排队序号(按分级分别排队) int queueNumber = queueService.nextNumber(level); // 3. 写入分诊记录 TriageRecord record = new TriageRecord(); record.setPatientId(request.getPatientId()); record.setLevel(level); record.setQueueNumber(queueNumber); record.setStatus(TriageStatus.WAITING); record.setCreateTime(new Date()); triageMapper.insert(record); // 4. 推送到对应诊室的叫号队列 callQueueService.push(level, record); return record; }这里的关键参数是level的计算规则。不同医院的分级标准不一样,源码里可能写死了一套规则,你需要根据实际需求调整calculateLevel方法。另外queueNumber的生成要注意并发——两个护士同时分诊,不能拿到同一个号。常见做法是用 Redis 的INCR或者数据库乐观锁。
3.2 分级调度:医生端如何按级别拉取待诊队列
医生登录后看到的队列不是简单的先来先服务,而是按分级权重排序。一级患者永远排在四级前面,同级内按挂号时间排序。这个查询在 MyBatis 的 XML 里通常长这样:
<!-- TriageMapper.xml --> <select id="selectDoctorQueue" resultType="TriageRecord"> SELECT * FROM triage_record WHERE status = 'WAITING' AND department_id = #{deptId} ORDER BY level ASC, create_time ASC LIMIT #{offset}, #{size} </select>ORDER BY level ASC, create_time ASC这一句就是分级调度的核心。level 越小优先级越高,同级别按时间先后。如果医院要求「二级患者等待超过 10 分钟自动升级为一级」,那还需要一个定时任务去扫描超时记录并更新 level。
前端 Vue 这边,医生端队列通常用轮询或者 WebSocket 刷新。轮询简单但浪费请求,WebSocket 实时但增加复杂度。源码里如果用的是setInterval每 5 秒拉一次,对于急诊场景够用了,别过度设计。
3.3 留观床位:状态流转与并发抢占
留观区床位是急诊系统的稀缺资源。一个床位从「空闲」到「占用」再到「清洁中」最后回到「空闲」,状态流转必须严格。代码里常见的问题是:两个护士同时给同一个床位办理入住,导致数据覆盖。
处理方式有两种。一种是数据库层面加唯一约束或者乐观锁:
-- 更新床位状态时带上旧状态条件 UPDATE bed SET status = 'OCCUPIED', patient_id = #{patientId} WHERE id = #{bedId} AND status = 'IDLE'; -- 检查 affectedRows,如果为 0 说明被别人抢了另一种是在 Service 层用synchronized或者分布式锁。单机部署用synchronized够用,多节点部署就得上 Redis 锁。源码里如果没处理这个并发,你在测试环境可能碰不到,一上生产就会出问题。
床位状态变更后,前端需要刷新床位图。Vue 组件里通常是一个二维数组渲染床位卡片,点击空闲床位弹出入住表单,提交后重新拉取列表。这部分逻辑不复杂,但要注意表单校验——患者 ID 必填、床位 ID 从点击事件里带过来,别搞混。
4. 避坑与排查:急诊系统源码落地时最容易翻车的 5 个地方
4.1 现象:前端页面能打开但所有接口返回 404
原因:Vue 的代理配置里pathRewrite写错了,或者后端server.servlet.context-path配了前缀但前端没加。
解决:打开浏览器开发者工具 Network 面板,看请求的实际 URL 是什么。如果请求发到了http://localhost:8081/api/xxx但后端实际接口是http://localhost:8080/emergency/api/xxx,那就要在代理里把pathRewrite改成{ '^/api': '/emergency/api' }。或者直接看后端application.yml里有没有context-path配置。
4.2 现象:MySQL 插入中文报错Incorrect string value
原因:数据库或者表的字符集不是utf8mb4,或者 JDBC URL 里没指定characterEncoding=utf8。
解决:先查SHOW CREATE TABLE triage_record;看表的字符集。如果是latin1或者utf8(不是 utf8mb4),执行ALTER TABLE triage_record CONVERT TO CHARACTER SET utf8mb4;。然后确认 JDBC URL 里有useUnicode=true&characterEncoding=utf8。两个都对了,中文才能正常写入。
4.3 现象:分诊排队序号重复,两个患者拿到同一个号
原因:queueService.nextNumber(level)方法没有做并发控制,两个线程同时读到同一个最大值然后各自加一。
解决:把序号生成放到数据库里用UPDATE ... SET current_value = current_value + 1然后查回来,或者用 Redis 的INCR命令。如果源码里用的是SELECT MAX(queue_number) + 1,那必须改掉。急诊场景下号重复是严重问题,护士叫号会乱。
4.4 现象:医生端队列刷新后顺序变了,一级患者跑到后面去了
原因:排序字段用错了,或者前端拿到数据后又做了一次本地排序把顺序打乱。
解决:检查 MyBatis 的ORDER BY是不是level ASC, create_time ASC。然后看 Vue 组件里有没有对数组做sort()操作。如果有,确认排序规则跟后端一致。另外注意level字段的类型,如果是字符串类型,'10'会排在'2'前面,必须用数字类型。
4.5 现象:床位状态更新成功但前端显示没变
原因:更新接口返回成功,但前端没有重新拉取数据,或者 Vue 的响应式没触发。
解决:确认更新成功后调用了this.fetchBedList()重新获取数据。如果用了 Vuex,检查 mutation 有没有正确提交。还有一种情况是后端返回了更新后的对象但前端直接改了本地数组的某个元素,而 Vue 2 对数组下标赋值不触发响应式,需要用this.$set()或者重新赋值整个数组。
5. 从能跑到好用:急诊系统源码二次开发时我常用的三个进阶技巧
5.1 用 MyBatis-Plus 代码生成器快速扩展新表
急诊系统源码里如果用的是 MyBatis-Plus,那扩展新业务表会快很多。比如医院要加一个「急诊手术申请」模块,你只需要建好表,然后跑一下代码生成器:
// CodeGenerator.java 核心配置 AutoGenerator generator = new AutoGenerator(); generator.setDataSource(new DataSourceConfig() .setUrl("jdbc:mysql://localhost:3306/emergency_db?serverTimezone=Asia/Shanghai") .setUsername("root") .setPassword("your_password") .setDriverName("com.mysql.cj.jdbc.Driver")); GlobalConfig globalConfig = new GlobalConfig() .setOutputDir(System.getProperty("user.dir") + "/src/main/java") .setAuthor("your_name") .setOpen(false); generator.setGlobalConfig(globalConfig); generator.setPackageInfo(new PackageConfig() .setParent("com.emergency") .setEntity("entity") .setMapper("mapper") .setService("service") .setController("controller")); generator.execute();跑完之后 entity、mapper、service、controller 全有了,你只需要改业务逻辑。这比手写快十倍,而且不容易漏掉字段。注意生成之前把表注释写好,生成的 Swagger 文档会好看很多。
5.2 前端打包放进 SpringBoot 的 static 目录
开发阶段前后端分离没问题,但交付时如果客户只想要一个 jar 包,那就需要把 Vue 打包产物放到 SpringBoot 的src/main/resources/static下。
# 前端目录执行打包 npm run build # 把 dist 目录下的文件复制到后端 static 目录 cp -r dist/* ../emergency-backend/src/main/resources/static/然后在 SpringBoot 里加一个配置,让所有非 API 请求都转发到index.html:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/**") .addResourceLocations("classpath:/static/"); } }这样打出来的 jar 包直接java -jar就能跑,前端页面和后端接口在同一个端口,省去了 Nginx 配置。注意 Vue Router 要用 hash 模式,history 模式需要额外配置,否则刷新页面会 404。
5.3 用日志和埋点定位急诊业务里的「玄学」问题
急诊系统上线后最怕的是「有时候叫号没反应」「有时候床位状态不对」。这种偶发问题靠猜没用,得靠日志。我一般会在关键业务方法入口和出口打上 traceId:
// 在分诊方法入口 String traceId = UUID.randomUUID().toString().substring(0, 8); log.info("[{}] 分诊开始, patientId={}, level={}", traceId, patientId, level); // ... 业务逻辑 log.info("[{}] 分诊完成, queueNumber={}", traceId, queueNumber);然后在 Nginx 或者网关层把 traceId 透传到前端响应头里。出问题时让护士报一下页面上的 traceId,你直接去日志平台搜这个 ID,整条链路一目了然。这个习惯我保持了五年,比任何调试工具都好使。
最后说一个我自己的教训:急诊系统的源码拿到手,别急着改业务逻辑,先把分诊、叫号、床位这三个核心链路的代码读一遍,画一张状态流转图。图画清楚了,后面加功能还是改 bug 都不会迷路。希望帮到你。
本文还有配套的精品资源,点击获取