资讯动态

SpringBoot+Uniapp医疗云平台源码:三端闭环与部署实战解析

发布时间:2026/10/27 8:28:11 来源:尧图企业网站定制
简介E疗通综合医疗云平台是一套基于SpringBoot 2.x与Uniapp的完整医疗系统源码面向需要搭建在线问诊与私人医生定制业务的开发者、产品经理或医疗信息化项目团队。平台参考京东健康与好医生模式完整包含后台管理、PC端及手机端实现名医在线一对一咨询、电子处方流转与药剂师审核、模拟医保购药、病患跟踪和智能用药提醒等核心功能同时覆盖用户端、运营端与医生端链路完整可直接演示或二次开发。后端采用SpringBoot集成Mybatis-Plus、SpringSecurity、Redis与MySQL8.0提供Swagger接口文档前端包含VueElementUI的Web后台和Uniapp的移动端APP模块化结构清晰便于学习复用。压缩包共2000个文件以1018个Java接口代码、500个Vue页面、297个JS逻辑文件为主另含XML、JSON、SQL、Shell脚本等配置与部署资源包体约79.73MB。已有166人学习下载适合具备SpringBoot与Vue基础、希望获得可落地工程方案的中高级Java全栈开发人员。1. 一套医疗云平台源码最值钱的不是页面而是三端闭环的业务链路「基于 SpringBoot Uniapp 的综合医疗云平台」这类源码我前后接手过三个版本形态大同小异患者用的 Android/iOS APP 一套、医生和运营用的后台管理一套、对外展示的 PC 门户一套后端清一色 SpringBoot MySQL。拿到代码后先别急着点运行最值钱的不是某个页面画得多好看而是「患者在线问诊 → 医生开方 → 运营后台排班统计 → 私人医生随访」这条链路在同一条数据库里闭环。它适合三类人想快速跑通互联网医疗 demo 找融资的团队、需要一套能答辩能演示的课设或毕设进阶项目的人、接了医疗外包但缺底层代码的开发者。有了这套东西原本从零建模要两个月的工作量可以压缩到两周。2. 拆开这套架构后端 SpringBoot、多端 Uniapp 与 PC 管理端各自的分工这套源码在工程结构上一般分成三个并列目录后端一个 SpringBoot 工程负责所有接口、鉴权、支付回调、定时任务APP 与 H5 共一个 Uniapp 工程一份代码产出 Android、iOS、微信小程序和 H5 页面PC 管理端通常是一个 Vue 工程部署方式有两种要么独立 Nginx 托管要么打包成静态文件塞进 SpringBoot 的 resources/static 目录。三端共用同一套/api接口只是页面载体不同。2.1 为什么这套方案选 SpringBoot Uniapp而不是 SpringCloud 或原生 App常见做法是 SpringBoot 2.x MyBatis-Plus MySQL 组合理由很直接生态成熟、招人容易、部署简单一个 jar 包扔到服务器就能跑。管理后台用 Vue Element UI 是因为组件现成表格、表单、权限菜单这类后台页面几乎不用自己写样式。Uniapp 能进这个组合核心原因是医疗 C 端必须同时覆盖微信小程序和 APP一套代码出多端比原生开发省掉一整支前端团队。对比一下就清楚后端如果换成 SpringCloud 微服务单机 demo 反而要多维护注册中心、网关、配置中心三套组件对这套业务量来说是负资产APP 如果换成 Flutter 或 React Native微信小程序仍然要单独维护一份代码等于同时养两套前端。标题里的组合是「做省力」的选型不是「做炫技」的选型看懂这一点后续二开就不会动辄想重构。2.2 核心业务模块在线问诊、私人医生定制、健康档案的数据流在线问诊的主链路是用户选科室、提交病情描述 → 创建问诊订单状态为待支付→ 支付成功进入待接诊 → 医生接诊后进入接诊中 → 图文或语音对话 → 医生写处方 → 用户确认处方 → 订单完成。状态机一般收敛在一个 service 类里每次改状态都要校验前置状态防止并发请求把订单状态改乱。这条链路里最容易写崩的是支付回调回调成功但订单状态没同步用户付款了却看不到医生接诊二开时优先检查这块的幂等处理。私人医生定制的本质是「会员订阅 服务计划」。用户购买套餐后系统在 member_subscription 表插入订阅记录并绑定一个医生医生按周期生成随访计划系统每天按计划生成待办提醒随访结果写回 health_record 表最终在 APP 端展示成趋势图表。PC 管理后台承担的则是医生排班、问诊订单列表、支付对账、健康资讯发布、会员到期续费提醒。数据归属上问诊订单是绝对主干chat_message 和 prescription 都挂 inquiry_order_id 外键健康档案不直接挂订单而是用户级汇总表——这样统计医生月接诊量、科室热门病种时SQL 只查订单表和关联表不用去翻聊天记录。2.3 数据库核心表从用户体系到随访计划这套源码的数据库一般包含十几张核心表我按业务权重排了个清单表名职责关键字段sys_user患者、医生、管理员统一账号体系user_type, status, mobiledoctor_info医生扩展信息doctor_no, title, specialty, service_package_iddepartment科室树parent_id, name, sortinquiry_order问诊订单主干order_no, user_id, doctor_id, status, fee, create_timechat_message图文、语音消息inquiry_order_id, sender_type, content, create_timeprescription处方inquiry_order_id, doctor_id, disease_name, medicine_json, statushealth_record健康档案user_id, record_type, content_jsonmember_subscription私人医生订阅user_id, doctor_id, package_id, expire_date, statusfollow_plan随访计划subscription_id, plan_json, cron_expr, next_run_time先说一个容易踩的坑订单表里通常会冗余 doctor_name、user_name 这类快照字段原因是「历史快照」——医生后来改名或离职订单里仍然要显示当时服务的人。二开时不要图省事把它改成纯关联表否则历史订单查询会多出大量 join一期数据量上来后性能明显变差。另一个要点是处方明细常用 JSON 存原因很简单开方页面的动态表单比固定字段更灵活但要统计药品使用频次就得用 MySQL 的 JSON_TABLE 函数不是普通 where 能搞定的。数据库这块不需要会复杂的增删改查技巧把表间关系理清楚比会写一百条 SQL 更重要。3. 本地跑通后端建库、改 yml、启动 SpringBoot 的最小命令集拿到源码的第一天我建议只做三件事建库导数据、改配置、启动 jar 包验证接口。不要一上来就翻业务代码先把地基打实。以下命令和配置以常见的 MySQL 8.0 SpringBoot 2.x 为例具体文件名以你拿到手的工程为准。3.1 初始化 MySQL导入 SQL 前的字符集与时区准备mysql -uroot -p -e CREATE DATABASE IF NOT EXISTS health_cloud DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -uroot -p health_cloud /path/to/health_cloud.sql第一行建库第二行把源码包里的 SQL 文件导入。如果 SQL 脚本里自己带了 CREATE DATABASE 和 USE 语句第一行可以跳过直接执行第二行重复建库不会报错但会把原有数据覆盖掉操作前确认这个库是全新环境。字符集必须用 utf8mb4因为问诊描述、处方备注里大概率出现 emoji 和生僻字老版本的 utf8 字符集会报乱码或 1366 错误MySQL 8.0 默认就是 utf8mb4但如果脚本内部写了旧字符集建议先全局替换再导入。导入完成后别急着关终端先验证数据是否完整select count(*) from sys_user;如果主表都不存在说明导错了库或脚本本身不完整。顺手把 MySQL 时区确认一下JDBC 连接串里会用到 Asia/Shanghai数据库服务器的时区不一致时时间字段会差 8 小时排查起来非常消耗耐心。3.2 application.yml 里必改的四个配置项spring: datasource: url: jdbc:mysql://localhost:3306/health_cloud?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalseallowPublicKeyRetrievaltrue username: health password: Health2024 driver-class-name: com.mysql.cj.jdbc.Driver servlet: multipart: max-file-size: 50MB max-request-size: 100MB file: upload-path: D:/health-cloud-upload/ access-path: /files/** jwt: secret: change-me-to-a-random-string-at-least-32-chars-long expire: 7200 server: port: 8080 mybatis-plus: mapper-locations: classpath*:mapper/**/*.xml configuration: map-underscore-to-camel-case: true这是改动最密集的文件四个重点项逐个说。数据源 URL 里的allowPublicKeyRetrievaltrue是 MySQL 8.0 的专属需求caching_sha2_password 插件首次连接时要向服务器要公钥不加这个参数会报 Public Key Retrieval is not allowed属于最常见的 SpringBoot 配置问题。file 段是后端的静态资源映射upload-path是文件落盘目录access-path是浏览器访问路径前缀它们必须成对出现后面第 5 章的图片 404 就是这里没配对。jwt.secret 必须手动换成一个 32 位以上的随机串源码包自带的默认值等于把鉴权拱手送人。MyBatis-Plus 的 mapper-locations 一定要写classpath*:带星号否则打成 jar 包后 mapper.xml 扫不到启动不报错一调接口就说 invalid bound statement。3.3 启动并用 curl 验证先看日志再打接口cd health-cloud-server mvn clean package -DskipTests java -jar target/health-cloud-server-1.0.0.jar --spring.profiles.activedev # 另开一个终端验证 curl -i http://localhost:8080/api/doctor/list?current1size10打包启动比 IDE 里直接跑 main 类更接近生产环境能提前暴露资源目录缺失、mapper 扫描不到这类问题。启动日志里看到 Started 才算成功如果报端口占用用lsof -i:8080找出占用进程处理掉或者直接改 server.port。curl 返回 200 只代表 HTTP 层通还要看响应体里的业务 code 是否为 0很多源码的返回结构是{code: 0, data: {...}, msg: success}code 非 0 说明后端业务本身报错了。带鉴权的接口先用 /api/login 拿 token再带Authorization: Bearer token请求把这条链路验证通后端就基本算跑起来了。4. Uniapp 多端与 PC 管理端联调APP、小程序、后台管理连同一个后端后端跑通后接下来把前端三端连到同一个接口地址上。这里最容易出现的情况是 APP 端调通了、小程序真机又 fail或者 PC 管理端跨域报错。联调的核心是「接口地址统一 Token 统一 错误处理统一」下面按端逐个说。4.1 封装 request.jsBaseURL 指向局域网 IPToken 统一注入const BASE_URL http://192.168.1.108:8080/api; export function request(options) { return new Promise((resolve, reject) { const token uni.getStorageSync(token); uni.request({ url: BASE_URL options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json, Authorization: token ? Bearer token : }, success: (res) { if (res.data.code 0) { resolve(res.data.data); } else if (res.data.code 401) { uni.removeStorageSync(token); uni.reLaunch({ url: /pages/login/login }); } else { uni.showToast({ title: res.data.msg || 请求失败, icon: none }); } }, fail: (err) reject(err) }); }); }这段封装解决三件事BaseURL 统一收敛、Token 自动注入、401 统一跳登录。真机联调时 BASE_URL 不能用 localhost要填电脑的局域网 IP且手机和电脑必须在同一网段如果后端没开 CORSH5 端会跨域APP 端没有跨域概念但要确认 Android 的联网权限没被关。401 分支单独拎出来是重点——很多源码里登录态判断散落在每个页面接手后第一件事就是把它们统一收进 request 层否则后面加一个页面就漏一个鉴权上线后用户 token 过期会看到各种诡异的白屏。4.2 manifest.json 配置与安卓 iOS 打包注意{ name: 健康云医疗, app-plus: { distribute: { android: { minSdkVersion: 21, targetSdkVersion: 30, permissions: [ android.permission.CAMERA, android.permission.READ_EXTERNAL_STORAGE, android.permission.WRITE_EXTERNAL_STORAGE, android.permission.RECORD_AUDIO ] }, ios: { privacyDescription: { NSCameraUsageDescription: 用于拍摄病历照片, NSMicrophoneUsageDescription: 用于医患语音聊天, NSPhotoLibraryUsageDescription: 用于选择相册图片 } } } } }manifest.json 是 Uniapp 多端打包的关口配置。权限的填写原则是「用多少申请多少」问诊场景需要相机、相册、麦克风就够了不要把定位、后台运行、通讯录这类敏感权限全开安卓上架应用市场时权限声明和隐私政策必须对应多一个无关权限就会被审核打回。iOS 端的 privacyDescription 是硬性要求缺任意一项描述App Store 审核直接拒。打包方式上云打包省事但要传云端本地离线打包要装 Android Studio 或 Xcode常见的翻车现场是本地 SDK 版本和 Uniapp 运行环境不匹配编译到一半报 aapt2 error处理办法是严格按 HBuilderX 官方配套版本装 SDK不要装最新版。4.3 微信小程序打包本地联调与上线前的域名校验export default { onShareAppMessage() { return { title: 在线问诊三甲医生在线接诊, path: /pages/index/index }; } };Uniapp 跑微信小程序端的联调步骤是固定的HBuilderX 运行到小程序模拟器微信开发者工具里点「详情 → 本地设置 → 勾选不校验合法域名」真机预览时保持手机和电脑同一网络。小程序和 APP 有个本质区别——真机环境强制校验 request 合法域名和 HTTPS开发者工具里关掉校验只对开发期有效。上线前必须在微信公众平台把接口域名配成 HTTPS 备案域名如果后端只有 http小程序真机请求会全部 fail这不是改代码能解决的得在 Nginx 反代一层 HTTPS。onShareAppMessage里的 path 要带参数就拼 query但要避免在分享路径里塞 token分享出去被第三方截获就是账号泄露。4.4 PC 管理端联调开发期代理和上线部署两种方式module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } };PC 管理端开发期的联调一般用 devServer 代理把前端页面里的/api请求转发到后端绕开跨域。上线后有两种常见部署方式独立 Nginx 托管或把 Vue 打包的 dist 静态文件放进 SpringBoot 的 resources/static 目录。如果选后者有一个历史路由的坑必须处理Vue Router 用 history 模式时用户刷新/doctor/list页面会 404因为后端没有这个路由最省事的方案是改用 hash 路由URL 带个#但功能不受影响一定要用 history 模式后端就得写一个 fallback Controller 把未匹配的路径转发到 index.html。这也是很多人问「vue 打包放进 springboot 中」时的标准答案。5. 跑这套源码最容易翻车的 5 个现场现象、原因与处理办法源码能不能快速跑起来拼的不是代码能力而是排查配置问题的经验。下面五个现场我基本每次都会遇到按「现象 → 原因 → 解决」写清楚。5.1 数据库连不上Access denied 与 Public Key Retrieval现象后端启动直接报Access denied for user rootlocalhost或者Public Key Retrieval is not allowed有时候还混着Communications link failure。原因基本是三个MySQL 8.0 默认的 caching_sha2_password 密码插件和旧驱动不兼容JDBC URL 缺少参数账号的 host 权限没放开。解决方法是把驱动换成 8.x 的com.mysql.cj.jdbc.DriverURL 里补上allowPublicKeyRetrievaltrueuseSSLfalse同时创建一个带远程访问权限的专用账号CREATE USER health% IDENTIFIED BY Health2024; GRANT ALL PRIVILEGES ON health_cloud.* TO health%; FLUSH PRIVILEGES;这套操作做完99% 的连接问题都能解决。剩下 1% 是密码里带了特殊字符没转义比如在某些连接池配置里会被截断建议密码只用字母数字加下划线。5.2 图片上传成功但访问 404静态资源映射是一对现象医生头像、病历图片上传接口返回了文件路径但浏览器打开路径直接 404。原因文件确实写到了磁盘但 SpringBoot 根本没有把/files/**这个 URL 前缀映射到磁盘目录所以请求打进来找不到文件。解决方法是写一个 WebMvcConfigurer 配置类Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/files/**) .addResourceLocations(file: uploadPath /); }注意uploadPath末尾一定要带斜杠且file:前缀不能丢。这里最隐蔽的坑是uploadPath写成相对路径比如./upload/用 IDE 启动没问题打成 jar 包部署后工作目录变了文件就写到别处去了。改成绝对路径或者在启动脚本里显式指定工作目录。5.3 小程序真机请求失败域名白名单、HTTPS 与证书链现象微信开发者工具里一切正常一用手机预览所有请求全部 fail或者控制台明确提示「不在以下 request 合法域名列表中」。原因就是小程序真机强制校验域名白名单和 HTTPS开发工具里勾选了「不校验合法域名」只对工具生效。解决方法是上线前把接口域名在微信公众平台配到 request 合法域名并且必须 HTTPS。这里有个容易被忽略的细节证书链不完整也会导致请求失败有些证书商只给了域名证书没给中间证书App 和浏览器都能打开小程序却报「未能完成请求」。验证证书链用openssl s_client -connect yourdomain:443 -showcerts看输出缺中间证书就补上别在图省事上栽跟头。5.4 Token 时灵时不灵拦截器排除路径没配全现象登录接口自己返回 401或者某些接口带 token 也 401换个接口又正常。原因十有八九是鉴权拦截器的excludePathPatterns配漏了。登录、注册、验证码、静态资源这些路径全部要排除漏了登录接口就会让整个系统变成「无法登录」。另一个常见问题是客户端 header 字段名和后端校验不一致后端读Authorization前端传了token自然 401。解决思路是先在后端拦截器里打印实际请求路径逐个对照排除列表同时统一约定 header 格式为Authorization: Bearer token客户端和后端都按这个标准改。还有一个隐蔽点拦截器把/files/**这种静态资源也拦了导致图片带上 token 才能看这在医疗场景里很麻烦记得排除。5.5 SpringBoot 版本太高或太低依赖冲突的降级处理现象mvn package报 spring-boot-maven-plugin 相关错误或者启动时 NoSuchMethodError、javax 包找不到。原因通常是本地环境 JDK 太新或者 IDE 自动把依赖版本解析到了最新版。源码基于 SpringBoot 2.x 时JDK 17 直接跑会踩 module 隔离问题SpringBoot 3.x 又把包名从 javax 整个换成了 jakarta这段迁移不是改一两个 import 能搞定的。处理办法是让工程版本对齐源码的 pom.xml parent 声明JDK 切到 8 或 11。如果你非要用高版本先把工程跑通再谈升级否则你会同时面对数据库驱动、Redis 客户端、MyBatis 插件三套兼容问题。老版本能稳定扛住 100 个并发比改不完的高版本值钱得多。6. 二次开发的方向把私人医生服务做成能续费的产品6.1 订阅到期提醒从一张状态表到定时任务私人医生定制服务的核心是「能让用户持续付费」。我一般会在 member_subscription 表加一个到期日然后写一个定时任务每天扫订阅状态提前三天给用户推送续费提醒Scheduled(cron 0 0 8 * * ?) public void remindExpiringSubscriptions() { // 查 expire_date 在 3 天内且 statusactive 的订阅 // 生成待办消息并调用 APP 推送 }cron 表达式表示每天早上 8 点执行。生产环境如果有多实例部署同一个任务会被每个实例各跑一遍造成重复推送需要引入分布式锁或者直接把任务迁到 XXL-Job 这类调度平台上管理。6.2 在线问诊的会话WebSocket 与 HTTP 轮询的取舍这套源码里问诊会话的实现一般不会太复杂。并发量不大时HTTP 轮询 3 秒一次足够用成本最低后端只需要一个消息列表接口。如果要做成能对外的产品建议升级到 WebSocketSpring 自带 WebSocketHandler改造范围能控制在会话模块内部。无论哪种方案消息都必须落库到 chat_message 表未读数用消息表的聚合 count 计算不要在业务表里单独维护一个「未读数」字段那东西同步起来非常痛苦。6.3 上线前验证并发、回滚与越权三件事这套系统在见客户之前我至少要跑三关验证。第一关是并发用 JMeter 模拟 100 个用户同时创建问诊订单观察订单号是否重复、状态是否错乱第二关是事务回滚故意让支付回调失败确认订单状态不会卡死在中间态第三关是越权访问换个用户 token 尝试拉取他人病历接口后端必须做归属校验否则聊天和处方数据就是裸奔。三关都过系统才谈得上稳定交付。我第一次跑通这套工程时卡得最久的不是业务代码而是第 5 章里那几种配置问题。后来养成的习惯是拿到源码第一步先把数据库脚本和 yml 配干净再去看业务代码所有中间件版本一律以源码 pom 为准不随手升级。这套流程帮我省掉了大半的玄学问题也希望能帮到你。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