SpringBoot-springboot项目接收解析HL7 V2.3.1协议报文
整理不易,如果您觉得对您有所帮助 请点赞支持下~谢谢
背景
本协议基于 HL7 v2.3.1 来定义
接收消息类型为:ORU^R01(样本结果)
每收到一条样本结果,需要回应一条样本应答消息(ACK)
7Edit工具模拟HL7协议请求
工具安装包地址:
通过百度网盘分享的文件:7Edit
链接:https://pan.baidu.com/s/12P-8RdsMyYBAaR7R6r8jGg
提取码:sky1
File - new - 选择自己的协议类型(此处我用的是ORU^R01)和版本(此处我用的是 2.3.1)
报文例子:
MSH|^~\&|BC-5300|Mindray|||20081120171602||ORU^R01|1|Q|2.3.1||||||UNICODE
PID|1|7393670^^^^MR|患者ID唯一标识^刘佳|19950804000000|患者姓名|||F
PV1||I|LAB^LABORATORY^|||SUR^SURGEON^DR^^^^^|||||||
OBR|1|234567890|151515^LAB TEST PANEL^L|1|202301011100||||||||N|||F|||||202301011200
OBX|1|ST|151515^GLUCOSE^L|1|102|mg/dL|70_105|N|||F
OBX|2|NM|151516^CHOLESTEROL^L|1|185|mg/dL|<200|N|||F
OBX|3|ST|151517^HEMOGLOBIN^L|1|14.5|g/dL|12.0_16.0|N|||F
OBX|4|NM|151518^WHITE BLOOD CELL COUNT^L|1|7.2|K/uL|4.0_11.0|N|||F
代码
pom文件引入Hapi依赖
<!-- HL7协议-全自动血液细胞分析仪-->
<dependency>
<groupId>ca.uhn.hapi</groupId>
<artifactId>hapi-base</artifactId>
<version>2.3</version> <!-- 请根据实际情况选择最新版本 -->
</dependency>
<dependency>
<groupId>ca.uhn.hapi</groupId>
<artifactId>hapi-structures-v231</artifactId>
<version>2.3</version> <!-- 请根据实际情况选择最新版本 -->
</dependency>
创建Component组件 配置ourHl7Server服务信息
package io.hk.modules.ws.config;
import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.app.HL7Service;
import ca.uhn.hl7v2.llp.MinLowerLayerProtocol;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* <p>@desc OURHl7Server服务
* 用于全自动血液细胞分析仪数据采集
* 监听HL7协议发送请求
* <p>@author
* <p>@date
**/
@Component
public class BasicListenerWithoutMessageHandling {
@Autowired
private MyReceivingApplication myReceivingApplication;
private static int PORT_NUMBER = 1919;
private static HapiContext context = new DefaultHapiContext();
@PostConstruct
public void newHL7Service() throws Exception {
try {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, 3100,
30, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(100));
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
MinLowerLayerProtocol mllp = new MinLowerLayerProtocol();
mllp.setCharset("UTF-8");
context.setLowerLayerProtocol(mllp);
context.setExecutorService(executor);
// 是否使用TLS/SSL
boolean useSecureConnection = false;
HL7Service ourHl7Server = context.newServer(PORT_NUMBER, useSecureConnection);
ourHl7Server.registerApplication(myReceivingApplication);
ourHl7Server.startAndWait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
Hapi注册单元(获取报文和解析保存)
其中重写processMessage 方法用于HL协议报文解析
package io.hk.modules.ws.config;
import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.*;
import ca.uhn.hl7v2.parser.PipeParser;
import ca.uhn.hl7v2.protocol.ReceivingApplication;
import ca.uhn.hl7v2.protocol.ReceivingApplicationException;
import ca.uhn.hl7v2.util.Terser;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.hk.common.DateUtil;
import io.hk.common.StringUtil;
import io.hk.common.utils.LogUtil;
import io.hk.common.utils.R;
import io.hk.common.utils.UuidUtil;
import io.hk.modules.ws.entity.IfInspResultDetailEntity;
import io.hk.modules.ws.entity.IfInspResultEntity;
import io.hk.modules.ws.entity.IfHealthInspDataEntity;
import io.hk.modules.ws.service.IfHealthInspDataService;
import io.hk.modules.ws.service.IfInspResultDetailService;
import io.hk.modules.ws.service.IfInspResultService;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.util.ThreadContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.*;
/**
* <p>@desc Hapi注册单元
* <p>@author
* <p>@date
**/
@Component
public class MyReceivingApplication implements ReceivingApplication {
@Autowired
IfInspResultDetailService ifInspResultDetailService;
@Autowired
IfInspResultService ifInspResultService;
@Autowired
private SecurityManager securityManager;
@Autowired
private IfHealthInspDataService ifHealthInspDataService;
/**
* <p>@desc 处理全自动血液细胞分析仪发来的报文数据
* <p>@author gaoyt
* <p>@date 2024/11/22 15:27
*
* @param theMessage
* @param theMetadata
**/
@Override
@Transactional
public Message processMessage(Message theMessage, Map theMetadata) throws ReceivingApplicationException, HL7Exception {
String username = "processMessage";
LogUtil.writelog("====================全自动血液细胞分析仪-获取HL7报文-开始=============================", username);
// ACK应答
Message response = null;
ThreadContext.bind(securityManager);
try {
// 解析保存HL7报文数据
R result = analysisModule(theMessage, theMetadata);
if ("0".equals(result.get("code").toString())) {
// AA 接收
response = theMessage.generateACK();
} else if ("101".equals(result.get("code").toString())) {
// AE 丢失必填字段
response = theMessage.generateACK("AE", new HL7Exception("101"));
} else {
// AE 错误
response = theMessage.generateACK("AE", new HL7Exception("207"));
}
} catch (Exception e) {
// AE 错误
try {
response = theMessage.generateACK("AE", new HL7Exception("207"));
} catch (Exception ex) {
LogUtil.writeExceptionLog(ex, username);
}
LogUtil.writeExceptionLog(e, username);
} finally {
ThreadContext.unbindSecurityManager();
LogUtil.writelog("====================全自动血液细胞分析仪-获取HL7报文-结束=============================", username);
}
return response;
}
public R analysisModule(Message hapiMsg, Map hapiMetadata) {
R result = R.ok();
String username = "analysisModule";
LogUtil.writelog("====================全自动血液细胞分析仪-解析HL7报文-开始=============================", username);
try {
// 获取体检结果
R ifInspR = getifInspResultEntity(hapiMsg);
if ("0".equals(ifInspR.get("code").toString())) {
IfInspResultEntity ifInspResult = (IfInspResultEntity) ifInspR.get("ifInspResult");
// 体检结果ID
String ifInspResultId = UuidUtil.get32UUID();
ifInspResult.setSysid(ifInspResultId);
// 获取体检结果明细
R ifInspResultDetailR = getifInspResultDetail(hapiMetadata, ifInspResult);
List<IfInspResultDetailEntity> ifInspResultDetailList = (List<IfInspResultDetailEntity>) ifInspResultDetailR.get("ifInspResultDetailList");
if ("0".equals(ifInspResultDetailR.get("code").toString())) {
// 保存到数据库
R saveResult = saveHapi(ifInspResult, ifInspResultDetailList);
if (!"0".equals(saveResult.get("code").toString())) {
result.put("code", 1);
result.put("msg", "保存体检结果失败");
return result;
}
} else if ("101".equals(ifInspResultDetailR.get("code").toString())) {
result.put("code", 101);
result.put("msg", "体检结果明细丢失必须的字段");
return result;
} else {
result.put("code", 1);
result.put("msg", "获取体检结果明细失败");
return result;
}
} else if ("101".equals(ifInspR.get("code").toString())) {
// 必填项校验不通过
result.put("code", 101);
result.put("msg", "体检结果丢失必须的字段");
return result;
} else {
result.put("code", 1);
result.put("msg", "获取体检结果失败");
return result;
}
} catch (Exception e) {
result.put("code", 1);
result.put("msg", "异常:" + e.getMessage());
LogUtil.writeExceptionLog(e, username);
} finally {
LogUtil.writelog("====================全自动血液细胞分析仪-解析HL7报文-结束=============================", username);
}
return result;
}
private R saveHapi(IfInspResultEntity ifInspResult, List<IfInspResultDetailEntity> ifInspResultDetailList) {
R result = R.ok();
String username = "saveHapi";
LogUtil.writelog("====================全自动血液细胞分析仪-保存HL7报文-开始=============================", username);
try {
ifInspResultService.save(ifInspResult);
ifInspResultDetailService.saveBatch(ifInspResultDetailList);
} catch (Exception e) {
result.put("code", 1);
result.put("msg", "异常:" + e.getMessage());
LogUtil.writeExceptionLog(e, username);
} finally {
LogUtil.writelog("====================全自动血液细胞分析仪-保存HL7报文-结束=============================", username);
}
return result;
}
/**
* <p>@desc 获取体检结果
* <p>@author gaoyt
* <p>@date 2024/11/25 10:37
*
* @param hapiMsg
**/
private R getifInspResultEntity(Message hapiMsg) {
R result = R.ok();
String username = "getifInspResult";
LogUtil.writelog("====================全自动血液细胞分析仪-获取体检结果-开始=============================", username);
IfInspResultEntity ifInspResult = new IfInspResultEntity();
try {
// 患者段信息
Terser terser = new Terser(hapiMsg);
// 患者姓名
String patientName = terser.get("/.PID-5");
// 患者性别 'M':表示男性(Male) 'F':表示女性(Female)
String patientSex = terser.get("/.PID-8");
// 存入输入库 0表示男性 1表示女性
String sex = "M".equals(patientSex) ? "0" : "1";
// 患者生日
String patientBirth = terser.get("/.PID-7");
// 根据出生日期获取到年龄
int patientAge = DateUtil.getAgeByBirth(patientBirth);
// 观察日期 (察请求的日期和时间)
String patientCheckDate = terser.get("/.OBR-7");
Date checkDate = DateUtil.getDateTime(patientCheckDate);
// fileOrderNumber 预约编号
String inspNo = terser.get("/.OBR-3");
// 根据预约编号查询省份ID
IfHealthInspDataEntity ifHealthInspData = ifHealthInspDataService.getBaseMapper().selectOne(new QueryWrapper<IfHealthInspDataEntity>()
.eq("is_del", 0)
.eq("is_active", 0)
.eq("insp_no", inspNo));
// 校验必填项
boolean flag = StringUtil.validateStrings(inspNo, patientCheckDate);
if (!flag) {
// 存在必填项为空
result.put("code", 101);
result.put("msg", "丢失必须的字段");
return result;
}
// 体检姓名
ifInspResult.setInspName(patientName);
// 性别(0-男,1-女)
ifInspResult.setSex(sex);
// 年龄
ifInspResult.setAge(patientAge);
// 血常规:BRT
ifInspResult.setHisItemsGroupCode("BRT");
// 是否存在图像文件,N-否、Y-是
ifInspResult.setIsFile("N");
// 检查日期
ifInspResult.setCheckDate(checkDate);
// 预约编号
ifInspResult.setInspNo(inspNo);
if (ifHealthInspData != null) {
// 体检机构ID
String corpId = ifHealthInspData.getCorpId();
ifInspResult.setAppId(corpId);
}
} catch (Exception e) {
result.put("code", 1);
result.put("msg", "异常:" + e.getMessage());
LogUtil.writeExceptionLog(e, username);
} finally {
LogUtil.writelog("====================全自动血液细胞分析仪-解析HL7患者标识段-结束=============================", username);
}
result.put("ifInspResult", ifInspResult);
return result;
}
/**
* <p>@desc 获取体检结果明细
* <p>@author gaoyt
* <p>@date 2024/11/25 10:35
*
* @param hapiMetadata
**/
private R getifInspResultDetail(Map hapiMetadata, IfInspResultEntity ifInspResult) {
R result = R.ok();
String username = "getifInspResultDetail";
LogUtil.writelog("====================全自动血液细胞分析仪-获取体检结果明细-开始=============================", username);
List<IfInspResultDetailEntity> ifInspResultDetailList = new ArrayList<>();
try {
// 获取到报文字符串
String[] message = hapiMetadata.get("raw-message").toString().split("\r");
// 拼接报文中所有OB前的报文
String messageBeforeObx = "";
for (String s : message) {
if (!s.startsWith("OBX")) {
messageBeforeObx = messageBeforeObx + s + "\r";
}
}
for (String s : message) {
if (s.startsWith("OBX")) {
PipeParser parser = new PipeParser();
String messageTmp = messageBeforeObx + s;
Message parse = parser.parse(messageTmp);
Terser terserParse = new Terser(parse);
// 检查项目 Observation Identifie
String obxIdentifier = terserParse.get("/.OBX-3");
// Observation Value:观察结果的具体数值或描述 反映了医疗观察的结果
String obxValue = terserParse.get("/.OBX-5");
// 观察结果值的单位 例如,血糖值可能以毫摩尔每升(mmol/L)为单位,这有助于接收方正确理解观察结果。
String obxUnits = terserParse.get("/.OBX-6");
// References Range 观察结果的参考范围
String obxRange = terserParse.get("/.OBX-7");
// Abnormal Flags: 用于标识观察结果是否异常。 常见的标识包括正常、高、低、异常等。
// A:异常(Abnormal) N:正常(Normal) H:高于正常范围(Higher than normal) L:低于正常范围(Lower than normal) C:危急值(Critical)
String obxFlag = terserParse.get("/.OBX-8");
// 检查日期
Date obxCheckDate = ifInspResult.getCheckDate();
// 校验必填项
boolean flag = StringUtil.validateStrings(obxIdentifier, obxValue, obxUnits, obxRange, obxFlag);
if (!flag) {
// 存在必填项为空
result.put("code", 101);
result.put("msg", "丢失必须的字段");
return result;
}
IfInspResultDetailEntity ifInspResultDetail = new IfInspResultDetailEntity();
// 检查项目
ifInspResultDetail.setProjectCode(obxIdentifier);
// 检测值
ifInspResultDetail.setResultValue(obxValue);
// 单位
ifInspResultDetail.setMeasure(obxUnits);
// 范围
ifInspResultDetail.setRanges(obxRange);
// 结果表示
ifInspResultDetail.setResultFlag(obxFlag);
// 检查日期
ifInspResultDetail.setCheckDate(obxCheckDate);
// 体检结果ID
ifInspResultDetail.setHisInspResultId(ifInspResult.getSysid());
ifInspResultDetailList.add(ifInspResultDetail);
}
}
} catch (Exception e) {
result.put("code", 1);
result.put("msg", "异常:" + e.getMessage());
LogUtil.writeExceptionLog(e, username);
} finally {
LogUtil.writelog("====================全自动血液细胞分析仪-解析HL7观察结果段-结束=============================", username);
}
result.put("ifInspResultDetailList", ifInspResultDetailList);
return result;
}
@Override
public boolean canProcess(Message message) {
return true;
}
}
本文来自博客园,作者:skystrivegao,转载请注明原文链接:https://www.cnblogs.com/skystrive/p/18576357
整理不易,如果对您有所帮助 请点赞收藏,谢谢~