news 2026/4/3 6:28:37

HL7协议对接

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HL7协议对接

背景

在对接医院中PETCT设备的诊疗数据时用到。

HL7定义及重要性

HL7(Health Level Seven)是一种基于国际标准组织(ISO)的开放标准,用于在医疗信息系统之间进行数据交换。HL7协议在医疗行业中的重要性在于其提供了一种高效、准确和标准化的信息传输方式,这对于改善病人护理、简化医疗机构的运营和管理以及支持临床决策具有重大意义。

HL7 消息结构

HL7 标准包含256个事件、116个消息类型、139个段、55种数据类型、408个数据字典,涉及79种编码系统。 在 HL7 中,有四个最基本的术语概念:

  • 触发事件(trigger evenDT):当现实世界中发生的事件产生了系统间数据流动的需求,则称其为触发事件。也可以理解为一个数据请求。

  • 消息(message):它是系统间传输数据的最小单位,由一组有规定次序的段组成。每个消息都是用一个消息类型来表示其用途。

  • 段(segment):它是数据字段的一个逻辑组合。每个段都用一个唯一的三字符代码所标志,这个代码称作段标志。

  • 字段(field):它是一个字符串,是段的最小组成单位。

在 HL7 中,消息(Message)是数据在系统之间交换的基本单元,每条消息都有各自的消息类型,消息类型用于定义消息目的,包含了触发事件。一个消息由多个段(Segment)组成,每一个段都有相应的名称,用于界定其内容或者功能。 一个段又由多个字段(Field)组成。一个消息中的第一个段总是消息头段(Message head segment),它指明了发送和接收的程序名、消息类型、以及一个唯 一的消息ID号码等,接下去段的构成由消息的类型决定。 一个字段又有可能由多个组件(Component)组成。有些消息可进一步由事件码(event code)细分。

段(SegmenDT)

什么是段?

在HL7消息中,消息的每个部分都包含一类特定的信息,例如患者信息或患者就诊数据。这里提到的部分就是段,也就是每一行后都会有一个回车符 < CR >

消息中每个段的名称由该段的第一个域(fields)指定,该域始终为三个字符。HL7消息中可使用超过120个不同的HL7段。

比较常用的分别为

  • 段名称: MSH (消息头) 段包含有关消息本身的信息。该信息包括消息的发送者和接收者、消息的类型以及发送的日期和时间。每个HL7消息都将MSH指定为其第一段。

  • 段名称: PID (患者信息) 段包含有关患者的人口统计信息,例如姓名、患者ID和地址

  • 段名称: NK1 (近亲信息) 细分包含患者近亲的联系信息

  • 段名称: PV1 (患者就诊信息) 部分包含有关患者住院时的信息,例如分配的位置和推荐医生。

  • 段名称: PV2(患者就诊附加信息)

  • 段名称: ORC(医嘱命令所做的检查项目)

  • 段名称: OBR 关于诊断以及观察的请求信息,用于记录医嘱信息

  • 段名称: OBX(用于记录观察的结果)

  • 段名称: QRD 查询定义段,用来定义查询的内容

    查询时间、编码格式、优先等级、ID号、请求数据的最大值、请求方的信息、所要请求的内容、数据编码的部门信息

  • 段名称: QRF 进一步定义查询内容

  • 段名称: DSP 重复消息段 装载LIS返回的报告结果,需要用循环的方式把数据取出

    备注

    由于HL7消息用于将各种与医疗保健相关的信息传递到各种不同的系统,因此有时HL7消息需要包含自定义数据。为了适应这种情况,HL7标准使系统供应商可以创建带有自定义字段的Z段,以传输此数据。按照惯例,所有自定义段都以字母Z开头。例如,可以创建ZPD段以包含自定义的患者人口统计信息。Z段可以放置在HL7消息中的任何位置,但是通常位于消息中的最后一段。

域(fields)

分隔符 “|”

HL7消息的每个段都包含一个或多个域(也称为fields)。默认情况下,竖线(|)字符用于将一个域与另一个域分开。

