基于JAVA HAPI包以树形结构实现可配置式 HL7 V2消息接收与解析

目录

一、前言

二、简单介绍HL7

三、7Edit 介绍

1、解析

2、发送

3、接收

四、服务搭建

五、消息解析

六、HAPI下HL7消息的结构

七、上代码

MyReceivingApplication

MessageTpyeList

MessageTypeAndTableList

TableNameAndFieldMap



一、前言

网络上有很多解析HL7 V2消息的文章,但是大部分都是按行拆分,按管道符拆分,之后根据业务,按照下标找到对应的业务数据,由于笔者负责公司里边的接口工作,所以查找到的解析工作,对我来讲,有以下几个弊端:

  1. 跟版本耦合,HL7-2.X有多个版本,不希望一个接口项目的代码,遇到另外一个项目版本不一的时候,需要再调整代码实现一遍
  2. 工作繁琐。需要逐个实现不同的接口类型。比如ADT_A01接口的代码,就不能接收 ORU_R01 的数据
  3. 需要开发者对消息结构有了解,需要知道哪些结构是List结构,从而有针对地循环那部分的代码

针对以上两点,本文介绍了以下几点内容:

  1. HL7 工具 7Edit 的使用:接收、发送、编辑 HL7文本。
  2. 使用 HAPI 搭建 HL7服务
  3. 针对以上问题,提出了自己的接口实现方案,着急的朋友可直接从第 六 部分开始看
  4. HAPI 中的数据结构模型介绍。

本文实现是基于 HAPI,了解更多,移步HAPI官网:HAPI – The Open Source HL7 API for Java

本文所涉及的代码实现,已经放在东南-bit/HL7Test

二、简单介绍HL7

HL7 是一种医疗领域不同应用之间电子传输的标准化协议。在医疗领域中比较常见。

V2版本示例数据如下:

MSH|^~\&|LIS||HTCIS||20201207101411||OUL^R21|U6680658|P|2.4|||AL|AL
PID||0001042069|0001042069||谢XXX|||M
PV1||O|^^^0305^肾内科门诊||||||001287||||||||||5407031|||||||||||||||||||||||||20201207093847
OBR|1|16032220|4237929723|F00000092055^电解质七项^Ordinary||20201207084203|||||||||2&血清|||肾内科门诊|0305|4861273||20201207101340||||||||||0179&肖晓蔚|0178&郭伟权
NTE|1
OBX|1|NM|12081^钾(K)||3.98|mmol/L|3.50-5.30||||F|||20201207093847
OBX|2|NM|12071^钠(Na)||143.00|mmol/L|137-147||||F|||20201207093847
OBX|3|NM|12063^氯(Cl)||104|mmol/L|99-110||||F|||20201207093847
OBX|4|NM|12062^钙(Ca)||2.50|mmol/L|2.11-2.52||||F|||20201207093847
OBX|5|NM|12057^磷(P)||0.87|mmol/L|0.85-1.51||||F|||20201207093847
OBX|6|NM|12054^镁(Mg)||0.76|mmol/L|0.75-1.02||||F|||20201207093847
OBX|7|NM|12053^总二氧化碳(CO2)||24.00|mmoll/L|21-31||||F|||20201207093847
OBR|2|16032217|4237929723|F00000110561^肝功八项(常规)^Ordinary||20201207084203|||||||||2&血清|||肾内科门诊|0305|4861273||20201207101340||||||||||0179&肖晓蔚|0178&郭伟权
NTE|2
OBX|1|NM|12047^丙氨酸氨基转移酶(ALT)||22.00|U/L|0-50||||F|||20201207093847
OBX|2|NM|12043^天门冬氨酸氨基转移酶(AST)||15.00|U/L|0-40||||F|||20201207093847
OBX|3|NM|12863^转氨酶比值(AST/ALT)||0.68||1.0-1.5|↓|||F|||20201207093847
OBX|4|NM|12357^总蛋白(TP)||77.4|g/L|65.0-85.0||||F|||20201207093847
OBX|5|NM|12124^白蛋白(Alb)||48.20|g/L|40.0-55.0||||F|||20201207093847
OBX|6|NM|10035^球蛋白(Glb)||29.20|g/L|20.0-40.0||||F|||20201207093847
OBX|7|NM|10036^白/球比值(A/G)||1.65||1.5-2.5||||F|||20201207093847
OBX|8|NM|12067^总胆红素(TBil)||8.70|μmol/L|0.0-<=26.0||||F|||20201207093847
OBX|9|NM|12069^直接胆红素(DBil)||3.60|μmol/L|0.0-<=8.0||||F|||20201207093847
OBX|10|NM|12482^间接胆红素(IBil)||5.10|μmol/L|0.0-<=18.0||||F|||20201207093847
OBX|11|NM|12050^总胆汁酸(TBA)||1.82|μmol/L|0-10.0||||F|||20201207093847
OBR|3|16032218|4237929723|F00000092060^空腹血糖测定^Ordinary||20201207084203|||||||||2&血清|||肾内科门诊|0305|4861273||20201207101340||||||||||0179&肖晓蔚|0178&郭伟权
NTE|3
OBX|1|NM|12219^葡萄糖(GLU)||5.13|mmol/L|4.11-5.89||||F|||20201207093847
OBR|4|16032216|4237929723|F00000092063^肾功六项^Ordinary||20201207084203|||||||||2&血清|||肾内科门诊|0305|4861273||20201207101340||||||||||0179&肖晓蔚|0178&郭伟权
NTE|4
OBX|1|NM|12016^尿素(Urea)||8.40|mmol/L|1.73-8.30|↑|||F|||20201207093847
OBX|2|NM|12018^肌酐(Cr)||123.00|μmol/L|59-111|↑|||F|||20201207093847
OBX|3|NM|12014^尿酸(UA)||438.90|μmol/L|202.3-416.5|↑|||F|||20201207093847
OBX|4|NM|12007^胱抑素C(CysC)||1.34|mg/L|0.40-1.10|↑|||F|||20201207093847
OBX|5|NM|12012^β2微球蛋白(β2-MG)||2.64|mg/L|0.67-2.33|↑|||F|||20201207093847
OBR|5|16032219|4237929723|F00000092064^血脂四项^Ordinary||20201207084203|||||||||2&血清|||肾内科门诊|0305|4861273||20201207101340||||||||||0179&肖晓蔚|0178&郭伟权
NTE|5
OBX|1|NM|12085^甘油三酯(TG)||0.85|mmol/L|<2.26||||F|||20201207093847
OBX|2|NM|12083^总胆固醇(CHOL)||4.55|mmol/L|2.16-5.20||||F|||20201207093847
OBX|3|NM|12088^高密度脂蛋白胆固醇(HDL)||1.68|mmol/L|>1.45||||F|||20201207093847
OBX|4|NM|12090^低密度脂蛋白胆固醇(LDL)||3.03|mmol/L|0.00-3.34||||F|||20201207093847
OBX|5|NM|13721^Non HDL CHOL||2.87|mmol/L|1.22-4.48||||F|||20201207093847
OBX|6|NM|13722^总胆固醇/高密度脂蛋白胆固醇比值(CHOL/HDL)||2.71||<3.59||||F|||20201207093847

上述是一个实际使用过程中,较为复杂的HL7消息,每一行是一个消息段,消息段内以管道符分隔,分割后的不同位置,有不同的业务含义。

现在需要搭建服务端,来接收上述消息,并返回消息回执。

在介绍解析流程前,介绍一下服务调试软件 7Edit。

三、7Edit 介绍

7Edit 软件用来接收、发送、解析HL7消息,三个关键点:接收发送解析。同时还可以帮助用户快速编辑HL7

1、解析

将示例中的消息,保存至一个纯文本文件,并将结尾后缀名改为 .hl7,   使用 7Edit软件打开,得到如下界面:

在右上方编辑界面,点击自己需要的字段,右键,选择showIn -> Structure,右侧的结构树,就能明确定位其在树种的位置。

可见标准的HL7消息,可以被解析成树形结构!

2、发送

点击Sender,没有的话,Windows->Show view->Sender即可出来。

依照上述次序点击按钮,

在方框2中即可编辑目标IP和端口PORT,其他配置可自行探索,点击OK->OK->Close,

点击绿色图标,即可发送HL7消息。

3、接收

切换到 Reciver,按照2中步骤,配置IP,和监听端口,点击绿色按钮,即可开始监听,接收HL7消息,不再赘述。

四、服务搭建

看到网上,很多使用Socker来搭建接收服务器的,其实DUCK不必,HAPI已经实现了HL7客户端和服务端的各项功能,查看HAPI的官方文档,即可找到各种样例,以下代码是我的服务一个实现过程

import ca.uhn.hl7v2.DefaultHapiContext;
import ca.uhn.hl7v2.HapiContext;
import ca.uhn.hl7v2.app.HL7Service;
import ca.uhn.hl7v2.app.ServerConfiguration;
import ca.uhn.hl7v2.llp.MinLowerLayerProtocol;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class BasicListenerWithoutMessageHandling {

	private static int PORT_NUMBER  = 8080;
	private static HapiContext context = new DefaultHapiContext();

	public static void main(String[] args) throws Exception {

		if(args.length > 0){
			PORT_NUMBER = Integer.parseInt(args[0]);
		}
		try {
			ThreadPoolExecutor executor = new ThreadPoolExecutor(
			10, 100,
			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);
			ServerConfiguration s = new ServerConfiguration();
			boolean useSecureConnection = false; // are you using TLS/SSL?
			HL7Service ourHl7Server = context.newServer(PORT_NUMBER, useSecureConnection);
			ourHl7Server.registerApplication(new MyReceivingApplication());
			ourHl7Server.startAndWait();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

其中第34行代码,需要注册一个 Application  这个application 中,即可实现对消息的处理。

这个处理器的源码在文章后面可以找到.

这时,启动运行  BasicListenerWithoutMessageHandling ,使用第二部分中的7Edit,对着服务推送数据,即可接受到正常的返回值,只是这时候未对消息做任何处理。

这里说下 processMessage 的两个参数,Message message, Map<String, Object> map。

使用调试工具,可以看到map中存放了如下的内容,

一个简单的服务,将 raw-message存放入数据库即可。

这样做的好处是,如果接收到的消息不规范,是可以返回相应的错误给到发送者的。读者可以自己改改试试。

怎么样,服务搭建是不是简单。

但是,搭建这样一个服务器,并不是我们的最终目的,这样的原始的消息,对我们的作用不大,我们最后要获得的,是蕴含在其中的一条条数据记录。

五、消息解析

常规的HL7消息处理,是逐行拆分,然后用管道符对每一行做分割,然后取固定位置的数据。这样做虽然简单省事,但是弊端也很明显,需要在对HL7规范很了解的情况下,并且需要十分清楚每一种类型的消息的消息结构,才能将其拆解成业务需要的样子。HL7消息有很多版本,这个版本可以这么硬解析,但是换一个别的版本,是不是代码都得改了。

查询到的很多HL7的文章,都是走的这个套路,这不是我这个专门做接口的程序员的风格,我们的目标是,灵活,可配置!

接上文第三部分,我们已经实现了原始信息入库的功能,使用调式模式,查看参数  message:

如果看了第二部分,这时候就有点眼熟了,没错,这条消息在 7Edit 是被这样解析的:

再详细一点:

看7Edit:

做这些对比,意思就很明显了,HAPI,已经完成了HL7的解析工作,并已经形成了一个树形结构, processMessage方法传进来的参数 message 中已经包含了这个结构。

由此我们便可以得出这样一个解析思路:

1、首先建立一张配置表,在里面放入对于我们的业务表,我们需要的字段信息在原消息的哪个位置可以取到

2、由根节点出发,采用深度优先遍历,每访问到一个叶子结点,我们就判断下这个结点是不是我们配置表需要的数据,如果是,就把这个结点入栈

3、每当配置字段值都已经取完了的时候,我们就把栈中的节点全部用于生成SQL,并将一部分节点适当出栈,继续递归。这样我们读取了的消息前部的患者基本信息就能被带入到业务数据里面。

4、当我们想把一条消息里面的数据,对应到我们的多张业务表的时候,就再遍历一下这个消息,执行上面同样的操作就可以了。

点击左侧,可看到右侧对应的内容。示例数据就存在5个较大的数据对象,每行OBX可对应一条记录,按照树形解析,就可很方便得到对应的记录数

具体的如何遍历,可以参考 message.printStructure() 方法。文章后部能看到代码

六、HAPI下HL7消息的结构

点开依赖包中一个HL7消息的实现

一个完整的HL7消息,对应一个Message对象,一个Message中包含多个 Structure对象,每个Structure 中,会有一个或多个Segment。

这些Structure,有些是由Group实现,

有些是由Segment实现

Segment又由 许多Type组成,其中Type也可由多个Type组成。

由此可见,HL7消息其实是被这样一层层严格定义的。由此形成一个庞大的树形结构。

基于此,我们可形成一个这样的解析思路:

1、建一张配置的表:

message_type是消息类型,table_name是对应的我们的业务表,table_field_name是业务字段名,hl7_field_name是HL7的中的字段名,取自  本文的  二、7Edit 介绍 > 1、解析  部分,showIn -> structure ,定位到左侧的时候显示的这个值

有些具体的逻辑还比较复杂,其生成如下的SQL:

INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('钾(K)','mmol/L','3.98','20201207093847','3.50-5.30','0001042069','O','null','4237929723','1','1','NM','12081');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('钠(Na)','mmol/L','143.00','20201207093847','137-147','0001042069','O','null','4237929723','1','2','NM','12071');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('氯(Cl)','mmol/L','104','20201207093847','99-110','0001042069','O','null','4237929723','1','3','NM','12063');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('钙(Ca)','mmol/L','2.50','20201207093847','2.11-2.52','0001042069','O','null','4237929723','1','4','NM','12062');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('磷(P)','mmol/L','0.87','20201207093847','0.85-1.51','0001042069','O','null','4237929723','1','5','NM','12057');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('镁(Mg)','mmol/L','0.76','20201207093847','0.75-1.02','0001042069','O','null','4237929723','1','6','NM','12054');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('总二氧化碳(CO2)','mmoll/L','24.00','20201207093847','21-31','0001042069','O','null','4237929723','1','7','NM','12053');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('丙氨酸氨基转移酶(ALT)','U/L','22.00','20201207093847','0-50','0001042069','O','null','4237929723','2','1','NM','12047');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('天门冬氨酸氨基转移酶(AST)','U/L','15.00','20201207093847','0-40','0001042069','O','null','4237929723','2','2','NM','12043');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('转氨酶比值(AST/ALT)','','0.68','20201207093847','1.0-1.5','0001042069','O','null','4237929723','2','3','NM','12863');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('总蛋白(TP)','g/L','77.4','20201207093847','65.0-85.0','0001042069','O','null','4237929723','2','4','NM','12357');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('白蛋白(Alb)','g/L','48.20','20201207093847','40.0-55.0','0001042069','O','null','4237929723','2','5','NM','12124');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('球蛋白(Glb)','g/L','29.20','20201207093847','20.0-40.0','0001042069','O','null','4237929723','2','6','NM','10035');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('白/球比值(A/G)','','1.65','20201207093847','1.5-2.5','0001042069','O','null','4237929723','2','7','NM','10036');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('总胆红素(TBil)','μmol/L','8.70','20201207093847','0.0-<=26.0','0001042069','O','null','4237929723','2','8','NM','12067');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('直接胆红素(DBil)','μmol/L','3.60','20201207093847','0.0-<=8.0','0001042069','O','null','4237929723','2','9','NM','12069');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('间接胆红素(IBil)','μmol/L','5.10','20201207093847','0.0-<=18.0','0001042069','O','null','4237929723','2','10','NM','12482');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('总胆汁酸(TBA)','μmol/L','1.82','20201207093847','0-10.0','0001042069','O','null','4237929723','2','11','NM','12050');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('葡萄糖(GLU)','mmol/L','5.13','20201207093847','4.11-5.89','0001042069','O','null','4237929723','3','1','NM','12219');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('尿素(Urea)','mmol/L','8.40','20201207093847','1.73-8.30','0001042069','O','null','4237929723','4','1','NM','12016');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('肌酐(Cr)','μmol/L','123.00','20201207093847','59-111','0001042069','O','null','4237929723','4','2','NM','12018');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('尿酸(UA)','μmol/L','438.90','20201207093847','202.3-416.5','0001042069','O','null','4237929723','4','3','NM','12014');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('胱抑素C(CysC)','mg/L','1.34','20201207093847','0.40-1.10','0001042069','O','null','4237929723','4','4','NM','12007');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('β2微球蛋白(β2-MG)','mg/L','2.64','20201207093847','0.67-2.33','0001042069','O','null','4237929723','4','5','NM','12012');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('甘油三酯(TG)','mmol/L','0.85','20201207093847','<2.26','0001042069','O','null','4237929723','5','1','NM','12085');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('总胆固醇(CHOL)','mmol/L','4.55','20201207093847','2.16-5.20','0001042069','O','null','4237929723','5','2','NM','12083');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('高密度脂蛋白胆固醇(HDL)','mmol/L','1.68','20201207093847','>1.45','0001042069','O','null','4237929723','5','3','NM','12088');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('低密度脂蛋白胆固醇(LDL)','mmol/L','3.03','20201207093847','0.00-3.34','0001042069','O','null','4237929723','5','4','NM','12090');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('Non HDL CHOL','mmol/L','2.87','20201207093847','1.22-4.48','0001042069','O','null','4237929723','5','5','NM','13721');
INSERT INTO `T4`(`F10`,`F12`,`F11`,`F14`,`F13`,`F1`,`F2`,`F3`,`F5`,`F6`,`F7`,`F8`,`F9`) VALUES ('总胆固醇/高密度脂蛋白胆固醇比值(CHOL/HDL)','','2.71','20201207093847','<3.59','0001042069','O','null','4237929723','5','6','NM','13722');

其行数 与OBX的行数相同!!!

而且值得注意的是,同一个消息类型,可以配置多张表!

七、上代码

服务器的代码上边已经贴过了

MyReceivingApplication

import ca.uhn.hl7v2.HL7Exception;
import ca.uhn.hl7v2.model.*;
import ca.uhn.hl7v2.protocol.ReceivingApplication;
import ca.uhn.hl7v2.protocol.ReceivingApplicationException;
import ca.uhn.hl7v2.util.Terser;

import java.io.IOException;
import java.util.*;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class myReceivingApplication implements ReceivingApplication {

    private  JdbcConnectionsPool pool = new JdbcConnectionsPool();
    public    MessageTpyeList messageTpyeList = new MessageTpyeList();

    public myReceivingApplication () throws SQLException {

        String sql = "SELECT * FROM `view_hl7_map` ";//SQL语句
        Connection conn = pool.getConnection();
        Statement st = conn.createStatement();
        ResultSet resultSet = null;
        resultSet = st.executeQuery(sql);
        List<String[]> list = new ArrayList<>();
        while(resultSet.next())
        {
            String messageType=resultSet.getString("message_type");
            String tableTame = resultSet.getString("table_name");
            String tableFieldName = resultSet.getString("table_field_name");
            String hl7FieldName = resultSet.getString("hl7_field_name");
            messageTpyeList.add(messageType,tableTame,tableFieldName,hl7FieldName);
        }
        release(conn,st,resultSet);
    }


    @Override
    public Message processMessage(Message message, Map<String, Object> map) throws ReceivingApplicationException, HL7Exception {
        message.printStructure();

        Terser terser = new Terser(message);

        String messageID= map.get("/MSH-10").toString();
        String messageType = message.getName();
        String SendIP = map.get("SENDING_IP").toString();
        String SendPort = map.get("SENDING_PORT").toString();
        String rawMessage = map.get("raw-message").toString();
        String rawMessageSql = "INSERT INTO `raw_hl7_message`(`messageType`, `messageID`, `SendIP`, `SendPort`,`rawMessage`)\n" +
                " VALUES ('"+messageType+"', '"+messageID+"', '"+SendIP+"', '"+SendPort+"','"+rawMessage+"');";
        for (MessageTypeAndTableList messageTypeAndTableList:messageTpyeList.list){
            if(messageType.equals(messageTypeAndTableList.messageTypeName)){
                for(TableNameAndFieldMap tableNameAndFieldMap:messageTypeAndTableList.list){
                    getResultList(message, tableNameAndFieldMap);
                }
            }
        }
        messageTpyeList.getSQLList();
        Message message1 = null;
        try {
            Connection conn = pool.getConnection();
            Statement st = conn.createStatement();
            st.execute(rawMessageSql);
            for (String string :messageTpyeList.sqlList){
                System.out.println(string);
//                st.execute(string);
            }
            message1 = message.generateACK();
            conn.close();
            st.close();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return message1;
    }

    @Override
    public boolean canProcess(Message message) {
        return true;
    }

    private void getResultList(Structure structurePara, TableNameAndFieldMap tableNameAndFieldMap) throws HL7Exception {


        if (!structurePara.isEmpty()) {
            if (Group.class.isAssignableFrom(structurePara.getClass())) {
                Group group = (Group) structurePara;
                for (String childrenStructName : group.getNames()) {
                    Structure[] structures = group.getAll(childrenStructName);
                    for (Structure structure : structures) {
                        if (!structure.isEmpty()) {
                            getResultList(structure, tableNameAndFieldMap);
                        }
                    }

                }
            } else if (!AbstractGroup.class.isAssignableFrom(structurePara.getClass())) {
                if (Segment.class.isAssignableFrom(structurePara.getClass())) {

                    Segment seg = (Segment) structurePara;
                    String segmentName = seg.getName();

                    if (tableNameAndFieldMap.inSegmentNameSet(segmentName)) {

                        List<String> segmentFieldLlist = tableNameAndFieldMap.segmentNameAndIndexMap.get(segmentName);
                        for (String segmentField : segmentFieldLlist) {
                            if (tableNameAndFieldMap.isInSegmentFieldStack(segmentField)) {
                                tableNameAndFieldMap.updateStackAandResult(segmentField);
                            }
                            int[] index = tableNameAndFieldMap.hl7_index_map.get(segmentField);
                            String hl7FieldValue = getHl7FieldValue(seg, index);
                            tableNameAndFieldMap.setSegmentFieldResult(segmentField, hl7FieldValue);
                        }
                        int l = seg.numFields();
                    }
                }
            }
        }

        if (Message.class.isAssignableFrom(structurePara.getClass())) {
            tableNameAndFieldMap.updateStackAandResult();
        }
    }

    private String getHl7FieldValue(Segment seg, int[] index) throws HL7Exception {

        String value = null;
        int[] subIndex = new int[index.length - 1];
        for (int i = 0; i < subIndex.length; i++) {
            subIndex[i] = index[i + 1];
        }
        Type[] type = seg.getField(index[0]);

        if(null == type || type.length <= 0 ){
            return "";
        }
        value = getTypeValue(type[0], subIndex);
        return value;
    }

    private String getTypeValue(Type type, int[] index) {

        String resultValue = null;
        if (type instanceof Primitive) {
            Primitive primitive = (Primitive) type;
            resultValue = primitive.getValue();
        } else if (type instanceof Composite) {

            Composite composite = (Composite) type;
            Type[] types = composite.getComponents();
            int[] subIndex = new int[index.length - 1];
            for (int i = 0; i < subIndex.length; i++) {
                subIndex[i] = index[i + 1];
            }
            resultValue = getTypeValue(types[index[0] - 1], subIndex);
        }else if(type instanceof Varies){
            Varies varies = (Varies)type;
            try {
                resultValue = varies.encode();
            } catch (HL7Exception e) {
                e.printStackTrace();
            }
        }
        return resultValue;
    }


    public static void release(Connection conn, Statement st, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if (st != null) {
            try {
                st.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        if (conn != null) {
            try {
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

MessageTpyeList

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class MessageTpyeList {
    public List<MessageTypeAndTableList> list;
    public List<String> sqlList = new ArrayList<>();

    public MessageTpyeList(){
        list = new ArrayList<>();
    }

    public void add(String messageType, String tableTame, String tableFieldName, String hl7FieldName) {
        int index = getMessageTpyeIndex(messageType);
        if(-1 != index){
            add(index,tableTame,tableFieldName,hl7FieldName);
        }else{
            MessageTypeAndTableList messageTypeAndTableList = new MessageTypeAndTableList(messageType,tableTame,tableFieldName,hl7FieldName);
            list.add(messageTypeAndTableList);
        }
    }

    private void add(int index, String tableTame, String tableFieldName, String hl7FieldName) {
        list.get(index).add(tableTame,tableFieldName,hl7FieldName);
    }

    private int getMessageTpyeIndex(String messageType){
        int index = -1;
        if(null == list){
            return index;
        }else{
            for(int i = 0;i < list.size();i++){
                if(list.get(i).messageTypeName.equals(messageType)){
                    index = i;
                    break;
                }
            }
        }
        return  index;

    }

    public void cleanResult() {
        for(MessageTypeAndTableList messageTypeAndTableList:list){
            messageTypeAndTableList.cleanResult();
        }
        sqlList = new ArrayList<>();
    }

    public void getSQLList() {
        for(MessageTypeAndTableList messageTypeAndTableList:list){
            sqlList.addAll(messageTypeAndTableList.getSqlList());
        }
    }
}

MessageTypeAndTableList

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;

public class MessageTypeAndTableList {
    public String messageTypeName;
    public List<TableNameAndFieldMap> list = new ArrayList<>();

    public MessageTypeAndTableList(String messageType, String tableTame, String tableFieldName, String hl7FieldName) {
        messageTypeName = messageType;
        add(tableTame,tableFieldName,hl7FieldName);
    }

    public void add(String tableTame, String tableFieldName, String hl7FieldName) {
        int index = getTableNameIndex(tableTame);
        if(-1 != index){
            list.get(index).add(tableFieldName,hl7FieldName);
        }else{
            TableNameAndFieldMap tableNameAndFieldMap = new TableNameAndFieldMap(tableTame,tableFieldName,hl7FieldName);
            list.add(tableNameAndFieldMap);
        }
    }

    public int getTableNameIndex(String messageType){
        int index = -1;
        if(null == list){
            return index;
        }else{
            for(int i = 0;i < list.size();i++){
                if(list.get(i).tableName.equals(messageType)){
                    index = i;
                    break;
                }
            }
        }
        return  index;

    }

    public void cleanResult() {
        for(TableNameAndFieldMap tableNameAndFieldMap:list){
            tableNameAndFieldMap.cleanResult();
        }
    }

    public List<String> getSqlList() {
        List<String> sqlList = new ArrayList<>();
        for(TableNameAndFieldMap tableNameAndFieldMap:list){
            sqlList.addAll(tableNameAndFieldMap.getSqlList());
        }
        return sqlList;
    }
}

TableNameAndFieldMap

import java.util.*;

public class TableNameAndFieldMap {
    // 表名字
    public String tableName = null;
    // 表中字段名与HL7字段名之间的映射关系
    public Map<String,String> table_hl7_fieldMap = new HashMap<>();
    // HL7字段名与拆解之后的索引之间的关系
    public Map<String,int[]> hl7_index_map = new HashMap<>();
    // 记录该表对应了HL7中的哪些 Segment 名字
    public Set<String> segmentNameSet = new HashSet<>(); //所有要找寻的Segment名称集合

    public Map<String,List> segmentNameAndIndexMap = new HashMap<>(); //Segment名称和Segment中的field中的位置

    public List<String> stacklList = new ArrayList<>();  //用作栈
    public Map<String,String> currentResultMap = new HashMap<>();

    public List<Map> resultMapLsit = new ArrayList<>();

    public TableNameAndFieldMap(String tableTame, String tableFieldName, String hl7FieldName) {
        tableName = tableTame;
        add(tableFieldName,  hl7FieldName);
    }

    public void add(String tableFieldName, String hl7FieldName) {
        table_hl7_fieldMap.put(tableFieldName,hl7FieldName);
        String[] strs = hl7FieldName.split("-");
        int[] intArray = new int[strs.length-1];
        for (int i = 0; i < strs.length; i++){
            if(i == 0){
                segmentNameSet.add(strs[0]);
                putToSegmentNameAndIndexMap(hl7FieldName);
//                segmentNameAndIndexMap.put(strs[0],tableFieldName);
            }else{
                intArray[i-1] = Integer.parseInt(strs[i]);
            }
        }
        hl7_index_map.put(hl7FieldName,intArray);
    }

    private void putToSegmentNameAndIndexMap(String hl7FieldName) {
        String hl7SegmentName = hl7FieldName.substring(0,3);
        List<String> list = new ArrayList<>();
        if(segmentNameAndIndexMap.containsKey(hl7SegmentName)){
            list.addAll(segmentNameAndIndexMap.get(hl7SegmentName));
        }else{

        }
        list.add(hl7FieldName);
        segmentNameAndIndexMap.put(hl7SegmentName,list);

    }

    public boolean inSegmentNameSet(String segmentName) {
        return segmentNameSet.contains(segmentName);
    }

    public boolean isInSegmentFieldStack(String segmentField) {
        return stacklList.contains(segmentField);
    }

    public void updateStackAandResult(String segmentField) {
        Map<String,String> newMap = new HashMap<>();
        newMap.putAll(currentResultMap);
        resultMapLsit.add(newMap);
        int indecx = stacklList.indexOf(segmentField);
        for(int i = stacklList.size(); i > indecx ;i--){
            currentResultMap.remove(stacklList.get(i-1));
            stacklList.remove(i-1);
        }
    }

    public void setSegmentFieldResult(String segmentField, String hl7FieldValue) {
        currentResultMap.put(segmentField,hl7FieldValue);
        stacklList.add(segmentField);
    }

    public void updateStackAandResult() {
        resultMapLsit.add(currentResultMap);
    }

    public void cleanResult() {
        resultMapLsit = new ArrayList<>();
        currentResultMap = new HashMap<>();
    }

    public List<String> getSqlList() {
        List<String> list = new ArrayList<>();

        if(null != resultMapLsit && resultMapLsit.size() > 0){
            for(Map<String,String> map:resultMapLsit){
                String tableFieldNames = "";
                String values = "";
                for (String tableFieldName:table_hl7_fieldMap.keySet()){
                    String hl7_field_name = table_hl7_fieldMap.get(tableFieldName);
                    tableFieldNames = tableFieldNames + ",`"+tableFieldName+"`";
                    values = values + ",'"+map.get(hl7_field_name)+"'";
                }
                tableFieldNames = "INSERT INTO `"+tableName+"`("+tableFieldNames.substring(1)+")";
                values = " VALUES ("+ values.substring(1)+");";
                list.add(tableFieldNames + values);
            }
        }
        return list;
    }
}

数据库连接及属性类的代码不再贴了。

HL7(Health Level Seven)是用于在医疗机构和健康信息系统之间交换和共享数据的国际标准。HL7数据是以文本格进行传输,在不同的系统之间进行解析和处理是很重要的。 使用Java解析HL7数据是相对简单和方便的。Java有许多开源库可用于处理和解析HL7消息。其中一种常用的库是HAPIHL7 Application Programming Interface)。 HAPI库提供了一些类和方法,可以轻松地读取和解析HL7消息。它支持各种版本的HL7标准,并提供了一些有用的功能,例如验证消息结构和字段及生成HL7消息。 使用HAPI解析HL7消息的一般步骤如下: 1. 导入HAPI库:首先,在Java项目中导入HAPI库。可以通过将相关JAR文件添加到类路径中来实现。 2. 创建消息对象:使用HAPI库中的类,例如HL7Parser,创建一个HL7消息对象。 3. 读取HL7消息:使用创建的消息对象,通过调用相应方法,从文件、字符串或网络等来源读取HL7消息。 4. 解析消息解析HL7消息的几种方是使用HAPI库提供的类和方法进行逐个字段或分段的访问。可以使用消息对象的方法,如getSegment()、getField()、getRepetition()等。 5. 处理消息数据:一旦成功解析HL7消息,可以对消息内容进行进一步处理,例如提取患者信息、诊断信息或执行特定操作。 6. 错误处理:在解析HL7消息时,应考虑错误处理。HAPI库提供了一些异常类,例如HL7Exception,可用于处理解析过程中出现的错误。 总之,使用Java解析HL7消息是可行的,并且HAPI库是一种常用的工具,可以简化解析过程。通过了解HL7消息的结构和了解HAPI库的使用,可以有效处理和利用HL7数据。
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值