目录
一、前言
网络上有很多解析HL7 V2消息的文章,但是大部分都是按行拆分,按管道符拆分,之后根据业务,按照下标找到对应的业务数据,由于笔者负责公司里边的接口工作,所以查找到的解析工作,对我来讲,有以下几个弊端:
- 跟版本耦合,HL7-2.X有多个版本,不希望一个接口项目的代码,遇到另外一个项目版本不一的时候,需要再调整代码实现一遍
- 工作繁琐。需要逐个实现不同的接口类型。比如ADT_A01接口的代码,就不能接收 ORU_R01 的数据
- 需要开发者对消息结构有了解,需要知道哪些结构是List结构,从而有针对地循环那部分的代码
针对以上两点,本文介绍了以下几点内容:
- HL7 工具 7Edit 的使用:接收、发送、编辑 HL7文本。
- 使用 HAPI 搭建 HL7服务
- 针对以上问题,提出了自己的接口实现方案,着急的朋友可直接从第 六 部分开始看
- 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;
}
}
数据库连接及属性类的代码不再贴了。