news 2026/9/4 4:10:22

Spring Boot+Vue.js医院急诊系统实战:架构设计与核心功能实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring Boot+Vue.js医院急诊系统实战:架构设计与核心功能实现

简介:本资源是一套完整的基于Spring Boot的医院急诊系统毕业设计级源码,面向计算机专业本科生、Java全栈初学者及医疗信息化课程实践者,解决急诊业务流程数字化、前后端分离开发与MySQL数据管理等典型工程问题。压缩包共852个文件,17.7MB,涵盖138个Java后端逻辑文件、50个Vue组件页面、153个JS交互脚本、44个CSS样式文件及63个JPG/GIF图片资源,辅以SQL建表语句、YML配置、BAT部署脚本和详细说明文档,结构清晰、模块完整。已有67人学习下载,资源经实测可正常运行,提供从环境搭建(JDK 1.8+MySQL 5.7/8+Eclipse/IDEA)到前后端联调的完整路径,包含登录、分诊、病历录入、医生排班等核心功能模块,且保留了.bak备份文件与多版本静态资源(SVG/woff/ttf等),便于理解开发迭代过程与UI适配逻辑。

1. 项目概述:一个面向实战的医院急诊系统

最近在整理过往项目资料时,翻出了一个几年前主导开发的医院急诊系统。这个项目在当时算是一个比较典型的“互联网+医疗”的院内信息化升级案例,核心目标是将急诊科从传统的手工登记、纸质流转的混乱状态,升级为一个流程化、数字化、可视化的高效工作平台。项目打包文件里包含了完整的后端(Spring Boot + Java)、前端(Vue.js)、数据库(MySQL)源码以及详细的说明文档,算是一个麻雀虽小但五脏俱全的实战项目。

这个系统主要解决了几个急诊科的痛点:一是患者信息录入慢、易出错,二是抢救、检查、治疗等环节的状态无法实时同步,导致医护人员“跑断腿”沟通,三是各类文书(抢救记录、医嘱单)生成效率低下,四是管理者无法直观掌握急诊室的实时负荷与资源使用情况。我们通过一个B/S架构的Web系统,将分诊台、抢救室、留观区、药房、检验科等角色串联起来,实现了从患者入院到离院(或转入住院)的全流程闭环管理。

对于开发者而言,这个项目源码的价值在于它并非一个简单的“增删改查”Demo,而是涉及了复杂的业务流程状态机、高实时性的WebSocket通信、多角色权限控制、以及前端复杂表格和图表展示等实战场景。无论你是想学习Spring Boot如何构建中型企业应用,Vue.js如何管理复杂的组件状态,还是想了解一个真实医疗系统的数据库设计与业务逻辑,它都能提供一个不错的参考范本。

2. 系统核心架构与设计思路拆解

2.1 技术栈选型背后的考量

当时选择Spring Boot + Vue.js + MySQL这个组合,是经过一番权衡的,现在看来依然是中小型后台管理系统的高效组合拳。

后端选择Spring Boot,核心诉求是“快速搭建、易于维护”。急诊系统业务模块多(分诊、抢救、医嘱、药品、统计等),Spring Boot的自动配置和起步依赖能让我们迅速集成MyBatis(数据层)、Spring Security(安全)、WebSocket(实时通信)、Redis(缓存与Session共享)等关键组件。它的“约定大于配置”理念,让团队能更专注于业务逻辑开发,而非繁琐的XML配置。例如,通过spring-boot-starter-websocket一个依赖,就轻松实现了抢救室大屏与护士站PC端的实时信息同步。

前端选择Vue.js而非当时的 Angular 或 React,主要基于两点:一是上手曲线平缓,团队前端资源有限,Vue的模板语法对后端转前端的同学更友好;二是其响应式数据绑定和组件化开发模式,非常适合构建像急诊系统这样拥有大量表单、表格和动态交互的SPA(单页应用)。我们利用Vue Router管理不同角色(医生、护士、管理员)的视图路由,用Vuex集中管理患者列表、医嘱项等全局状态,使得前端逻辑清晰可控。

