SpringBoot+Vue3+MySQL8实战:手把手教你从零搭建一个门诊HIS系统(附完整源码)
·
SpringBoot+Vue3+MySQL8实战:从零构建门诊HIS系统的技术精要
1. 项目架构设计与技术选型
在医疗信息化领域,门诊HIS系统作为核心业务支撑平台,其技术架构的合理性直接关系到系统的稳定性与扩展性。我们选择SpringBoot+Vue3+MySQL8这一主流技术栈,不仅因为其成熟的社区生态,更看重其在医疗场景下的特殊适配能力。
技术栈深度解析 :
- SpringBoot 2.7 :采用约定优于配置的理念,快速搭建RESTful API服务。特别配置了
spring-boot-starter-actuator用于健康监控,这对7×24小时运行的医疗系统至关重要 - Vue3 + Composition API :相比Options API,Composition API更适合处理复杂的医患交互状态逻辑。通过
provide/inject实现跨层级组件通信,完美支持病历表单的多级嵌套 - MySQL8.0 :利用窗口函数简化科室工作量统计,JSON字段类型存储动态扩展的检查报告模板
- MyBatis-Plus 3.5 :其Lambda表达式查询构建器让多表关联查询更直观,例如:
// 查询某医生当天的接诊患者
lambdaQuery()
.eq(PatientVisit::getDoctorId, doctorId)
.between(PatientVisit::getVisitTime,
LocalDateTime.now().withHour(0),
LocalDateTime.now().withHour(23))
.list();
开发环境推荐配置 :
| 工具类型 | 推荐方案 | 医疗场景优化点 |
|---|---|---|
| IDE | IntelliJ IDEA + Vue插件 | 内置HTTP Client调试医疗API |
| 数据库工具 | DBeaver | 可视化ER图维护复杂表关系 |
| API测试 | Postman + Newman | 自动化测试挂号业务流程 |
| 前端调试 | Vue DevTools | 追踪处方表单状态变化 |
关键提示:医疗系统开发必须考虑《电子病历系统功能应用水平分级评价标准》,在数据字段设计阶段就要预留评级需要的审计字段。
2. 核心业务模块实现
2.1 患者挂号子系统
挂号作为医疗流程的入口,其并发处理能力直接影响患者体验。我们采用Redis分布式锁解决号源争抢问题:
public boolean lockRegistration(Integer scheduleId) {
String lockKey = "reg_lock:" + scheduleId;
return redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
}
挂号业务状态机设计 :
stateDiagram-v2
[*] --> 待支付
待支付 --> 已取消: 超时未支付
待支付 --> 已支付: 完成缴费
已支付 --> 已就诊: 医生接诊
已支付 --> 已退号: 患者退号
已就诊 --> [*]
2.2 电子处方模块
处方业务涉及复杂的药品配伍规则,我们采用规则引擎Drools实现药品禁忌检查:
rule "抗生素与益生菌冲突"
when
$p : Prescription()
$a : Medicine(name == "抗生素") from $p.getMedicines()
$b : Medicine(name == "益生菌") from $p.getMedicines()
then
throw new DrugConflictException("抗生素会杀死益生菌");
end
处方关联表设计 :
CREATE TABLE `prescription_detail` (
`id` bigint NOT NULL AUTO_INCREMENT,
`prescription_id` bigint NOT NULL COMMENT '主处方ID',
`medicine_id` bigint NOT NULL COMMENT '药品ID',
`dosage` decimal(10,2) NOT NULL COMMENT '单次剂量',
`frequency` varchar(20) NOT NULL COMMENT '用药频次',
`usage` varchar(50) NOT NULL COMMENT '用药途径',
`days` int NOT NULL COMMENT '用药天数',
PRIMARY KEY (`id`),
KEY `idx_prescription` (`prescription_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3. 医疗特色功能实现
3.1 检查报告结构化存储
利用MySQL8的JSON字段存储动态结构的检查结果:
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONObject examResult; // 存储如{ "血压": "120/80", "心率": 72 }
影像检查特殊处理 :
- DICOM文件存储MinIO对象存储
- 建立文件索引表关联患者信息
- 前端使用Cornerstone.js实现DICOM阅片
3.2 医学术语标准化
对接医疗术语标准服务实现诊断编码自动转换:
# 对接ICD-10服务示例
def convert_diagnosis(text):
url = "https://icd-api.com/translate"
params = {"q": text, "apiKey": "YOUR_KEY"}
response = requests.get(url, params=params)
return response.json().get("code")
4. 医疗安全与合规
4.1 双因素认证设计
医护人员登录采用短信验证码+密码的双因素认证:
<script setup>
const sendVerifyCode = async () => {
if (countdown.value > 0) return;
await api.sendSms(phone.value);
countdown.value = 60;
timer = setInterval(() => {
countdown.value--;
if (countdown.value <= 0) clearInterval(timer);
}, 1000);
};
</script>
4.2 审计日志实现
基于Spring AOP记录关键操作日志:
@AfterReturning(pointcut = "@annotation(auditLog)", returning = "result")
public void afterReturning(JoinPoint joinPoint, AuditLog auditLog, Object result) {
String operation = auditLog.value();
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
String ip = request.getRemoteAddr();
LogEntry log = new LogEntry();
log.setOperation(operation);
log.setIp(ip);
log.setParams(JsonUtils.toJson(joinPoint.getArgs()));
logService.save(log);
}
日志审计关键字段 :
| 字段名 | 类型 | 说明 |
|---|---|---|
| operator_id | varchar(32) | 操作人工号 |
| operation | varchar(100) | 操作类型(如"开立处方") |
| patient_id | varchar(32) | 涉及患者ID |
| operate_time | datetime | 操作时间(精确到毫秒) |
| before_state | text | 操作前数据状态 |
| after_state | text | 操作后数据状态 |
5. 性能优化实践
5.1 挂号排队算法优化
采用最小堆算法实现智能分诊:
public class RegistrationQueue {
private PriorityQueue<Patient> queue =
new PriorityQueue<>(Comparator.comparingInt(Patient::getPriority));
public void addPatient(Patient patient) {
// 急诊患者优先级+100,老年患者+20
int priority = patient.isEmergency() ? 100 : 0;
priority += patient.getAge() > 60 ? 20 : 0;
patient.setPriority(priority);
queue.add(patient);
}
}
5.2 药品库存缓存策略
使用多级缓存减少数据库压力:
- 本地Caffeine缓存:存储高频访问的药品基础信息
- Redis集群:维护实时库存数量
- 数据库:作为最终数据持久层
@Cacheable(value = "medicine", key = "#id")
public Medicine getMedicine(Long id) {
return baseMapper.selectById(id);
}
@CachePut(value = "medicine", key = "#medicine.id")
public Medicine updateMedicine(Medicine medicine) {
updateById(medicine);
return medicine;
}
6. 部署与监控
6.1 Docker-Compose部署方案
version: '3'
services:
his-api:
image: his-backend:1.0
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
depends_on:
- redis
- mysql
his-frontend:
image: his-frontend:1.0
ports:
- "80:80"
mysql:
image: mysql:8.0
volumes:
- ./mysql/data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=yourpassword
redis:
image: redis:6
ports:
- "6379:6379"
6.2 Prometheus监控配置
采集医疗关键指标:
- job_name: 'his_app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['his-api:8080']
labels:
service: '门诊系统'
核心监控指标 :
app_registration_count_total:挂号业务量app_prescription_duration_seconds:开处方耗时db_query_duration_seconds:数据库查询延迟system_cpu_usage:服务器CPU负载
在真实三甲医院部署时,这套监控体系成功预警了挂号高峰期的线程池耗尽问题,我们通过动态扩容Kubernetes Pod实例平稳度过了就诊早高峰。
更多推荐
所有评论(0)