资讯动态

云医院系统前后端分离代码实战:架构解析、启动与避坑指南

发布时间:2026/10/11 11:49:56 来源:尧图企业网站定制
简介东软云医院系统前后端代码是一份面向医疗信息化领域实训教学的完整工程包基于SpringBoot与Vue.js技术栈覆盖在线预约、电子病历、药品库存、远程诊疗等典型业务场景适合正在学习JavaWeb全栈或想了解医疗系统架构的开发者参考。压缩包共500个文件约1.31MB包含172个Java源文件、171个class编译文件、84个XML配置、41个Vue组件以及SQL脚本、yml配置文件、Maven封装脚本等前后端代码与数据库脚本分层清晰便于直接导入IDE研究。目前已有563人学习下载项目从实体类、控制器、服务层到DAO层均有完整实现并附带注册、挂号、收费、药品管理等模块的可运行逻辑能够帮助学习者快速掌握SpringBoot自动配置、MyBatis映射和Vue组件化开发的实际协作方式也为医疗信息化课程设计或实训答辩提供了可直接落地的参考方案。1. 云医院系统前后端代码先看架构再动手否则连不上数据库拿到一套云医院系统前后端代码第一反应通常是“先跑起来看看”。但这类系统和普通后台管理系统不一样它不是一个单一应用而是由预约挂号、门诊医生站、护士站、药房、收费、检验检查等多个子系统组成的前后端分离工程。如果直接从前端页面开始点大概率卡在登录接口返回 401或者数据库连接失败。更麻烦的是这类代码往往带着完整的科室、员工、药品等初始化数据数据库脚本体积大依赖关系复杂稍不留神就会执行一半报错。本文我会按照从架构到落地的顺序把这类系统的代码结构、启动步骤、接口链路和常见坑位拆开让想二次开发或学习医疗业务的新手能少走弯路也让有经验的开发者能快速定位改造边界。2. 先看懂系统骨架云医院系统的模块划分与技术栈选型2.1 前后端分离架构里哪些模块是必须的云医院系统的前端通常分为患者端小程序/App/H5和医生端Web 管理台。后端则按业务域拆分成若干个微服务或模块化单体。常见做法是网关层负责认证鉴权、路由转发和限流基础服务负责用户、角色、科室、机构、数据字典业务服务负责挂号、分诊、医生工作站、收费、药房、检查检验集成服务负责支付、短信、医保接口等。这里要强调一点如果你拿到的代码是模块化单体那一般是一个 Spring Boot 工程内包含多个 Maven 模块运行时是一个进程。如果是微服务版则需要额外启动注册中心、配置中心和网关复杂度会高不少。我建议新手先明确自己拿到的是哪种形态这决定了后续启动方式和调试成本。判断方法很简单看后端根目录下有没有eureka、nacos、spring-cloud-gateway相关依赖以及是否有bootstrap.yml文件。2.2 常见技术栈组合后端 Spring Boot、前端 Vue 系医疗云 HIS 系统在中小型项目里最常见的组合是后端用 Java 8/11 Spring Boot Spring Security MyBatis-Plus MySQL前端用 Vue 2/3 Element UI Axios Vue Router Pinia/Vuex。有些较新的版本会引入 Redis 做会话和验证码缓存用 RabbitMQ 做异步消息比如挂号成功后的短信通知。了解技术栈的目的不是为了背清单而是为了后续启动时选择合适的 JDK 和 Node 版本。比如 Spring Boot 2.x 用 Java 8 最稳Vue 2 项目在 Node 16 以下环境构建更不容易报错。如果你直接用 Node 20 去跑一个依赖node-sass的老项目十有八九会在npm install阶段翻车。反过来如果你的代码是 Spring Boot 3.x 和 Vue 3那 JDK 17 和 Node 18 是更合理的选择。先确认版本再动手能省掉一半的玄学报错。另外数据库选型也要注意。绝大多数云医院系统用的是 MySQL但有些版本会使用 PostgreSQL 或 Oracle。你需要在pom.xml或application.yml里确认驱动依赖。如果代码里用了to_char、sysdate这类 Oracle 语法那在 MySQL 下执行 SQL 必然报错不要强行兼容。2.3 代码仓目录结构与关键文件定位拿到代码后第一件事是看顶层目录。典型结构如下cloud-hospital/ ├── backend/ │ ├── pom.xml │ ├── src/main/java/ │ ├── src/main/resources/ │ │ ├── application.yml │ │ ├── application-dev.yml │ │ └── sql/ │ │ ├── schema.sql │ │ └── data.sql ├── frontend/ │ ├── package.json │ ├── vite.config.js │ └── src/ │ ├── api/ │ ├── views/ │ ├── router/ │ └── store/ └── docs/重点找三个文件后端的application.yml、前端的接口封装文件src/api/、以及数据库初始化脚本sql/下的.sql文件。这一步能让你在 5 分钟内判断这套代码是单体还是微服务以及数据库是 MySQL 还是 PostgreSQL。我一般会先搜索spring.cloud和eureka关键词判断有没有注册中心。还有一个容易被忽略的文件是README.md或docs/deploy.md。很多项目会把启动顺序、默认账号、端口分配写在里面。但现实是这种文档往往不完整写着“见某某文档”就断了。所以别把希望全寄托在文档上自己去看配置和 SQL 脚本更靠谱。3. 把前后端跑起来环境准备、数据库初始化和最小启动命令3.1 环境清单与版本匹配建议先准备好基础环境不要用最新版用稳定版能省很多事。下面是我通常建议的版本组合组件版本建议说明JDK1.8 或 11Spring Boot 2.x 对应 83.x 对应 11/17Maven3.6管理后端依赖MySQL5.7 或 8.05.7 对老 SQL 更兼容Node.js14 或 16Vue 2 项目在 16 下构建最稳Redis5.0若用到缓存和验证码必须启动这里注意如果项目用了高版本的依赖比如 Spring Boot 2.7那么 JDK 8 完全没问题。如果代码里用的是javax包千万别把javax换成jakarta那是另一个大坑。另外MySQL 8.0 和 5.7 在连接驱动和时区处理上有差异如果代码里的 JDBC 驱动是com.mysql.jdbc.Driver那在 MySQL 8 下会报错要改成com.mysql.cj.jdbc.Driver。3.2 后端启动改配置文件、初始化数据库、启动入口后端启动的核心是让数据库先就绪。首先创建数据库实例然后执行初始化脚本。很多人在这里翻车因为脚本可能拆成schema.sql和data.sql后者需要依赖前者的表结构顺序不能乱。常见做法是-- 创建数据库字符集必须用 utf8mb4否则医学符号存不进去 CREATE DATABASE IF NOT EXISTS cloud_hospital DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; use cloud_hospital; -- 先执行结构脚本再执行数据脚本 source /path/to/schema.sql; source /path/to/data.sql;这里utf8mb4非常重要。医疗系统里会存患者姓名、诊断描述、药品说明经常出现生僻字和特殊符号如果库字符集是utf8某些生僻字会变成?而且影响后续写入。如果你已经创建了utf8的库可以用ALTER DATABASE ... CHARACTER SET utf8mb4转换但表结构已经有的字段需要单独改很麻烦。接着修改后端的application-dev.yml核心是数据源配置server: port: 8080 spring: datasource: url: jdbc:mysql://localhost:3306/cloud_hospital?useUnicodetruecharacterEncodingutf8mb4useSSLfalseserverTimezoneAsia/Shanghai username: root password: yourpassword driver-class-name: com.mysql.cj.jdbc.Driver redis: host: localhost port: 6379 database: 0 mybatis: mapper-locations: classpath:mapper/**/*.xml configuration: map-underscore-to-camel-case: true这里map-underscore-to-camel-case: true是 MyBatis 的经典配置能把user_name映射成userName省去大量手写 ResultMap。如果没有这个配置查询结果会返回user_name字段而实体里是userName前端拿不到数据接口返回一堆空对象。启动后端用 Maven 命令cd backend mvn clean package -DskipTests java -jar target/cloud-hospital-backend.jar如果想调试用mvn spring-boot:run。启动成功的标志是控制台出现Started Application in x seconds同时访问http://localhost:8080/actuator/health能看到{status:UP}。如果端口被占用可以在启动命令里加--server.port8082。3.3 前端启动依赖安装、代理转发、登录页验证前端相对简单但要处理好开发环境的代理。Vue 开发服务器默认端口是 8080和后端冲突所以通常会改为 8081并把/api开头的请求代理到 8080。配置在vite.config.js或vue.config.js里// vite.config.js import { defineConfig } from vite import vue from vitejs/plugin-vue export default defineConfig({ plugins: [vue()], server: { port: 8081, proxy: { /api: { target: http://localhost:8080, changeOrigin: true, // 后端接口可能没有 /api 前缀需要重写 rewrite: (path) path.replace(/^\/api/, ) } } } })这里changeOrigin: true会把请求头里的Host改成目标地址避免后端基于Host做判断时报错。rewrite很关键因为前端代码里通常把baseURL设为/api而后端controller的RequestMapping可能不包含这个前缀。如果不重写请求会打到后端不存在的路径上返回 404。安装依赖和启动cd frontend npm install npm run dev如果npm install报node-sass错误是因为 Node 版本太新。解决办法是移除node-sass改用sass或者直接切到 Node 16。node-sass需要从 GitHub 下载二进制文件网络不稳时也会挂改用sass之后会省心很多。启动后打开页面用默认账号登录。如果卡在验证码加载不出来多半是 Redis 没启动而不是前端代码问题。4. 看懂前后端交互从登录到问诊的接口链路与权限设计4.1 认证流程令牌如何下发、刷新和失效云医院系统的登录逻辑和普通系统差异不大但有一个关键点用户角色必须和机构绑定比如医生属于某个科室科室属于某个院区。前后端通过 JWT 或类似令牌维护会话。常见流程是前端提交账号密码验证码校验在后端完成。后端校验通过后生成 token返回用户信息、角色列表、权限标识。前端将 token 存入 localStorage并在 Axios 拦截器里自动加到请求头。后端网关或过滤器解析 token并把用户上下文塞进 ThreadLocal。一个常见问题是退出登录时只清掉前端 token后端 token 还在有效期内。JWT 无状态后端无法主动让它失效解决办法是维护一个 Redis 黑名单在退出时把jtitoken 唯一标识加入黑名单并设置过期时间。如果你要改造登录模块记得同时改前后端两边的处理逻辑否则会出现“退出后点返回还能访问接口”的安全漏洞。4.2 一个典型业务接口挂号时的参数校验与数据落库挂号接口能反映整套系统的核心逻辑。前端传参通常包括患者 ID、科室 ID、医生 ID、号源类型、预约时间段、费用类型。后端要做的事有校验患者是否存在、是否在黑名单校验医生当天是否有出诊排班号源是否未满校验费用的医保类型计算自付金额插入挂号记录扣减号源生成就诊序号发送预约成功短信异步。代码里常见的落库逻辑如下Transactional public RegisterResult register(RegisterRequest request) { Patient patient patientMapper.selectById(request.getPatientId()); if (patient null) { throw new BizException(患者不存在); } Schedule schedule scheduleMapper.selectById(request.getScheduleId()); if (schedule.getRemaining() 0) { throw new BizException(号源已满); } // 扣减号源注意用乐观锁避免并发超卖 scheduleMapper.decreaseRemaining(request.getScheduleId()); Register register new Register(); register.setPatientId(patient.getId()); register.setScheduleId(schedule.getId()); register.setStatus(1); register.setRegisterNo(registerNoGenerator.next()); registerMapper.insert(register); return new RegisterResult(register); }注意Transactional保证事务同时scheduleMapper.decreaseRemaining里的 SQL 应是update schedule set remaining remaining - 1 where id #{id} and remaining 0这种方式比先查出remaining再更新更能防并发。如果不加remaining 0条件两个请求同时读到remaining1都去执行set remaining remaining - 1最后会变成 0但第二个请求应该被拒绝。这种“先检查再扣减”的经典并发问题在挂号系统里最容易出现也是需要重点测试的地方。4.3 前后端联调时接口文档的用法这类代码里通常会带 Swagger 或 Knife4j启动后端后访问http://localhost:8080/doc.html能看到接口列表。联调时我习惯先找到挂号接口看它的请求参数和响应结构然后对照前端src/api/register.js里的方法名确认参数映射。前端调用方式一般是import request from /utils/request export function createRegister(data) { return request({ url: /register/create, method: post, data }) }联调卡住时先看浏览器 Network 面板检查请求是否被代理转发、是否携带了 token、响应状态码是 401 还是 500。如果是 500立刻看后端日志的堆栈第一行绝大多数是空指针或数据库字段不匹配。如果返回 404确认一下前端请求的 URL 是不是被rewrite写错了如果返回 405大概率是GET/POST方法不匹配。这些小问题的排查方向比看接口文档更实际。5. 云医院系统改造避坑5 个让人翻车的真实问题5.1 数据库脚本执行一半失败现象执行source data.sql时提示Unknown column或外键约束失败。原因脚本里的表创建顺序没有被正确处理比如先插科室记录但科室表还没有建好。另一个常见原因是data.sql中插入了重复主键或者在已有数据的库上重新执行脚本。解决先执行结构脚本并且检查结构脚本里是否包含DROP TABLE IF EXISTS。如果有千万不要在已有库里直接跑整个脚本否则数据会被清空。我一般会把脚本拆成按模块执行先建基础表用户、机构、科室再建业务表挂号、处方、收费最后插入数据。每一次执行都先备份。这里分享一个血泪经验某次我在测试库上直接跑了全量脚本把生产库同步过来的测试数据全冲掉了后来花了半天重新造数。从那以后我执行任何data.sql前都会先mysqldump备份。5.2 前端请求跨域被拦现象浏览器控制台报CORS policy或No Access-Control-Allow-Origin header。原因前端端口是 8081后端是 8080开发环境下需要代理如果直接请求http://localhost:8080/api就会触发跨域拦截。解决优先配置前端代理而不是在后端开CrossOrigin。因为生产环境通常由 Nginx 做同源转发代码里开了跨域反而会暴露接口。如果实在想在后端解决可以在后端加一个过滤器只允许 localhost 来源别用*。注意用了代理之后浏览器 Network 面板里看到的请求 URL 仍然是http://localhost:8081/api/...但实际后端收到的是http://localhost:8080/...所以排查时别被前台 URL 迷惑。5.3 本地环境和线上环境配置没分离现象本地启动成功但把 jar 包部署到测试环境数据库连不上。原因application.yml里写死了本地地址没有使用 Profile 区分环境。解决把不同环境拆成application-dev.yml、application-prod.yml启动时用--spring.profiles.activeprod指定。同时把数据库密码等敏感信息放到环境变量里代码中只引用占位符spring: datasource: password: ${DB_PASSWORD:}这样本机可以留空测试环境通过环境变量注入。如果代码里还有jasypt加密配置注意密文会绑定机器环境换环境启动会报解密失败这是另一个黑匣子最好在改造初期就统一处理。5.4 金额和时间字段精度问题现象收费金额显示是10.000000001或者日志时间比本地晚 8 小时。原因数据库金额字段用了double或float时间用了默认timestampJVM 时区和数据库时区不一致。解决金额一律用decimal(10,2)实体用BigDecimal。如果 MySQL 里已经是double要转换字段类型。时间问题在 JDBC URL 里加serverTimezoneAsia/Shanghai同时保证数据库连接的时区参数与服务器一致。前端展示金额时不要用parseFloat因为二进制浮点数会有精度误差正确做法是用toFixed(2)或者直接展示后端返回的字符串。如果你在前端做金额累加更要用整数分做运算避免浮点累加误差。5.5 用户表里的机构隔离被忽略现象开发人员测试时能看到别的医院的患者数据。原因云医院系统往往是一个平台多个医院/机构共用一套代码通过org_id做数据隔离。但很多人写 SQL 时忘了带org_id条件导致越权查询。解决写查询时在 SQL 条件里强制拼接当前用户的org_id而不是依赖前端传参。可以在 MyBatis 拦截器里统一处理也可以在每个 Mapper 的 XML 里手动加上and org_id #{orgId}。这是一条安全红线做二次开发时一定要优先处理。我见过一个模拟项目X因为漏了机构隔离导致 A 医院的医生在搜索患者时能看到 B 医院的患者姓名和身份证号这是合规事故级别的 bug。测试时至少用两个不同机构账号交叉验证数据是否隔离。6. 让这套代码真正变成自己的模块替换与验证技巧6.1 从替换登录页到换掉整个认证模块如果你拿这套代码是为了快速搭建自己的产品不要把时间花在改业务代码上而是先替换认证和用户界面。第一步是改前端登录页把云医院系统的 logo、标题、配色换成自己的第二步是改后端登录接口的返回字段比如增加企业自定义属性第三步才是改数据库字典表比如机构名称、科室名称。这样做的目的是先跑通一条最小闭环用户登录、看到首页、跳转到挂号列表。很多开发者一上来就改挂号逻辑结果三天都没法登录进去进度卡在最前端。我的习惯是在改造前先git init并提交一次原始代码作为基线这样即使改坏了也能用git checkout回到原始状态。这个操作相当于给自己留了一颗后悔药。后续每完成一个模块就提交一次方便对比差异。如果你用 Git 管理还能用git log -p追踪某个字段是哪个版本引入的。6.2 用接口联调日志定位前后端责任前后端联调时最怕互相甩锅。前端说“我请求发对了”后端说“我没收到参数”。我的做法是在后端写一个简单的过滤器把每个请求的 URL、方法、参数、响应状态和耗时打印出来这样出问题时能根据日志判断是谁的问题。Component public class ApiLogFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long start System.currentTimeMillis(); HttpServletRequest req (HttpServletRequest) request; // 简化输出实际项目里用 logback 记录到单独文件 System.out.println(req.getMethod() req.getRequestURI()); chain.doFilter(request, response); long cost System.currentTimeMillis() - start; System.out.println(req.getRequestURI() cost cost ms); } }然后在排查问题时前端把某个接口的请求参数和返回结果从浏览器 Network 面板复制出来后端对照日志里的输入输出很快就能定位是参数名不对、类型不对还是后端逻辑抛异常。在真实联调中大部分 400 错误都是因为前端把参数名写成了patientId而后端要求的是patient_id或者是 JSON 里多了一层data包装。另外我还习惯在前端请求封装的request.js里加一个响应拦截器当后端返回业务码非 200 时把message直接用ElMessage.error弹出来。这样前端负责人能第一时间看到后端给出的具体报错而不是去猜。说一个我自己的教训有一次在改一个挂号系统时我以为把remaining 0写在更新语句里就万无一失了结果因为没有把Transactional加到方法上两条并发请求同时进入最终号源变成了负数。后来我把事务注解补上还在数据库层面加了CHECK (remaining 0)约束。从那以后我养成了一个习惯凡是涉及库存、号源、金额的字段必须在数据库层面兜底校验一次不能只靠应用层。这也是我想提醒你的代码跑通只是第一步把并发、数据隔离和精度问题处理干净这套系统才算真的能交付。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