数据库选用MySQL,这是最务实的选择。急诊系统的数据关系虽然复杂(患者、病历、医嘱、药品、库存等),但事务性要求强,且存在大量的关联查询(如查询某个患者的所有检查记录)。MySQL在5.7版本后对JSON字段的支持,也让我们在存储一些动态扩展的体征信息时更加灵活。同时,其成熟的生态和运维经验,对于医院信息科后续的维护至关重要。

2.2 业务架构与模块划分

系统在业务上采用了经典的分层架构和模块化设计,确保高内聚、低耦合。

后端模块划分:

  1. 急诊核心模块:包含患者登记、分诊(根据病情严重程度分级,如1级濒危、2级危重等)、急诊病历书写。这是数据入口。
  2. 抢救与留观模块:这是系统的“心脏”。管理抢救床位、实时记录生命体征(通过接口对接监护仪数据,或手动录入)、生成抢救记录。留观区则管理需要短期观察的患者。
  3. 医嘱与执行模块:医生开具药品、检查、治疗医嘱,护士核对并执行。这里实现了严格的闭环管理,每条医嘱都有“已开立、已审核、已执行、已停止”等状态。
  4. 药品与物资管理模块:与医院HIS(医院信息系统)或独立的库存系统对接,实现药品的申领、发放、盘点,确保急救药品随时可用。
  5. 统计与报表模块:为科室主任和管理者提供实时数据看板,如实时在院人数、患者停留时间、病种分布、医护工作量等。

前后端交互设计:采用完全分离的模式。前端Vue项目独立部署,通过Axios库调用后端Spring Boot提供的RESTful API。所有API请求都经由Spring Security和JWT(JSON Web Token)进行认证和授权。这种分离为未来可能的移动端(如护士Pad端)扩展提供了便利。

数据库设计核心思想:围绕“患者一次就诊”为核心。主表是visit_record(就诊记录),关联patient_info(患者基本信息)、triage_record(分诊记录)、medical_orders(医嘱主表)、order_execution(医嘱执行记录)等。大量使用外键约束保证数据一致性,并对visit_record表的status字段(如“分诊中”、“抢救中”、“留观中”、“已离院”)建立了索引,以优化高频的状态查询。

注意:在实际医疗系统中,患者基本信息通常来自医院的EMPI(患者主索引)系统,本项目为了演示完整性,独立设计了patient_info表。真实上线时,这部分应通过接口同步。

3. 关键功能实现细节与核心技术点

3.1 高实时性:WebSocket在急诊大屏的应用

急诊抢救室通常配备一块大屏幕,动态显示所有抢救床位患者的关键信息(姓名、年龄、生命体征、预警状态)。这是系统的“门面”,要求信息延迟极低。

我们使用Spring Boot集成的STOMP over WebSocket协议来实现。后端通过@Controller注解处理STOMP消息,前端使用SockJS-client和stompjs库连接。

后端关键配置与代码:

@Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { // 指定连接端点,允许SockJS降级 registry.addEndpoint("/ws-emergency").setAllowedOriginPatterns("*").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { // 启用简单的内存代理,用于订阅/广播 registry.enableSimpleBroker("/topic", "/queue"); registry.setApplicationDestinationPrefixes("/app"); } }

当护士在PC端更新某个抢救患者的体征(如血压)时,后端服务在更新数据库后,会立即向特定主题发布消息:

@Service public class PatientMonitorService { @Autowired private SimpMessagingTemplate messagingTemplate; public void updateVitalSigns(PatientVitalSigns signs) { // 1. 更新数据库... vitalSignsMapper.update(signs); // 2. 计算预警状态(如血压过高/过低) String alertLevel = calculateAlertLevel(signs); signs.setAlertLevel(alertLevel); // 3. 广播给所有订阅了该床位信息的客户端 messagingTemplate.convertAndSend("/topic/rescue-bed/" + signs.getBedId(), signs); } }

前端关键实现:在Vue组件中,我们会在mounted生命周期钩子中建立WebSocket连接,并订阅对应的床位主题。

mounted() { this.connectWebSocket(); }, methods: { connectWebSocket() { const socket = new SockJS('/ws-emergency'); const stompClient = Stomp.over(socket); stompClient.connect({}, (frame) => { // 订阅所有抢救床位主题,这里以1号床为例 stompClient.subscribe('/topic/rescue-bed/1', (message) => { const updatedSigns = JSON.parse(message.body); // 更新本地数据,视图会自动响应 this.patientData = updatedSigns; // 如果预警状态变化,触发前端弹窗或声音提示 if (updatedSigns.alertLevel !== 'normal') { this.showAlert(updatedSigns); } }); }); } }

实操心得:WebSocket连接在用户刷新或网络波动时会中断。我们前端增加了心跳检测和自动重连机制。另外,对于非实时性要求极高的数据(如患者列表更新),我们仍采用HTTP轮询或长轮询,以减轻WebSocket服务器的压力。

3.2 复杂状态流转:基于状态模式的医嘱生命周期管理

一条医嘱从开立到完成,状态流转复杂且规则严格。例如,医生开立(CREATED) -> 护士审核(VERIFIED) -> 护士执行(EXECUTING) -> 执行完成(COMPLETED)。也可能被医生停止(STOPPED)。如果使用大量的if-else来判断状态能否变更以及变更后需要触发的动作(如执行医嘱时要扣减库存),代码会非常臃肿且难以维护。

我们引入了状态模式来优雅地管理医嘱状态。首先定义一个状态接口和一系列具体状态类:

public interface OrderState { // 能否切换到目标状态 boolean canTransitionTo(OrderState nextState); // 状态变更时执行的动作 void handleAction(MedicalOrder order, OrderContext context); } @Component public class CreatedState implements OrderState { @Override public boolean canTransitionTo(OrderState nextState) { // 创建状态只能转向“已审核”或“已取消” return nextState instanceof VerifiedState || nextState instanceof CancelledState; } @Override public void handleAction(MedicalOrder order, OrderContext context) { // 创建时,可能初始化一些默认属性,或记录日志 log.info("医嘱[{}]已开立,开立医生:{}", order.getOrderNo(), order.getCreateDoctor()); } } @Component public class ExecutingState implements OrderState { @Autowired private InventoryService inventoryService; @Override public boolean canTransitionTo(OrderState nextState) { return nextState instanceof CompletedState || nextState instanceof StoppedState; } @Override @Transactional // 重要:状态变更涉及业务操作,需要事务管理 public void handleAction(MedicalOrder order, OrderContext context) { // 执行医嘱时,核心业务是扣减药品或材料库存 if ("MEDICATION".equals(order.getOrderType())) { inventoryService.deductStock(order.getItemId(), order.getQuantity(), order.getPatientId()); } // 记录执行时间和执行人 order.setExecuteTime(new Date()); order.setExecuteNurse(context.getCurrentUserId()); log.info("医嘱[{}]开始执行,执行护士:{}", order.getOrderNo(), context.getCurrentUserId()); } }

然后,有一个上下文类OrderContext来持有当前状态并处理状态转换请求:

@Service public class OrderContext { private MedicalOrder order; private OrderState currentState; @Autowired private ApplicationContext appContext; // 用于获取状态Bean public void transitionTo(String stateName) { OrderState nextState = (OrderState) appContext.getBean(stateName); if (currentState.canTransitionTo(nextState)) { currentState = nextState; currentState.handleAction(this.order, this); // 更新数据库中订单的状态字段 order.setStatus(stateName); updateOrderInDB(order); } else { throw new IllegalStateException("无法从状态[" + currentState + "]转换到[" + stateName + "]"); } } }

这样,当护士点击“执行医嘱”按钮时,后端服务只需调用orderContext.transitionTo("executingState")。所有的状态校验和伴随业务逻辑都封装在对应的状态类中,新增状态或修改规则变得非常清晰。

3.3 前端复杂表格与图表渲染优化

急诊系统的管理后台有大量数据表格(如患者列表、医嘱列表)和统计图表(如24小时就诊人次趋势图)。如果处理不当,页面性能会急剧下降。

对于大型表格(Vue + Element UI):

  1. 虚拟滚动:对于可能超过1000条的数据,我们使用了Element UI的el-table结合vue-virtual-scroller实现虚拟滚动。只渲染可视区域内的DOM元素,极大提升了渲染性能。
  2. 分页与懒加载:后端API支持分页查询,前端表格每次只加载当前页数据。对于表格内的展开行详情(如查看某患者的所有医嘱),采用懒加载方式,点击展开时才去请求数据。
  3. 列显示优化:允许用户自定义显示哪些列,减少不必要的数据绑定和DOM节点。

对于数据图表(ECharts):

  1. 按需引入:不使用完整的ECharts包,而是通过echarts/coreecharts/charts等按需引入的方式,减小最终打包体积。
  2. 数据抽样:当需要展示长时间段(如一年)的精细趋势图时,请求全部数据在前端渲染可能导致卡顿。我们与后端约定,当数据点超过一定数量(如1000个)时,后端进行降采样(如取日均值)后再返回。
  3. 防抖请求:在时间范围选择器组件上,应用防抖函数,避免用户快速切换范围时频繁发起请求。
// 使用lodash的debounce优化图表数据请求 import { debounce } from 'lodash'; export default { data() { return { fetchChartData: debounce(this.realFetchData, 500) // 500ms防抖 }; }, methods: { handleDateChange() { // 用户改变时间范围时,触发防抖函数 this.fetchChartData(); }, realFetchData() { // 实际发起API请求获取图表数据 axios.get('/api/statistics/visit-trend', {params: this.queryParams}).then(...); } } }

4. 数据库设计与核心业务逻辑实现

4.1 核心表结构设计解析

数据库设计是整个系统的基石。以下是几个核心表的设计思路:

1. 就诊记录表 (visit_record)这是整个急诊流程的“总纲”,一次就诊一条记录。

CREATE TABLE `visit_record` ( `visit_id` varchar(32) NOT NULL COMMENT '就诊流水号,主键', `patient_id` varchar(32) NOT NULL COMMENT '患者ID', `triage_level` tinyint(4) DEFAULT NULL COMMENT '分诊等级:1-濒危,2-危重,3-急症,4-非急症', `chief_complaint` varchar(500) DEFAULT NULL COMMENT '主诉', `status` varchar(50) NOT NULL DEFAULT 'REGISTERED' COMMENT '状态:REGISTERED, TRIAGED, RESCUING, OBSERVING, DISCHARGED, ADMITTED...', `register_time` datetime NOT NULL COMMENT '挂号时间', `discharge_time` datetime DEFAULT NULL COMMENT '离院时间', `attending_doctor_id` varchar(32) DEFAULT NULL COMMENT '接诊医生ID', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`visit_id`), KEY `idx_patient_id` (`patient_id`), KEY `idx_status_time` (`status`,`register_time`) -- 复合索引,用于高频查询 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='急诊就诊记录表';

设计要点:status字段使用明确的字符串,而非魔法数字,提高可读性。idx_status_time索引对于按状态和时段筛选患者的查询至关重要。

2. 医嘱表 (medical_orders) 与执行记录表 (order_execution)我们将其拆分为主表和执行表,以支持一条长期医嘱(如“测血压q6h”)对应多次执行记录。

CREATE TABLE `medical_orders` ( `order_id` bigint(20) NOT NULL AUTO_INCREMENT, `visit_id` varchar(32) NOT NULL COMMENT '关联就诊ID', `order_type` varchar(50) NOT NULL COMMENT '医嘱类型:MEDICATION(药品), EXAMINATION(检查), TREATMENT(治疗)', `order_content` varchar(1000) NOT NULL COMMENT '医嘱内容', `order_status` varchar(50) NOT NULL DEFAULT 'CREATED' COMMENT '状态:CREATED, VERIFIED, EXECUTING, COMPLETED, STOPPED', `frequency` varchar(100) DEFAULT NULL COMMENT '频次,如“每日一次”、“每6小时一次”', `doctor_id` varchar(32) NOT NULL COMMENT '开嘱医生', `create_time` datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`order_id`), KEY `idx_visit_status` (`visit_id`,`order_status`) ) ENGINE=InnoDB COMMENT='医嘱主表'; CREATE TABLE `order_execution` ( `execution_id` bigint(20) NOT NULL AUTO_INCREMENT, `order_id` bigint(20) NOT NULL COMMENT '关联医嘱ID', `scheduled_time` datetime NOT NULL COMMENT '计划执行时间', `actual_time` datetime DEFAULT NULL COMMENT '实际执行时间', `executor_id` varchar(32) DEFAULT NULL COMMENT '执行护士ID', `result_note` varchar(500) DEFAULT NULL COMMENT '执行结果备注', `status` varchar(50) DEFAULT 'PENDING' COMMENT '执行状态:PENDING, EXECUTED, CANCELLED', PRIMARY KEY (`execution_id`), KEY `idx_order_schedule` (`order_id`,`scheduled_time`) ) ENGINE=InnoDB COMMENT='医嘱执行记录表';

设计要点:拆分后,medical_orders表更稳定,而高频变动的执行记录放在order_execution表,符合数据库设计范式,也便于查询某条医嘱的所有执行历史。

4.2 关键业务逻辑:分诊与患者流转

分诊是急诊的“第一关”。其核心逻辑是根据患者的生命体征、主诉等,自动或手动计算出一个分诊等级(1-4级),并据此决定患者流向(立即抢救、优先就诊、普通排队等)。

后端分诊逻辑实现示例:我们设计了一个分诊规则引擎,规则可以配置(例如,存储在数据库表中)。当分诊护士提交信息时,后端会遍历规则进行计算。

@Service public class TriageService { @Autowired private TriageRuleRepository ruleRepository; public TriageResult evaluate(PatientTriageData data) { List<TriageRule> rules = ruleRepository.findActiveRules(); int totalScore = 0; String suggestedLevel = "4"; // 默认非急症 List<String> triggers = new ArrayList<>(); for (TriageRule rule : rules) { // 例如,规则:如果呼吸频率 > 30次/分,加5分 if ("respiratory_rate".equals(rule.getIndicator()) && data.getRespiratoryRate() > rule.getThreshold()) { totalScore += rule.getScore(); triggers.add(rule.getRuleName()); } // 规则:如果收缩压 < 90mmHg,加10分 if ("systolic_bp".equals(rule.getIndicator()) && data.getSystolicBP() < rule.getThreshold()) { totalScore += rule.getScore(); triggers.add(rule.getRuleName()); } // ... 其他规则,如血氧饱和度、意识状态等 } // 根据总分映射分诊等级 if (totalScore >= 15) { suggestedLevel = "1"; // 濒危 } else if (totalScore >= 10) { suggestedLevel = "2"; // 危重 } else if (totalScore >= 5) { suggestedLevel = "3"; // 急症 } TriageResult result = new TriageResult(); result.setSuggestedLevel(suggestedLevel); result.setScore(totalScore); result.setTriggeredRules(triggers); // 同时,根据分诊等级,自动更新就诊记录状态,并推送消息 if ("1".equals(suggestedLevel) || "2".equals(suggestedLevel)) { // 推送到抢救室大屏和护士站 messagingTemplate.convertAndSend("/topic/new-critical-patient", data.getVisitId()); } return result; } }

患者状态流转驱动业务:系统内很多操作都依赖于visit_record.status。我们使用Spring的事件发布机制来解耦状态变更后的后续动作。

// 1. 定义事件 public class PatientStatusChangedEvent extends ApplicationEvent { private String visitId; private String oldStatus; private String newStatus; // ... 构造方法和getter } // 2. 在更新状态的地方发布事件 @Service public class VisitRecordService { @Autowired private ApplicationEventPublisher eventPublisher; @Transactional public void updateStatus(String visitId, String newStatus) { VisitRecord record = visitRecordMapper.selectById(visitId); String oldStatus = record.getStatus(); record.setStatus(newStatus); visitRecordMapper.updateById(record); // 发布状态变更事件 eventPublisher.publishEvent(new PatientStatusChangedEvent(this, visitId, oldStatus, newStatus)); } } // 3. 监听事件,执行后续业务 @Component public class StatusChangeListener { @EventListener @Async // 异步处理,避免阻塞主流程 public void handlePatientStatusChanged(PatientStatusChangedEvent event) { if ("RESCUING".equals(event.getNewStatus())) { // 状态变为“抢救中”,自动创建抢救记录模板 rescueRecordService.createTemplate(event.getVisitId()); // 通知相关医护人员 notificationService.notifyRescueTeam(event.getVisitId()); } if ("DISCHARGED".equals(event.getNewStatus())) { // 状态变为“已离院”,自动结算未结费用(调用HIS接口) billingService.settleUnpaidOrders(event.getVisitId()); // 释放床位资源 bedService.releaseBedByVisitId(event.getVisitId()); } } }

这种事件驱动的方式,使得核心的状态变更服务保持简洁,而各种复杂的后续业务(通知、创建记录、结算)由专门的监听器处理,系统扩展性大大增强。

5. 项目部署、配置与常见问题排查

5.1 从零开始的环境搭建与部署

拿到源代码后,要成功运行起来,需要按顺序完成以下步骤:

1. 后端环境准备:

  • JDK:确保安装 JDK 8 或 11(Spring Boot 2.x 兼容版本)。在终端输入java -version验证。
  • Maven:安装 Maven 用于管理依赖和构建项目。解压源码后,在根目录(含pom.xml的文件夹)运行mvn clean install下载依赖并打包。
  • MySQL:安装 MySQL 5.7 或以上版本。使用sql/init_database.sql文件(如果项目提供)创建数据库和表结构。如果没有,需要根据实体类手动建表。
  • Redis (可选但推荐):如果项目使用了Redis做缓存或Session存储,需要安装并启动Redis服务。

2. 关键配置文件修改:核心配置文件是src/main/resources/application.ymlapplication.properties

spring: datasource: url: jdbc:mysql://localhost:3306/emergency_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai username: your_username password: your_password driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 # password: 如果有密码则配置 # 文件上传路径配置(用于存储上传的检查报告等) servlet: multipart: max-file-size: 10MB max-request-size: 100MB # 自定义配置,如JWT密钥、文件存储路径等 hospital: file: upload-path: /data/upload/emergency jwt: secret: your-256-bit-secret-key-here # 务必修改! expiration: 86400000 # token有效期,单位毫秒

注意:jwt.secret是安全关键项,必须使用一个足够复杂且保密的字符串替换,切勿使用默认值。

3. 前端环境准备与运行:

  • Node.js:安装 Node.js (建议 LTS 版本),自带 npm。
  • 进入前端项目目录(通常包含package.jsonvue.config.js)。
  • 运行npm installyarn install安装所有依赖。国内用户建议配置淘宝镜像:npm config set registry https://registry.npmmirror.com
  • 修改前端配置文件,通常是src/config/index.js.env.development,将API请求的基地址指向你的后端服务地址(例如VUE_APP_API_BASE_URL=http://localhost:8080)。
  • 运行npm run serve启动开发服务器,或npm run build构建生产环境静态文件。

4. 部署上线:

  • 后端:使用mvn clean package打包生成target/emergency-system-0.0.1-SNAPSHOT.jar。然后通过java -jar emergency-system-0.0.1-SNAPSHOT.jar --spring.profiles.active=prod命令启动。生产环境建议使用 nohup 或 systemd 托管。
  • 前端:运行npm run build生成dist文件夹。将其内容部署到Nginx或Apache等Web服务器上。并配置反向代理,将/api等请求转发到后端Spring Boot应用。
  • Nginx 配置示例:
    server { listen 80; server_name your-domain.com; location / { root /path/to/your/dist; index index.html; try_files $uri $uri/ /index.html; # 支持Vue Router的history模式 } location /api/ { proxy_pass http://localhost:8080/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # WebSocket代理配置 location /ws-emergency/ { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }

5.2 开发与运行中的典型问题及解决

在开发和部署这个系统的过程中,我们踩过不少坑,这里总结几个最常见的问题:

1. 前端跨域问题 (CORS)在开发阶段,前端运行在localhost:8081,后端在localhost:8080,浏览器会因同源策略阻止请求。

  • 解决方案:在后端Spring Boot中配置全局CORS。
    @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOriginPatterns("*") // 生产环境应指定具体域名 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .allowCredentials(true) .maxAge(3600); } }

    注意:生产环境allowedOriginPatterns务必替换为实际的前端域名,如"https://hospital.example.com",使用"*"存在安全风险。

2. 前端路由在刷新后404使用Vue Router的history模式,在非根路径刷新页面时,Nginx会尝试去找对应的文件,导致404。

  • 解决方案:如上文Nginx配置所示,关键是在location/块中添加try_files $uri $uri/ /index.html;这行配置,将所有非静态文件的请求重定向到index.html,由前端路由接管。

3. 数据库连接池耗尽或慢查询在高并发下,可能出现“Cannot get connection from pool”错误或接口响应极慢。

  • 排查与解决:
    • 检查连接池配置:application.yml中优化HikariCP(Spring Boot默认连接池)参数,如maximum-pool-sizeconnection-timeout
    • 分析慢查询日志:在MySQL中开启慢查询日志slow_query_log=ON,找到执行时间过长的SQL。
    • 优化索引:使用EXPLAIN分析慢查询SQL的执行计划,检查是否缺少索引或索引失效。例如,为visit_record表的statusregister_time字段添加复合索引,对提升按状态和时间筛选的查询速度效果显著。
    • 代码层面:检查是否有在循环中执行SQL查询的“N+1查询问题”,应使用MyBatis的<collection>@Many注解进行关联查询,或手动编写联表SQL。

4. 文件上传失败或路径错误系统需要上传检查报告、知情同意书等文件。

  • 常见问题:配置的spring.servlet.multipart.max-file-size太小;文件存储路径不存在或应用没有写入权限。
  • 解决:
    1. 确保配置的文件大小限制足够。
    2. 在代码中或启动脚本里,检查并创建上传目录。
      @PostConstruct public void init() { File uploadDir = new File(uploadPath); if (!uploadDir.exists()) { uploadDir.mkdirs(); } }
    3. 在Linux服务器上,确保运行Java进程的用户(如www-datajavaapp)对该目录有读写权限:chown -R javaapp:javaapp /data/upload/emergency

5. WebSocket连接不稳定大屏或客户端偶尔收不到实时消息。

  • 排查:
    1. 检查Nginx代理配置是否正确支持WebSocket升级(见上文配置)。
    2. 前端增加连接状态监听和自动重连逻辑。
      stompClient.connect({}, onConnected, (error) => { console.error('连接失败,5秒后重连...', error); setTimeout(this.connectWebSocket, 5000); });
    3. 检查服务器防火墙是否放行了WebSocket使用的端口(通常是80/443或自定义端口)。

这个急诊系统项目,从技术选型到业务落地,涵盖了现代Web应用开发的多个核心环节。它不仅仅是一套代码,更是一套解决特定领域复杂问题的设计思想和工程实践的集合。对于学习者,我建议不要只停留在运行起来的层面,可以尝试去修改分诊规则、增加一个新的医嘱类型、或者优化一下那个复杂表格的渲染性能,在这个过程中遇到问题并解决,才是提升的真正途径。最后,在处理任何医疗相关数据时,请务必牢记数据安全和隐私保护,这是开发的底线。

本文还有配套的精品资源,点击获取

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

信号滤波工程实践:从频谱分析到Python参数调优

刚做信号处理的人&#xff0c;一定都有过这种体验&#xff1a;辛辛苦苦采回来的波形满是毛刺&#xff0c;同事扔过来一句“加个滤波不就行了”&#xff0c;你打开代码&#xff0c;面前却是一堆选择题——低通还是高通&#xff1f;Butterworth 还是 Chebyshev&#xff1f;I 阶还…

作者头像 李华
网站建设 2026/9/4 4:07:58

FPGA实现1024点FFT:从算法原理到Verilog流水线设计实战

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

作者头像 李华
网站建设 2026/9/4 4:07:27

中式小汉堡:家常食材打造营养均衡减脂餐

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

作者头像 李华
网站建设 2026/9/4 4:07:08

ABAQUS内聚力模型插件Insert_czm_to_abaqus_input实战指南

简介&#xff1a;本资源是面向ABAQUS中高级用户与断裂力学仿真研究者的专用插件工具包&#xff0c;聚焦裂纹扩展模拟中的内聚力模型&#xff08;CZM&#xff09;自动化建模难题&#xff0c;显著降低CZM单元在inp文件中手动插入的复杂度与出错率。资源共82个文件&#xff0c;涵盖…

作者头像 李华
网站建设 2026/9/4 4:07:07

开源AI基建盘点:五大方向有效抑制大模型幻觉

先给结论&#xff1a;这篇盘点不是推荐某一款模型&#xff0c;而是整理 5 类能让 AI 输出更可控、更少“一本正经胡说八道”的开源基建方向——统一工作区、端侧模型、本地大模型推理、检索引擎、决策图谱。它们解决的问题不一样&#xff0c;组合起来&#xff0c;正好是一条“入…

作者头像 李华