域可以是原始数据类型(例如字符串或数字),也可以包含多个元素(Component)。如果某个域(fields)包含多个元素,则这些元素(Component)通常以^字符分隔。如果元素还包含子元素(Subcomponent),则这些子元素通常以&字符分隔,子元素(Subcomponent)必须 是原始数据类型(例如字符串或数字)。

  • "|"分隔符中可以包含其他的分隔符:

  • “^” 成分分隔符,表示该位置有多个属性,例如:|101761^熊婷| 该位置是患者信息,101761是患者编号 熊婷是患者名字

  • “~” 子成分分隔符,成分的下一分级

  • “&” 表示该位置是数组结构,类型相同可以循环 例如:|&张三|&李四

HL7数据类型

序号类型编码 类型说明
1ST 字符串
2TX 文本数据
3FT 格式化文本
4NM 数字
5SI 序列id
6SN 结构化数据
7ID HL7表的编码值
8IS 用户定义表的编码
9EI 实体标识符
10DT 日期
11TM 时间
12CE 编码要素
13CX 具有校验数位的扩展符合ID
14XCN 扩展符合ID号和ID名
15XAD 扩展地址
16XPN 扩展姓名
17XTN 扩展通讯号码

java对接

引入依赖

<dependency> <groupId>ca.uhn.hapi</groupId> <artifactId>hapi-base</artifactId> <version>2.3</version> </dependency> <dependency> <groupId>ca.uhn.hapi</groupId> <artifactId>hapi-structures-v24</artifactId> <version>2.3</version> </dependency>
@Slf4j @Component public class Hl7AppRunner implements ApplicationRunner { @Autowired SystemConfig systemConfig; /** * 设置核心线程数 */ private static final int CORE_POOL_SIZE = 50; /** * 设置最大线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程 */ private static final int MAX_POOL_SIZE = 100; /** * 设置缓冲队列大小 */ private static final int QUEUE_CAPACITY = 100; /** * 设置线程的最大空闲时间,超过了核心线程数之外的线程,在空闲时间到达之后会被销毁 */ private static final int KEEP_ALIVE_SECONDS = 60; private static HapiContext context = new DefaultHapiContext(); public void start() { try { ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_SECONDS, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(QUEUE_CAPACITY)); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); MinLowerLayerProtocol mllp = new MinLowerLayerProtocol(); mllp.setCharset("UTF-8"); context.setLowerLayerProtocol(mllp); context.setExecutorService(executor); //生产环境中可能出现段中域的类型不符合标准,例如病人死亡日期生产环境中出现0的情况导致数据无法接收,实际只能为null或标准的日期格式,而这些数据不影响业务,所以跳过校验。 context.setValidationContext(new NoValidation()); ServerConfiguration s = new ServerConfiguration(); Integer port = 9200; boolean useSecureConnection = false; // are you using TLS/SSL? HL7Service ourHl7Server = context.newServer(port, useSecureConnection); ourHl7Server.registerApplication(new MyReceivingApplication()); // ourHl7Server.setExceptionHandler(new MyHl7ExceptionHandler()); ourHl7Server.startAndWait(); log.info("socket 服务 启动成功 SUCCESS , port {}", port); } catch (Exception e) { e.printStackTrace(); } } @Override public void run(ApplicationArguments args) throws Exception { start(); } }
@Slf4j @Component public class MyReceivingApplication implements ReceivingApplication { @Override public Message processMessage(Message message, Map map) throws ReceivingApplicationException, HL7Exception { Message ack = null; try { if (!message.isEmpty()) { log.info("ip,{},port,{}", map.get("SENDING_IP"), map.get("SENDING_PORT")); log.info("接收成功,{}", message); handleMessage(message); } } catch (Exception e) { log.error("处理HL7消息异常", e); } try { ack = message.generateACK(); log.info("返回处理结果ACK:{}", ack.toString()); } catch (Exception e) { log.error(e.getMessage()); } return ack; } @Override public boolean canProcess(Message message) { return true; } public String handleMessage(Message message) throws HL7Exception { String id = ""; if (message instanceof ORU_R01) { //检查报告类型的消息 ORU_R01 oruR01 = (ORU_R01) message; MSH msh = oruR01.getMSH(); id = msh.getMsh10_MessageControlID().getValue(); ORU_R01(oruR01); } else if (message instanceof SIU_S12) { SIU_S12 siuS12 = (SIU_S12) message; MSH msh = siuS12.getMSH(); id = msh.getMsh10_MessageControlID().getValue(); siuS12(siuS12); } else if (message instanceof ORM_O01) { ORM_O01 ormO01 = (ORM_O01) message; ORM_O01_ORDER order = ormO01.getORDER(); ORC orc = order.getORC(); String orderStatus = orc.getOrc5_OrderStatus().getValue(); messageDO.setType(orderStatus); if ("SC".equals(orderStatus)) { System.out.println("登记"); //处理登记类型的消息 ORM_O01_sc(ormO01); } else if ("CM".equalsIgnoreCase(orderStatus)) { //处理完成检查类型的消息 System.out.println("完成检查"); ORM_O01_cm(ormO01); } else if ("IP".equalsIgnoreCase(orderStatus)) { //处理检查收费类型的消息 System.out.println("检查收费"); ORM_O01_ip(ormO01); } } // 保存消息记录 saveMessage(messageDO) return id; } }

可视化工具的使用

7Edit 2.x

消息查看

业务中可以通过接口对接文档获取需要的字段,然后找到对应段中的域获取。

消息发送

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/3 4:20:14

5分钟深度拆解:Figma数据流转的架构设计与工程实践

5分钟深度拆解&#xff1a;Figma数据流转的架构设计与工程实践 【免费下载链接】Figma-Context-MCP MCP server to provide Figma layout information to AI coding agents like Cursor 项目地址: https://gitcode.com/gh_mirrors/fi/Figma-Context-MCP 还在为设计稿到代…

作者头像 李华
网站建设 2026/3/22 16:01:42

Wan2.2-T2V-A14B与Pika、Runway等商业产品的差距在哪?

Wan2.2-T2V-A14B与Pika、Runway等商业产品的差距在哪&#xff1f; 在短视频爆炸式增长的今天&#xff0c;内容创作者每天都在和“时间”赛跑。一个广告创意从灵感到成片&#xff0c;动辄几周&#xff1b;一段电影预演动画&#xff0c;需要专业团队反复打磨——而AI生成技术正试…

作者头像 李华
网站建设 2026/3/24 23:23:11

无线组网新突破!SG-Lora-TCP 模块,7 公里 TCP 信号无线透传更自由

在工业自动化、智慧园区、远程监控等场景中&#xff0c;TCP 网线布线受地形限制、施工成本高、后期维护不便等问题是否一直困扰着你&#xff1f;SG-Lora-TCP 无线中继模块重磅来袭&#xff0c;通过 Lora 无线通信技术将 TCP 信号转为无线信号远传&#xff0c;空旷传输距离达 70…

作者头像 李华
网站建设 2026/3/27 22:43:10

祖传项目二开快上线了,却还有很多旧的资源,怎么办?

点击上方亿元程序员关注和★星标 引言 哈喽大家好&#xff0c;欢迎小伙伴提供的素材&#xff1a; 亿哥晚上好&#xff0c;上次压缩了PNG图片后&#xff0c;图片资源还是非常大。 仔细研究了一下&#xff0c;发现项目里面居然还有很多没用到的祖传资源&#xff01; 游戏快要上线…

作者头像 李华
网站建设 2026/3/25 5:49:36

ZyPlayer终极配置手册:5大核心功能深度解析

ZyPlayer终极配置手册&#xff1a;5大核心功能深度解析 【免费下载链接】ZyPlayer 跨平台桌面端视频资源播放器,免费高颜值. 项目地址: https://gitcode.com/gh_mirrors/zy/ZyPlayer ZyPlayer是一款跨平台桌面端视频资源播放器&#xff0c;以其免费高颜值的特点为用户提…

作者头像 李华
网站建设 2026/4/3 4:13:50

23、全面了解TCP/IP:资源、书籍与网络社区

全面了解TCP/IP:资源、书籍与网络社区 1. TCP/IP书籍推荐 学习TCP/IP,阅读相关书籍是个很好的途径。以下为你推荐一系列经典书籍: | 书籍名称 | 作者 | 出版社 | ISBN | 简介 | | — | — | — | — | — | | 《TCP/IP illustrated》 | Richard Stevens | Addison - We…

作者头像 李华