Spring Integration TCP反序列化器无法获取完整消息求助
问题场景
我们用Spring Integration Flow对接TCP端口接收HL7消息,当前代码如下:
@Bean public IntegrationFlow integrationFlow() { return IntegrationFlows.from(Tcp.inboundGateway(Tcp.nioServer(port) //.deserializer(new HL7Deserializer()) .deserializer(TcpCodecs.lengthHeader1()) .serializer(TcpCodecs.lengthHeader1()) )) .transform(Transformers.objectToString()) .channel("testChannel") .get(); } @Bean public IntegrationFlow testingChannnel() { return IntegrationFlows.from("testChannel") .handle("messageHandler", "handleMessage") .get(); } @Component public class MessageHandle implements MessageHandler { @Override public void handleMessage(Message<?> message) { String payload = message.getPayload().toString(); System.out.println("Received message: " + payload); } }
输入的HL7格式消息:
MSH~|&HTAPPL200TSQA~SQA-VENDOR~DNSDG HOME TELEHEALTH613~SQA-VA~DNS20170530223011^ACK~A04200 TSQAApplication320170530223011T2.4^^ALNEUSA
MSAAA613Application120170530223005^^^^0~Message accepted^
现在遇到的问题是:反序列化时消息被拆分接收,收到的内容如下:
Received message: MSH~|&HT
Received message: PPL200TSQA~SQA-VENDOR~DNSDG HOME TELEHEALTH613~SQA-VA~DNS2017
Received message: 530223011^ACK~A04200 TSQAApplication3201705302
Received message: 3011T2.4^^ALNEUSA
MSAAA613Application12017
问题原因
你当前用的TcpCodecs.lengthHeader1()是基于1字节长度头的编解码器,它要求消息开头必须带1个字节的长度标识,用来告诉解码器后续要读取多少字节的内容。但HL7消息本身并不遵循这个规则,HL7是靠特定的结束符(通常是\r)或者自身的结构来标识完整消息的,所以用长度头解码器会把HL7消息按错误的规则拆成碎块。
修改方案
方案1:启用HL7专用编解码器(推荐)
你代码里已经注释了HL7Deserializer,这是Spring Integration专门为HL7消息设计的反序列化器,直接启用它就行,同时配套使用HL7序列化器处理响应:
@Bean public IntegrationFlow integrationFlow() { return IntegrationFlows.from(Tcp.inboundGateway(Tcp.nioServer(port) .deserializer(new HL7Deserializer()) .serializer(new HL7Serializer()) // 发送HL7响应时用专用序列化器 )) .transform(Transformers.objectToString()) .channel("testChannel") .get(); }
提示:
HL7Deserializer默认用\r作为消息结束符,如果你对接的系统用的是其他结束符(比如\n),可以通过构造方法指定,例如new HL7Deserializer('\n')。
方案2:使用基于结束符的通用编解码器
如果不想用HL7专用的,也可以用Spring Integration提供的基于结束符的编解码器,指定HL7消息的结束符即可:
@Bean public IntegrationFlow integrationFlow() { return IntegrationFlows.from(Tcp.inboundGateway(Tcp.nioServer(port) .deserializer(TcpCodecs.cr()) // 以\r作为结束符,对应HL7标准 .serializer(TcpCodecs.cr()) )) .transform(Transformers.objectToString()) .channel("testChannel") .get(); }
注意:这种方式只是简单按结束符分割消息,不如HL7专用解码器适配性强,无法处理HL7消息的一些特殊结构场景。
验证效果
修改完成后重启服务,再发送完整的HL7消息,就能收到完整的内容,不会再出现拆分的情况。
内容的提问来源于stack exchange,提问作者Piratheepan

