门诊到结算全链路贯通:基于 Spring Cloud + Vue 打造双架构解耦的开源数字化医院信息系统 (HIS)
在医院数字化与智慧医疗体系建设中,医院信息系统(Hospital Information System,简称 HIS)是所有临床与管理业务运转的中枢骨干。然而长期以来,传统 HIS 领域往往被昂贵、封闭、代码老旧的商业软件所垄断,许多中小型医院、诊所及医疗信息化研发团队在系统升级和二次定制时面临重重阻碍:
- 业务流程高度耦合:挂号、就诊、电子处方、检验检查、药房发药、收费结算环环相扣,单一环节故障常引发全盘崩溃;
- 架构老旧演进艰难:遗留系统多采用重度存储过程或单体巨石架构,难以应对线上预约挂号激增的高并发潮汐;
- 学习改造成本高昂:商业系统缺乏开放源码与清晰文档,开源领域成熟且兼顾临床规范的系统凤毛麟角。
今天为大家深度拆解一套优秀的开源数字化医疗项目 —— HIS 医院信息管理系统。该系统不仅覆盖完整的门诊与住院核心业务链条,更极具前瞻性地同时提供了 单体式(HIS-master) 与 微服务分布式(his-cloud) 两套后端工程实现,配套现代化 Vue 前端(HIS-web) 与 移动端助手(HIS-app),为开发者和医院信息化团队提供了难得的高标准参考范例。
一、双架构解耦拆解:单体直连 vs 微服务拓扑
在系统架构设计上,许多项目往往陷入「非单体即微服务」的极端抉择。而该开源项目给出了极其务实的双架构演进方案:
1. 单体工程(HIS-master):采用经典 Spring Boot + MyBatis-Plus + MySQL 架构,模块间通过 Java 内部 Service 依赖进行调用。极度精炼、资源消耗低,非常适合教学研习、单机敏捷二次开发以及日就诊量较小的基层卫生院、社区门诊。
2. 微服务集群(his-cloud):基于 Spring Cloud 体系打造,拆分 API 网关、服务注册中心、配置中心,并将业务垂直划分为门诊服务、医生工作站服务、医技检验服务、药房进销存服务及财务结算服务。适合大中型医疗机构高可用集群部署与团队分工协作。


架构演进与拓扑矩阵
| 架构维度 | 单体架构(HIS-master) | 微服务架构(his-cloud) |
|---|---|---|
| 适用场景 | 社区诊所、民营门诊、敏捷二次开发 | 二级及以上医院、多院区协同、高并发排队 |
| 服务治理 | 单进程 Spring Context 内部调度 | Spring Cloud Netflix / Alibaba 服务注册与发现 |
| 网关调度 | Nginx 反向代理直达后端单实例 | Spring Cloud Gateway 动态鉴权与路由分发 |
| 数据库组织 | 统一共享单库(按业务表名分区隔离) | 垂直业务分库 + Redis 临床高频排班缓存 |
| 调用协议 | Java 本地内存直接引用(In-JVM) | RESTful / OpenFeign 声明式 RPC + 降级容错 |
二、门诊就诊全链路业务状态机与服务调用闭环
医疗信息系统区别于常规电商系统的一大特征在于:业务节点具备极强的法定执业严谨度与不可逆状态约束。一个标准的门诊患者就诊流程必须严格贯穿五个生命周期阶段:


1. 挂号分诊(Registration):采集患者基本信息与医保卡号,分配挂号单流水号(reg_id),根据医生排班表(Schedule)推入诊室候诊队列;
2. 医生接诊与病历处方(Doctor Station):接诊后医生录入主诉、现病史,结合 ICD-10 疾病编码开立诊断;开立药品处方(Prescription)和医技检查处置单(Disposal);
3. 医技处置(Medical Technology):放射科、生化检验科接收检验指令,采样检验后将电子报告结构化写回电子病历系统(EMR);
4. 收费结算(Cashier & Billing):收费系统聚合患者当前名下待缴费账单,支持医保统筹基金支付与自费部分混合结算,发票与电子凭证对账归档;
5. 药房核发(Pharmacy):发药窗口调用核验流水,药师双签字确认无配伍禁忌后确认出库,药品库存计数原子扣减。
三、核心技术实践:OpenFeign 声明式调用与熔断容错
在 his-cloud 微服务架构中,医生工作站(Doctor Service)在开立处方时,需要向药房库存服务(Pharmacy Service)校验药品实时库存与价格,避免因缺药导致无效处方。
系统采用 OpenFeign 进行声明式跨服务调用,并绑定 Hystrix / Sentinel 实现医疗故障隔离保护:
package com.his.cloud.doctor.feign;
import com.his.cloud.common.api.CommonResult;
import com.his.cloud.doctor.dto.DrugStockCheckDTO;
import com.his.cloud.doctor.feign.fallback.PharmacyFeignFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
/**
* 跨服务调用药房中心接口客户端
*/
@FeignClient(
value = "his-pharmacy-service",
fallback = PharmacyFeignFallback.class
)
public interface PharmacyFeignClient {
/**
* 批量校验药品库存与锁定状态
* @param checkList 药品ID与待开具数量列表
* @return 校验结果及当前库存批次信息
*/
@PostMapping("/api/pharmacy/stock/check-batch")
CommonResult<Boolean> verifyAndLockDrugStock(@RequestBody List<DrugStockCheckDTO> checkList);
}
降级熔断实现类保障了在药房网络波动时,前端能够友好提示并支持医生保存处方草稿,而不至于发生接口线程池耗尽导致的雪崩:
package com.his.cloud.doctor.feign.fallback;
import com.his.cloud.common.api.CommonResult;
import com.his.cloud.doctor.dto.DrugStockCheckDTO;
import com.his.cloud.doctor.feign.PharmacyFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.List;
@Slf4j
@Component
public class PharmacyFeignFallback implements PharmacyFeignClient {
@Override
public CommonResult<Boolean> verifyAndLockDrugStock(List<DrugStockCheckDTO> checkList) {
log.error("药房服务调用超时或异常,触发医生站处方开立降级保护!入参数量: {}", checkList.size());
// 允许暂存为待审核草稿,提示前端暂时切换为异步核库
return CommonResult.failed("药房库存系统繁忙,处方已保存为草稿,系统将在网络恢复后自动复核!");
}
}
四、处方状态流转设计与业务闭环
处方状态是医疗业务流的核心标尺,系统内设计了严格的状态生命周期管理枚举:
package com.his.cloud.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public enum PrescriptionStatusEnum {
DRAFT(1, "草稿开立"),
SUBMITTED(2, "已提交待缴费"),
PAID(3, "已交费待发药"),
DISPENSED(4, "已发药核销"),
REFUNDED(5, "已退费作废"),
EXPIRED(6, "超时作废");
private final Integer code;
private final String description;
public static boolean canDispense(Integer statusCode) {
return PAID.getCode().equals(statusCode);
}
}
在药房端确认发药时,系统执行严格的状态机校验与悲观/乐观并发锁更新,确保发药业务幂等性:
@Transactional(rollbackFor = Exception.class)
public boolean dispensePrescription(Long prescriptionId, Long pharmacistId) {
Prescription prescription = prescriptionMapper.selectById(prescriptionId);
if (prescription == null) {
throw new BusinessException("处方记录不存在!");
}
// 状态防重校验:仅允许“已缴费待发药”状态流转
if (!PrescriptionStatusEnum.canDispense(prescription.getStatus())) {
throw new BusinessException("当前处方未完成结算或已核发,禁止重复发药!");
}
// 1. 扣减批次实体库存并写流水台账
drugInventoryService.deductStockByPrescription(prescription);
// 2. 状态机推进至 DISPENSED
prescription.setStatus(PrescriptionStatusEnum.DISPENSED.getCode());
prescription.setDispenseUserId(pharmacistId);
prescription.setDispenseTime(LocalDateTime.now());
int rows = prescriptionMapper.updateById(prescription);
if (rows <= 0) {
throw new OptimisticLockingFailureException("处方状态已被其他窗口并发修改,请刷新后重试!");
}
return true;
}
五、生产级落地踩坑与核心经验
在将该开源项目落地或在真实医疗网络部署时,建议重点关注以下四个架构关键点:
1. 内外网物理隔离与医保专网直连:公立医院通常将内网业务网与医保专网物理隔离。微服务网关层(Gateway)需部署在双网卡服务器上,严格通过白名单限制医保前置机的数据透传。
2. 就诊高并发排队与 Redis 令牌桶:早高峰挂号容易引发秒杀级流量。系统将医生排班配额放入 Redis 进行原子递减(DECR),扣减成功后方可进入数据库持久化,有效杜绝了挂号超卖。
3. 敏感病历(EMR)国密合规脱敏:患者姓名、身份证号、过敏史在非主诊医生调阅时,必须由前端或网关层拦截器实施动态脱敏过滤(如姓名只展示姓氏,身份证号屏蔽出生年月)。
4. 分布式事务强一致性:在 his-cloud 模式下,针对「收费结算 ↔ 处方核销 ↔ 库存扣减」的强关联场景,建议引入 Seata 的 AT 模式或可靠消息最终一致性方案,避免跨库数据不一致。
六、总结
这套开源 HIS 系统通过清晰的代码分层、严谨的医疗流程建模与灵活的「单体+微服务」双架构实现,不论是对想要深入学习 Spring Cloud 企业级落地架构的开发者,还是有中小型门诊系统自研诉求的技术团队,都具有极高的参考价值。
代码仓库已全面开源,感兴趣的朋友可以克隆代码深入研究本地环境搭建与二次定制!
💻 配套实训环境与动手练习
本文涉及的相关技术指令、开发环境与工具链已内置在边学边练在线实验室中,无需繁琐安装配置,随时在浏览器中实践体验: