目录

一、前言

二、简单介绍HL7

三、7Edit 介绍

1、解析

2、发送

3、接收

四、服务搭建

五、消息解析

六、HAPI下HL7消息的结构

七、源代码


一、前言

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

  1. 跟版本耦合,HL7-2.X有多个版本,不希望一个接口项目的代码,遇到另外一个项目版本不一的时候,需要再调整代码实现一遍
  2. 工作繁琐。需要逐个实现不同的接口类型。比如ADT_A01接口的代码,就不能接收 ORU_R01 的数据

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

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

本文实现是基于 HAPI,了解更多,移步HAPI官网:https://hapifhir.github.io/hapi-hl7v2/

二、简单介绍HL7

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

示例数据如下:

MSH|^~\&|LIS||HTCIS||20201207101411||OUL^R21|U6680658|P|2.4|||AL|AL
PID||0001042069|0001042069||谢继韬|||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的文章,都是走的这个套路,这不是我这个专门做接口的程序员的风格,我们的目标是,灵活,可配置!

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

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

再详细一点:

看7Edit:

做这些对比,意思就很明显了,HAPI,已经完成了HL7的解析工作,并已经形成了一个树形结构, processMessage方法传进来的参数 message 中已经包含了这个结构。所以目标就很简单了,遍历 message ,并取出相应节点的值。

由根节点到叶子节点的路径,便可以很方便的对应一条数据库记录,即使出现重复的结构,我们也无需担心。

点击左侧,可看到右侧对应的内容。示例数据就存在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);}@Overridepublic 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;}@Overridepublic 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;}
}

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

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

  1. Java后端递归构建树形结构

    记录:在Java后台利用递归思路进行构建树形结构数据,返回给前端,能以下拉菜单等形式进行展示. 简明:为了简化代码,引入Lombok的Jar包,可省略实体类set().get()方法. <dep ...

  2. java读取文件目录返回树形结构

    为实现读取文件目录下的文件信息,生成树形结构,以方便前端做一些展示 1.结构实体类 package cn.cnic.instdb.model.system;import lombok.Data; im ...

  3. java树结构遍历_树形结构,java_树遍历统计总数,树形结构,java - phpStudy

    树遍历统计总数 { platformId: 3, areaId: "", areaName: "ROOT", parentAreaId: "" ...

  4. java实现处理无限层级树形结构

    树形结构在实际业务中是很经常遇到的,比如说机构.菜单.部门等等业务就会经常遇到层级关系.一般层级处理,有两种方式 (1)将所有的数据返回给前端,由前端处理,组装成树形结构,别担心,前端有组件的,只要后 ...

  5. 使用树形结构保存实体

    阅读原文请访问我的博客BrightLoong's Blog 之前在项目需要实现一个功能--将xml文件映射成实体,然后对映射的实体进行逻辑处理,最后保存到数据库中:由于xml结构的数据是结构化的数据, ...

  6. CSS(基于Java开发的学习)

    CSS(基于Java基础学习) CSS学习结构 ​ 1. CSS简介 层叠样式表(Cascading Style Sheets),是一种用来为HTML文档添加样式的语言,CSS文件的扩展名一般为.cs ...

  7. [附源码]计算机毕业设计JAVA基于Java小区电信计费管理系统

    [附源码]计算机毕业设计JAVA基于Java小区电信计费管理系统 项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Ecli ...

  8. (附源码)计算机毕业设计SSM基于Java的校园交友平台

    (附源码)计算机毕业设计SSM基于Java的校园交友平台 项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe( ...

  9. (附源码)计算机毕业设计SSM基于java平台的心理测试系统

    (附源码)计算机毕业设计SSM基于java平台的心理测试系统 项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclisp ...

  10. (附源码)计算机毕业设计SSM基于Java的茶叶销售管理系统

    (附源码)计算机毕业设计SSM基于Java的茶叶销售管理系统 项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclisp ...

最新文章

  1. UML类图新手入门级介绍
  2. STL中的map、unordered_map、hash_map
  3. 某一列高度变化_高度近视,老了后会瞎吗?
  4. 全网最全程序员效率工具及小技巧
  5. 格莱泽检验matlab,计量经济学实验指导书
  6. 【深度学习】词的向量化表示
  7. MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践
  8. 前端学习(3257):js高级教程(1)准备
  9. mac bochs 调试linux,Mac OS X下编译安装带debugger的bochs
  10. excel自定义函数添加和使用方法
  11. Linux硬盘分区方案与分区格式介绍
  12. 转:Django新手需要注意的10个要点
  13. 嵌入式程序员基本知识二(转载)
  14. 不畏将来,不念过往,如此安好
  15. python pexels_从零开始学习python爬虫方法,从安装到语法基础(附赠资料)
  16. 什么是虚拟主机?虚拟主机的作用有哪些?
  17. Packet Tracer(第二期)--4RIP
  18. JAVA Calendar详解
  19. 线性代数-向量组的线性相关
  20. 《物理光学》——光的衍射

热门文章

  1. Transformer12
  2. 小程序验证身份证号、验证手机号方法
  3. 解决MAC删除应用程序后依然残留的图标
  4. Google Earth Engine ——边界线识别!
  5. 全力配合金融改革,尝试期货投资基金
  6. 《P2SGrad Refined Gradients for Optimizing Deep Face Models》论文阅读
  7. BFU数据结构头歌实验:基于BF算法的病毒感染检测
  8. C语言-1-初识C语言(二)
  9. A Unified Multi-scale Deep Convolutional_Neural Network for Fast Object Detection 论文笔记
  10. html地图周边搜索,高德地图API实现定位、地点搜索和周边搜索(H5/Vue/微信小程序)...