Mirth Connect 互联互通 第三章 创建通道
第三章 创建通道
引子:本章是最基本的操作,有详实的图片,供大家参考,向后章节就不会这么详细了,因为大多数基本操作都在这里介绍了。
本章介绍了通道的真实环境实现,及生命周期,每一个组件最基本的概念。希望大家能喜欢,多谢支持,学习,交流。
现在,让我们挽起袖子干活:创建通道。我们会创建一个简单的通道,接受一个HL7v2消息并转存成文件。
如果Mirth Connect Server还没启动,通过Mirth Connect Server Manager启动服务,然后启动Mirth Connect Administrator。在管理员界面上,左侧Mirth Connect中,切换到Channels项,注意多出了个Channel Task可折叠的导航栏。
图3-1 导航栏
在这里选择"New Channel",看到如下界面:
图3-2 通道概述窗口
界面中相关描述如下:
1 输入通道的名字 例如: Simple Channel
2 添加通道标签,如Test,标签的作用用于以后对通道进行分类。
3 设置入站和出站格式:HL7v2.x
4 点击“Save Changes” 保存通道。
OK,简单的通道创建完毕。
Source Connector(源连接器)
切换到Source标签,来配置源连接器,用于指定管道怎么从通道中读取消息,为了试验的目的,我们选择的是Connector Reader,从Mirth Connect Administrator接口发送消息,因此不需要任何应用测试我们创建的通道。
图3-3 源连接器设置
很明显,对于连接器类型Channel Reader没有更多项的配置,其他的选项会有更多的配置项,自己可以切换一下看看。在左边任务栏中的Channel Task里有Edit Filter和Edit Transformer,本实验于此无关,我们添加一个Filter,让大家熟悉这个过程,由于我们的实验不需要Filter,实验后删除掉它。点击Edit Filter切换如下界面:
图3-4 源连接器过滤器
在任务栏和右键菜单中都有关于Filter的菜单项。我们选择Add New Rule,
图3-5 规则过滤器
在类型列需要双击才能选择过滤器的类型,我们选择javascript,并双击name列重命名这个过滤器,在规则中可以写js脚本。
图3-6 过滤器操作
我们右键删除刚刚创建的Filter,并单击左侧任务栏中的Back to Channel,返回到Source Connector。Transformer转换器的操作过程与Filter类似。
如果创建了过滤器或转换器,需要校验是否正确,那么就单击Validate Connector.
图3-7 源连接器验证
我们看到已经成功的校验了,单击Save Changes 保存即可。
当然不但通道可以导出,过滤器和转换器一样可以导出。
TMP(模板对象) MSG(消息对象) Message(消息)
如果你曾经为某个通道创建过转换脚本,或阅读这方面的知识,你可能已经知道有两个魔法变量,他们就是"tmp"和"msg",你可以用这两个变量来调整入站和出站消息。
那么,他们是什么,从哪里来,为什么Message在一个地方,而msg在另外的地方?
为了回答这些问题,咱们预习或复习一下Mirth引擎是怎样处理即将到来的消息和传递消息。
Attachment Script 附件脚本
这是消息会遇到的第一个关口。这个阶段的入站消息是一个可访问的消息对象,此时还没有存入数据库,因此,你可以在这里写脚本对数据进行判断,有可能某种原因不让它进入数据库,比如字符编码问题,不符合进入你的数据库,就要删掉它。
Preprocessor Script 预处理脚本
在入站消息遇到Preprocessor之前,会被以原始格式存入数据库。因此,即使消息被修改了,原始内容仍然存在,在Global全局和Channel Preprocessor的脚本里,入站消息对象可以通过connectorMessage.getRaw().getContent()访问。
Source Filter and Transformer Scripts 源过滤器和转换器脚本
事实上,过滤器脚本和转换器脚本会被合并成一个脚本执行,就像这样:
if (doFilter() == true){
doTransform();
return true;
} else { return false; }
不管你给过滤器添加了多少个规则,也不管你给转换器添加了多少个转换步骤,最终都会被合并成一个单独的脚本。在执行这个脚本前,Mirth 引擎为入站消息添加如下一行创建满足ECMAScript和XML规范的消息对象:
msg = new XML(connectorMessage.getTransformedData());
如果你在出站消息模板窗口提供了消息模板,引擎也为出站消息添加满足E4X XML规范的对象:
tmp = new XML(template);
在这个阶段,入站出站消息可以被直接访问到:
connectorMessage.getRaw().getContent()//入站消息
connectorMessage.getTransformedData()//未经处理的出站消息
在Preprocessor步骤上,数据库只包含被存储的原始消息。一旦Mirth引擎失败,当重启的时候,引擎会再次提取存储原始消息进行处理。
如果你没有提供出站模板或显示声明tmp实例,那么msg实例就会被作为源连接器的出站消息。
Destination Filter and Transformer Scripts 目标过滤器和转换器脚本
目标的过滤器和转换器类似于源过滤器和转换器。Mirth引擎创建msg和tmp实例处理入站和出站消息。根据上面的陈述,在这个阶段入站出站消息也能直接访问:
connectorMessage.getRaw().getContent() //入站消息
connectorMessage.getTransformedData() //出站消息
当消息被完全处理后,对于源连接器,数据库里就会包含原始的、原始被处理过的、转换的、编码的消息,同样,对于目标连接器,数据库里包含编码的和发送的消息。
如有你没有提供任何出站模板或显示声明创建tmp实例,msg实例会被当做目标连接器的出站消息。
Response Script 应答脚本
类似的,Mirth引擎使用connectorMessage.getResponseTransformedData()返回的消息创建msg对象,如果有出站消息模板,利用出站消息模板创建tmp。
Postprocessor script 后处理器脚本
最后执行的脚本就是通道的Postprocessor了,紧接着是Global Postprocessor。这两个阶段是个简单的占位符,不提供任何消息处理机制,也不提供逻辑处理。
复习完以上知识,我们准备继续......
Destinations Connector 目标连接器
接下来,切换到Destinations标签页,指定通道如何以及在哪里发送出站消息。每个通道必须至少有一个目标,当然多个目标也是可以的。
现在,改变目标的名称为 To File ,改变Connector type 连接器的类型为File Writer,来配置这个连接器。
单击连接器类型的下拉菜单会有很多中,你大可以逐个的去了解熟悉一下这些类型和设置,了解完毕,切回File Writer。指定文件名和被写入文件的位置(不需要在目录里建文件),单击Test Writer按钮来校验设置的正确性。
图3-8 目标连接器设置
一个重要的步骤就是要指明导出到文件的数据种类,拖拽右边Destination Mappings框中的Encoded Data到Template框中(见下图)。这就告诉通道把入站消息,以在Summary标签里设置的格式转换到文件里(还记得吗?我们设置的是HL7v2.x)。
注意:你能通过左边的面板或右键的弹出菜单切换导航页面或功能。
每个目标都有自己的过滤器、转换器、应答处理器。多个目标就会重新排列,让最繁忙的目标先运行,因此,可以提高整个通道的性能。如果我们有不需要的目标,可以禁止掉。最后和源连接器一样,能够导入导出目标连接器,当然也可以整个通道导出。
图3-9 目标连接器模板编码
Filter 过滤器
我们不打算为这个通道指定过滤器,目标To File只是简单的处理由源连接器传过来的所有消息。
Transformer 转换器
入站消息到出站消息的映射或转换既可以放在源链接器转换器里,也可以放在目标转换器里。我的首选是使用目标转换器处理属于这个特定目标的消息,而其他消息不予处理。
单击Edit Transformer创建新的以步骤为单位的转换器。改变转换器的步骤类型为JavaScript且重命名为SetDate。
看到没有,在转换器窗口的右边有三个附加标签:Reference, Message Tree, Message Template,在本章我们逆序讲解这三个标签的使用方法,从Message Template消息模板讲起
图3-10 目标连接器转换器
消息模板使得入站消息映射到出站消息变得很容易。切换到这个标签,你可以看到两个消息模板区。为了简单化,在这个通道,我会使用HL7v2.4 ACK消息。一般情况下,我会添加目标过滤器只允许某个类型的消息通过。如果你没有HL7v2.4 ACK消息或根本不知道那是什么,这里有个现成的模板供参考和使用。
HL7v2.4 ACK 模板:
MSH|^~\&|ADM||ALL||||ACK^A01^ACK||D|2.4|||NE|
MSA|||
把这个模板拷贝粘贴到入站消息模板区或出站消息模板区,Data Type数据类型都设置为HL7v2.x(在Summary 标签里设置过的)。看看出站消息模板的数据类型列表,为了熟悉每个数据类型,单击properties,详细了解Mirth Connect提供的每个数据类型所有属性。最后不要忘记切回HL7v2.x。
图3-11 出站模板
现在切换到Message Tree标签。Mirth Connect 试着解析消息模板,并以树状结构展示,如果失败,你会看到像“Template is not valid HL7v2.x”的警告。而我们的模板是有效的,已经成功解析了。
图3-12 模板消息树
打开任何节点,例如MSA,然后拖拽MSA.1.1下的[empty]节点到转换器的JavaScript编辑区。你会看到tmp['MSA']['MSA.1']['MSA.1.1']。
图3-13 转换器快捷脚本
最后一个标签就是Reference了,这个标签预定义了好多JS的函数,也有用户定义的JS函数,它们能够被拖拽到转换器的JS编辑器里。JS函数被逻辑分组,选项ALL显示所有的函数,它们是按字符排序的。为了获得想要的函数范围,我们可以在过滤文本框里输入关键字,查看那些你特定需要的函数,例如:输入log,你应该看到有log an info statement和log an error statement两个选项。拖拽log an info statement选项到JS编辑器里,效果是这样:
logger.info('message');
图3-14 函数检索
再来一个,选择分类项选Date Functions,过滤框输入date,在列出来函数项中拖拽"Get Current Date"到JS 编辑区,你应该看到var dateString = DateUtil.getCurrentDate(pattern);
图3-15 日期时间函数
学习Mirth Connect API隐含的所有规则,那将非常耗时,幸运的是Mirth 3.4提供了代码提示及级联使用方法。而有关更多的代码编辑器的设置在Mirth Connect pannel(Dashboard)>Settings>Administrator>Code Editor Preference。
图3-16 引用函数检索方式设置
我们看看代码的级联提示
图3-17 JS脚本级联提示
我们输入以下信息在JS编辑区里:
图3-18 最终脚本
做完这一切,单击Validate Script,只是检查代码的语法正确与否,OK,单击Back to Channel,继续单击Save Changes保存我们要部署的第一个通道。
图3-19 脚本校验
Deployment 部署
一旦通道保存,我必须部署它。对于单个通道,在channel Tasks任务栏中单击Deploy channel,对于多个类似通道,单击Redeploy All。
图3-20 通道单独部署或全部部署
在上述两种操作方式下,Mirth Connect Administrator都切换回Dashboard窗口,我们可以看到,一个Simple Channel已经被部署了,并以列表方式显示。检查其状态是启动的状态。
图3-21 通道部署后状态
Testing the Channel 测试通道
你可能会回想起来,Simple Channel源连接器类型我们选择的是Channel Reader,它允许直接通过Mirth Connect Administrator接口放置一个消息。
请看具体的操作,在DashBoard Tasks 导航面板上选择Send Message发送消息,如果你不了解HL7V2.x ACK 消息结构,可以拷贝粘贴消息Source 3-3的片段,然后单击Process Message进行消息的处理。
Source 3-3HL7v2.4 正向ACK消息样例
MSH|^~\&|ADM|Sender|ALL|Receiver|2014||ACK^A01^ACK|0123456789|D|2. 4|||NE| MSA|AA|0987654321
图3-22 通道消息发送
到我们指定To File 目标文件写入连接器的文件夹,看看是否有test.hl7文件。
图3-23 通道产生的文件
打开该文件,看看内容,注意日期字段已经替换为我们定义的时间和格式。
图3-24 通道产生文件的内容
Dashboard界面会显示该通道的统计信息,而在Server Log信息面板会显示目标转换器的日志输出信息.(日志的日期可以在转换器里写入脚本)
图3-25 运行通道信息面板
单击左边面板的clear statistics,可以复选弹出窗口的任何项,快捷方式有个Invert Selection,会全部选择或全部不选,然后OK。可以清零统计信息。
图3-26 清除通道统计信息
切换Current Statistics 和Lifttime Statistics单选,看看面板的不同变化。
图3-27 当前统计信息
单击Remove All Messages,选择 Include selected channels that are not stopped ...然后Yes。注意到LiftTime仍然显示通过通道的所有消息。
图3-28 清空通道选项
单击"X",清除面变消息。
图3-29 server Log 面板清除
Failure 失败
作为一名软件开发人员,你认为代码编写的漂亮,但也有失败的时候。如果连接器、过滤器或转换器失败,会出现什么情况,让我们来模拟这个场景。
通道反部署,单击Channels,选择Simple Channel 记录行。单击EditChannel或双击切换到通道编辑模式。在Summary标签上单击Set Data Types,改变源连接器入站消息类型,把HL7v2.x改成XML。实际上,HL7版本2消息不是XML格式,因此这很明显是个失败的案例。
图3-30 通道编辑
图3-31 通道数据类型设置
保存这个改变后,重新部署这个通道。清零统计信息、消息、和日志,如果你还不知道,较早前有解释,向前翻阅相关章节。发送同样的ACK消息。这次结果应该不一样的,Errored列应该有一个失败的消息显示出来。
图3-32 通道错误统计
为了找到错误的原因,展开错误通道,选择包含错误的连接器(我们的例子就是Source Connector):
图3-33 通道产生的具体错误
然后单击View Message或双击失败通道的名字,你应该可以看到该连接器的视图窗口,对,就是有错误的那个连接器,然后单击错误,切换到Errors 标签,可以看到具体的错误信息。
图3-34 错误详细信息
在这个窗口的堆栈跟踪给定的一些关于产生错误的提示及如何找到这个错误。提示的是ER7Serializer error(ER7序列化错误),发生错误的原因是ERROR MESSAGE: Error converting XML to ER7,很明显提示XML转换错误。在这个窗口中,切换Messages、Mappings、Errors标签,让自己熟悉它们提供的信息。
也可以选择Reprocess Messages再次发送被选择的消息,很显然,错误依然存在,我们还没有改动。
为了修复这个问题,单击导航面板的Channels,选择Simple Channel的Summary标签页,改变源链接器入站消息类型为HL7v2.x。保存并重新部署该通道。
图3-35 通道入站和出站消息配置
发送消息并注意到已成功传递了这个消息,文件也按预期创建了。
图3-36 通道正常消息
Global map(全局映射),Global Channel Map(全局通道映射),Channel Map(通道映射)
你可能对一个地方创建的变量(例如在全局脚本里)是如何传递到另一个地方(多数情况下是通道脚本)感到困惑。Mirth Connect使用了一个复杂的概念(一种被称为全局和通道映射)解决这个问题。这种映射的变量有5个,其中三个是最常用的。
Global Map该变量对所有通道都有效;一个通道可以把变量放到全局映射里,其他通道就可以访问它。这种能力使用的时候一定要小心,因为有可能另一个通道正使用你要覆盖的变量接收消息。
Global Channel Map该映射用于为特定通道指定变量的。在Channel's Summary标签选项卡上有关于这个变量的选择:clear this map when the channel is deployed 当通道部署时,是否清零映射。
Channel Map该映射与Global Channel Map是一样的,但仅存在于唯一消息的上下文中,也就是一旦有新消息到达,所有数据被清除。
其他两个映射是:
Connector Map用于Mirth引擎,存储连接器特定消息,例如 消息的发送者和消息类型。你可以使用这个映射;然而你需要的值可能被萧清。
Response Map存储通道的应答消息,例如 ACK消息。尤其是,你在目标转换器创建确认消息,并且映射通道后处理器的响应。
五个map的生命周期是不同的,下图显示一个映射什么时候可用,以及被放置到映射里的变量在那些阶段能被检索到。
图3-37 映射的生命周期
看上图,Connector Map 在Channel Attachment脚本里是无效的;然而,放到Global Preprocessor脚本里的数据是能够被Channel Preprocessor脚本访问的。
Global Map允许把一个变量传递给所有脚本处理器。以如下方式访问这个映射:
Packages.com.mirth.connect.server.util.GlobalVariableStore.getInstance().getVariables()
Global Channel Map 在全局部署和反部署里是无效的,除此以外,和Global Map一样。直接调用这个映射:
Packages.com.mirth.connect.server.util.GlobalChannelVariableStoreFactory.getInstance().get(channelId).getVariables()
Channel Map、Connector Map、Response Map的实例调用如下:
connectorMessage.getChannelMap()
connectorMessage.getConnectorMap()
connectorMessage.getResponseMap()
所有映射都实现了java.util.Map接口,意味着Map<K,V>的所有方法都适用于Mirth Connect映射。
Global Scripts 全局脚本
有两样事情我们还没有接触到:全局脚本和代码模板。
全局脚本和通道脚本一样扮演同样的角色,有助于划分业务逻辑。他们都有部署、反部署、预处理和后处理脚本,唯一的不同是全局脚本适合于所有通道。
单击Mirth Connect Administrator 导航面板中的Channels,然后单击Channel Tasks中的Edit Global Scripts,部署全局脚本编辑器窗口默认的显示出来。
图3-38 部署阶段全局脚本
假设我们有几个与Simple Channel类似的通道(目前为止我们就创建一个),他们把消息都存储在本地机同一个文件夹下,现在我们可能需要重定向这些文件到不同的地方(比如:网络驱动器盘符下)。逐个改变源连接器就太乏味了,而且容易发生错误。更好的办法是设置一次文件夹位置,把它传递给每个源连接器,只有需要的时候去改变它,这就是Deploy Global Script允许我们所做的事情。
在右边全局脚本编辑器区域显示预定义和用户定义的JS 函数列表,与我们通道转换器的Reference标签功能类似。
在分类项中选择Map Functions或在过滤框中输入global,跟全局有关的函数就显示出来,拖拽Put Global Variable Map 到编辑器里,就会看到Map的键值对函数,敲入下面的脚本到编辑器里,这段代码主要是提取在系统环境变量里配置的TMP环境变量,并存到全局脚本里。你应该校验该文件夹是否存在。
var tempdir = java.lang.System.getenv("TMP");
globalMap.put('testDir', tempdir );
var testDir = new Packages.java.io.File( globalMap.get('testDir') );
if ( !testDir.exists() )
try {
testDir.mkdir();
} catch (err) {
logger.error( 'GLOBAL Scripts: Cannot create Temp folder ' + err.message );
}
校验这个部署全局脚本并保存。OK,现在到了改变Simple Channel目标连接器设置的时候了。
打开Simple Channel 通道,进入通道编辑区,切换到Destinations标签,如果你创建了多个目标,请选择To File目标。在Directory文本框中输入 ${testDir},这时候点击Test Write 会显示错误,因为testDir变量在编辑模式中还无效,你必须重新部署以使得Deploy Global Script所有事情生效。
图3-39 目录设置和测试写入
保存Simple Channel,单击Redeploy All。如果你定义的文件夹不存在,在Server Log 信息面板窗口会显示一个错误。如果是这样,矫正Global Scripts重新部署所有。按照前面章节讲的测试一下Simple Channel,看消息是否发送成功。
图3-40 通道生成的文件
如果你想存储Global Scripts脚本到文件里,请记住不能和通道一起使用Export All选项。你不需在菜单中只对Global Script导入和导出(这个功能自己练习,就在Global Script编辑器的左边面板中)
Code Templates 代码模板
代码模板是你创建和管理自己代码、变量和函数的位置。创建的变量和函数在转换器、过滤器以及其他脚本编辑器里的引用列表中是有效的。在Mirth Connect 导航面板Channel Tasks里,单击Edit Code templates,打开代码模板编辑器。
作为示例,我会定义一个简单的函数返回带有格式的日期时间值。单击New Library,设置一个名字,并定义该库显示在哪些通道里。
图3-41 代码模板编辑
单击New Code Template,把Name列从Template 1改成 Get Current Date/Time或其他什么,检查Type应该设置成Function并敲入代码。上下文Context栏设置用户定义的函数在哪些阶段脚本里显示。在这个例子里,我们的Now() 函数在Source Connector 和Destination Connector里可见。
图3-42 代码函数可见性设置
保存代码模板,返回Simple Channel,切换到To File 目标转换器。右边面板切换到Reference标签,在Category下拉列表里选择User Defined Functions。可以看到我们刚刚定义的函数了,拖拽这个函数到编辑区,修改MSH.7.1片段值,并使用这个函数设置日期时间。
图3-43 用户定义函数在转换器中显示
保存和测试Simple Channel通道,和我们以前用的发送消息一样。你应该可以看到类似的结果了。