清除过滤器
文章
Qiao Peng · 一月 31, 2024
InterSystems IRIS、Health Connect和上一代的Ensemble提供了优秀的互操作架构,但即便有低代码开发能力,很多开发者还是希望能用自己的技术栈语言在InterSystems的产品上开发互操作产品。
考虑到互操作产品本身的开放性要求和各个技术栈背后庞大的生态价值,InterSystems IRIS和Health Connect提供了Production EXtension (PEX)架构,让开发者使用自己的技术栈语言来开发互操作解决方案。目前PEX支持Java、.net、Python。
这里我们介绍使用Java利用PEX进行互操作产品的开发。
一 InterSystems IRIS上使用Java开发的基础
在进入PEX主题前,需要简单介绍一下Java在InterSystems IRIS上开发的各种技术选项,因为PEX也是以这些技术选项为基础的。
如果仅把InterSystems IRIS作为一个数据库看待,可以使用JDBC对它进行SQL访问,这是最传统的开发方式;
Java是一个面向对象的开发语言,而InterSystems IRIS也是支持面向对象的数据平台。InterSystems IRIS的外部语言服务器技术,提供了一套Java原生SDK,让Java和InterSystems IRIS可以互相访问对方的对象,甚至Java可以通过它直接访问InterSystems IRIS后台的持久化多维数组。外部语言服务器提供了非常灵活、高效的开发方式;
如果是想把Java对象直接持久化到InterSystems IRIS,除了Hibernate,InterSystems IRIS提供一种更高性能的方法 - XEP(Express Event Persistence表达事件持久化);
最后,Java可以通过PEX开发InterSystems IRIS的互操作产品组件。PEX基于Java原生SDK。
作为多种Java访问方式的基础,InterSystems IRIS的Java外部语言服务器的架构如下:
InterSystems IRIS和Java通过动态代理对象的方式操作对方对象,动态代理无需在对方代码变更时重新生成代理类。
InterSystems IRIS提供了intersystems-jdbc-<版本号>.jar,不仅用于JDBC连接、也用于Java外部语言服务器连接,提供Java原生SDK。
在Java端通过jdbc.IRIS管理InterSystems IRIS连接,使用jdbc.IRISObject反向操作IRIS对象。
InterSystems IRIS端提供并管理包括Java语言服务器在内的一系列外部语言服务器。注意,一般情况下,使用系统开箱的这些外部服务器就够了,不需要额外建立额外的Java语言服务器。而且,也无需事先启动,外部语言服务器会在调用时自动启动。
Java连接到InterSystems IRIS,并创建IRIS外部服务器的示例:
String connStr = "jdbc:IRIS://127.0.0.1:1972/USER";
String user = "superuser";
String pwd = "SYS";
// 使用DriverManager 创建IRIS连接
// IRISConnection conn = (IRISConnection)java.sql.DriverManager.getConnection(connStr,user,pwd);
// 或使用IRISDataSource 创建IRIS连接
IRISDataSource ds = new IRISDataSource();
ds.setURL(connStr);
ds.setUser(user);
ds.setPassword(pwd);
IRISConnection conn = (IRISConnection) ds.getConnection();
// 创建IRIS外部服务器
IRIS irisjv = IRIS.createIRIS(conn);
// 调用IRIS类%PopulateUtils的类方法Name,产生随机姓名
String tempTrader = irisjv.classMethodString("%PopulateUtils", "Name");
二 PEX 开发
PEX针对于互操作产品的开发,通过PEX使用外部语言开发互操作产品所需的组件,甚至可以通过PEX开发互操作产品的所有组件。
2.1 InterSystems IRIS互操作产品架构
典型的InterSystems IRIS互操作产品架构如下,它的典型工作机制是:
业务服务通过入站适配器监听外部系统,例如TCP和文件系统,将数据组织成消息发送给业务流程
业务流程根据流程需要在特定流程节点将消息发送给业务操作
业务操作通过出站适配器访问外部应用,发送数据并获取响应,并将响应数据组织成消息反馈给业务流程
在互操作产品内部流转的都是消息,消息默认自动持久化并可以通过SQL等方式结构化查询
互操作产品涉及3类组件:
业务组件:包括业务服务、业务流程、业务操作
适配器:包括入站适配器和出站适配器
消息
这3类组件都可以通过PEX进行开发。
2.2 PEX 类和类包
InterSystems IRIS 提供了一个intersystems-utils-<版本号>.jar包,提供com.intersystems.enslib.pex类包,用于基于Java开发互操作产品组件。
在Java代码里还要调用IRIS Object Script开发的组件和代码,因此,还需要intersystems-jdbc-<版本号>.jar。
2.3 示例业务场景介绍
下面我们根据一个示例业务场景介绍如何使用Java PEX进行互操作产品的开发。
业务场景是一个银行间汇款的流程:
业务服务(Finance.FromFileTransaction)监听特定文件夹,并从新汇款申请文件中解析出汇款请求,发送给业务流程(Finance.ProcessPaymentRequest);
业务流程先将请求发送给汇出行的业务操作(Finance.ToPayFromBank),获取汇出行的审核结果;
如果汇出行审核批准,则业务流程继续将请求发送给接收行的业务操作(Finance.ToPayToBank)
这里汇出行的业务操作和接收行的业务操作都会将数据写入特定文件夹的文件中。
这个场景中,我们完全使用Java开发全部的组件,包括:请求、响应消息;入站、出站文件适配器;业务操作;业务流程和业务服务。
下面我们就开始吧。
2.4 消息开发
Java消息类是com.intersystems.enslib.pex.Message的子类,消息中的属性,需要定义为public。它会在互操作业务组件间传递时自动持久化。
在IRIS端,Java消息自动映射到EnsLib.PEX.Message,它是一个持久化的IRIS类,包含以下属性:
%classname属性:Java消息类名
%json属性:Java消息的JSON类型(IRIS动态对象)
在InterSystems IRIS端,例如消息可视化追踪页面和消息表,你看到的Java消息都是EnsLib.PEX.Message类型。
PEX消息用到的共同账号信息类的示例代码:
package Finance;
// 封装银行账号信息的类.
public class PaymentProfile extends com.intersystems.enslib.pex.Message {
public int AccountNumber;
public int RoutingNumber;
public String UserName;
}
请求消息的示例代码:
package Finance;
import Finance.PaymentProfile;
// PEX开发的转账请求消息.
public class TransactionRequest extends com.intersystems.enslib.pex.Message {
public double TransactionAmount; // 转账金额
public PaymentProfile PayFrom; // 付方银行账号信息
public PaymentProfile PayTo; // 收方银行账号信息
public String FromCurrency; // 付方货币
public String ToCurrency; // 收方货币
// 实例化银行账号属性.
public TransactionRequest(){
PayFrom = new PaymentProfile();
PayTo = new PaymentProfile();
}
}
响应消息的示例代码:
package Finance;
// PEX开发的转账响应消息.
public class TransactionResponse extends com.intersystems.enslib.pex.Message {
public boolean approved;
}
2.5 业务组件和适配器的运行时变量
在互操作产品的管理配置页面,可以设置各个业务组件和适配器的配置项,例如文件适配器的文件路径,方便实施和管理。
对于Java开发的业务组件和适配器,同样我们需要这样的配置项。这些配置项,我们称之为运行时变量,这样进行定义:
运行时变量是Java业务组件类和适配器类的public类型的属性
对这些属性使用Java annotation进行元数据描述,例如:
@FieldMetadata(IsRequired=true,Description="文件路径")
public String FilePath;
后面的Java业务组件和适配器会用到运行时变量的声明方法。
2.6 入站适配器开发
如果要开发Java入站适配器,需要定义一个com.intersystems.enslib.pex.InboundAdapter的Java子类。并在类中实现以下方法:
方法
参数
说明
OnTask
无
适配器根据调用间隔设置,周期性地调用该方法对数据源进行查询;将数据调用BusinessHost.ProcessInput()将数据发送给业务服务;BusinessHost是业务服务的固定的变量名
OnInit
无
适配器初始化的方法
OnTearDown
无
适配器退出清理的方法
例如入站文件适配器示例代码如下:
package Finance;
import java.io.File; // 导入File类.
import java.io.FileNotFoundException; // 导入此类以处理错误.
import com.intersystems.enslib.pex.FieldMetadata; // 导入PEX运行时变量类
// 这是一个PEX的入站适配器,检测定义在InboundFilePath的文件夹路径。如果文件夹下有文件,遍历这些文件,使用ProcessInput()将文件路径发送给业务服务
public class PEXInboundAdapter extends com.intersystems.enslib.pex.InboundAdapter {
@FieldMetadata(IsRequired=true,Description="输入文件路径")
public String InboundFilePath; // 文件夹路径配置项.
public void OnTearDown() {}
public void OnInit() {}
public void OnTask() throws Exception {
// 检查文件夹路径,并遍历文件.
File folder = new File(InboundFilePath);
File[] list = folder.listFiles();
if (list.length > 0) {
for (File file : list) {
// 忽略.keep后缀文件.
// 其它文件路径发送给业务组件BusinessHost.
if (file.getName().equals(".keep")) {continue;}
BusinessHost.ProcessInput(file.getAbsolutePath());
}
}
}
}
2.7 Java开发组件的注册与更新
开发好的Java组件,需要在InterSystems IRIS端进行注册,让互操作产品可以直接使用这些组件。
注册的方法在Production扩展页面,点击注册新组件:
在远程类名称中填写Java组件类名
在代理名称中填写IRIS生成的代理类名称,可以和Java类名不同。这个类名是在互操作产品中看到和使用的名字。
选择外部语言服务器为%Java Server
将封装有Java组件类的jar文件路径和其它依赖jar文件路径添加到网关额外CLASSPATHS下
注册后就可以在列表中看到注册的组件和组件类型,并在互操作产品中可以直接使用了。
如果后来修改了Java代码,则需要选中已经组册的组件,对其进行更新:
* 记得下面这些Java开发的组件也需要注册后使用。
2.8 出站适配器开发
同样,可以通过继承com.intersystems.enslib.pex.OutboundAdapter来开发Java出站适配器类。
它需要实现以下方法:
方法
参数
说明
OnInit
无
适配器初始化的方法
OnTearDown
无
适配器退出清理的方法
其它方法
根据需要
执行具体的适配器操作
例如出站文件适配器示例代码如下,它提供写文件的方法:
package Finance;
import java.io.File; // 导入File类.
import java.io.FileNotFoundException; // 导入此类以处理错误.
import java.lang.StringBuffer; // 导入string buffer类.
import java.io.FileWriter; // 写文件的包.
import java.util.Date; // 处理日期的包.
import com.intersystems.enslib.pex.FieldMetadata; // 导入PEX运行时变量类.
import java.text.SimpleDateFormat; // 格式化日期字符串的包.
// 这是一个PEX的出站适配器,通常被业务操作使用,连接到外部系统. 这里适配器提供WriteToFile()方法,供业务操作调用.
public class PEXOutboundAdapter extends com.intersystems.enslib.pex.OutboundAdapter {
@FieldMetadata(IsRequired=true,Description="输出文件路径")
public String FilePath; // 输出文件路径.
public void OnTearDown() {}
public void OnInit() {}
//写文件的方法,输入参数input是向文件中写入的内容
public Object WriteToFile(java.lang.Object input) throws Exception {
// 转换为字符串
String OutputMessage = (String)input;
// 允许用户输入的路径有或没有尾部路径分隔符.
if (FilePath.substring(FilePath.length() - 1) != File.separator) {
FilePath = FilePath + File.separator;
}
// 用当前日期时间产生文件名.
Date today = new Date();
SimpleDateFormat Formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String DateString = Formatter.format(today);
// 产生完整文件路径.
String OutputPath = FilePath + DateString;
// 创建文件.
File OutputFile = new File (OutputPath);
// 实例化FileWriter对象.
FileWriter writer = new FileWriter(OutputFile);
// 将内容写入文件
writer.write(OutputMessage);
writer.close();
return null;
}
}
2.9 业务操作开发
Java业务操作类,是com.intersystems.enslib.BusinessOperation的子类。需要实现以下功能:
方法
参数
说明
OnInit
无
适配器初始化的方法
OnTearDown
无
适配器退出清理的方法
OnMessage
无
个方法会在业务操作收到其它业务组件传递过来的消息时被调用
在该方法内部,可以调用适配器的方法 - Adapter.invoke("适配器方法名", 方法参数)
Adapter是适配器对象,已经实例化,无需执行自己的实例化代码。Adapter是固定变量名
getAdapterType
无
返回使用的适配器类名
如果是PEX开发的适配器,返回的是它注册到InterSystems IRIS的代理类名
如果使用默认适配器,返回 Ens.InboundAdapter
如果不使用适配器,返回空字符串
例如我们的示例中,有以下2个业务操作:
1. 与汇出银行接口的业务操作类:
package Finance;
import Finance.TransactionRequest;
import Finance.PaymentProfile;
import Finance.TransactionResponse;
import java.lang.StringBuffer;
// PEX业务操作类,和支付银行接口.
// 它从业务流程接收请求消息Finance.ProcessPaymentRequest, 将消息内容写入文件并返回内容为'approval' 的响应消息(Finance.TransactionResponse).
public class ToPayFromBank extends com.intersystems.enslib.pex.BusinessOperation {
public void OnTearDown() {}
public void OnInit(){}
// 确定适配器
public String getAdapterType() {
return "Finance.PEXOutboundAdapter";
}
// 响应请求消息
public java.lang.Object OnMessage(java.lang.Object object) throws java.lang.Exception {
// 将输入对象转换为对应的类实例.
TransactionRequest request = (TransactionRequest)object;
// 初始化StringBuffer对象,构造输出文件内容.
StringBuffer outputMessage = new StringBuffer();
// 将数据写入StringBuffer.
outputMessage.append("Debit request:" + System.lineSeparator());
outputMessage.append("Route:" + request.PayFrom.RoutingNumber + System.lineSeparator());
outputMessage.append("Account: " + request.PayFrom.AccountNumber + System.lineSeparator());
outputMessage.append("Amount: " + request.TransactionAmount);
// 调用出站适配器的方法,将数据写入文件.
Adapter.invoke("WriteToFile", outputMessage.toString());
// 实例化响应消息,并对响应消息赋值后返回给业务流程.
TransactionResponse response = new TransactionResponse();
response.approved = true;
return response;
}
}
2. 与接收银行接口的业务操作类:
package Finance;
import Finance.TransactionRequest;
import Finance.PaymentProfile;
import java.lang.StringBuffer;
// PEX业务操作类,和收款银行接口.
// 从业务流程接收请求消息,并将消息内容写入文件.
public class ToPayToBank extends com.intersystems.enslib.pex.BusinessOperation {
public void OnTearDown() {}
public void OnInit(){}
// 确定适配器
public String getAdapterType() {
return "Finance.PEXOutboundAdapter";
}
// 响应请求消息
public java.lang.Object OnMessage(java.lang.Object object) throws java.lang.Exception {
// 将输入对象转换为对应的消息类实例.
TransactionRequest request = (TransactionRequest)object;
// 实例化StringBuffer对象以构造文件内容.
StringBuffer outputMessage = new StringBuffer();
// 将数据写入StringBuffer.
outputMessage.append("credit request:" + System.lineSeparator());
outputMessage.append("SourceRouting:" + request.PayFrom.RoutingNumber + System.lineSeparator());
outputMessage.append("SourceAccount: " + request.PayFrom.AccountNumber + System.lineSeparator());
outputMessage.append("ToAccount: " + request.PayTo.AccountNumber + System.lineSeparator());
outputMessage.append("Amount: " + request.TransactionAmount);
// 调用出站适配器方法将数据写入文件
Adapter.invoke("WriteToFile", outputMessage.toString());
// 无需响应消息.
return null;
}
}
2.10 业务流程开发
使用Java开发业务流程,则完全是代码开发模式,而非基于BPL的低代码模式。
Java业务流程类是com.intersystems.enslib.pex.BusinessProcess 的子类,需要实现以下方法:
方法
参数
说明
OnInit
无
适配器初始化的方法
OnTearDown
无
适配器退出清理的方法
OnRequest
request 请求消息
处理发送给业务流程的请求消息,这个请求消息启动业务流程
OnResponse
request 请求消息,
response 响应消息,
callRequest - 本次异步调用发起的请求消息,
callResponse - 本次异步调用收到的响应消息,
completionKey - 异步调用发起时传入的completionKey
处理异步调用返回的响应消息-callResponse
OnComplete
request 请求消息,
response 响应消息
整个业务流程完成时,被调用的方法
另外,类里还可以声明需要在业务流程期间保存的持久化数据,和在BPL中要到的上下文(context)数据一样,例如记录汇出行的审核结果。声明时,需要加@Persistent这个Java annotation:
@Persistent
// 定义名为runningTotal的持久化的属性
public integer runningTotal = 0;
本用例的业务流程示例代码如下:
package Finance;
import Finance.TransactionRequest; //导入请求消息类
import Finance.TransactionResponse; //导入响应消息类
// 这是一个PEX业务流程类,它从业务服务(Finance.FromFileService)接收请求消息.
// 先将汇款请求消息发送给汇出行业务操作(Finance.ToPayFromBank) 并等待审核结果. 如果批准, 将请求消息发送给接收行业务操作(Finance.ToPayToBank).
public class ProcessPaymentRequest extends com.intersystems.enslib.pex.BusinessProcess {
public Object OnComplete(Object object,Object object2) {return null;}
public void OnTearDown(){}
public void OnInit(){}
// 无需返回响应消息给调用者
public java.lang.Object OnResponse(java.lang.Object request, java.lang.Object response, java.lang.Object callRequest, java.lang.Object callResponse, java.lang.String completionKey) throws java.lang.Exception {
return null;
}
// 处理请求消息
public java.lang.Object OnRequest(java.lang.Object object) throws java.lang.Exception {
// 将输入对象转换为对应的消息类实例.
TransactionRequest request = (Finance.TransactionRequest) object;
// 将支付请求消息以同步请求的方式发送给汇出行.
Object response = SendRequestSync("Finance.ToPayFromBank", request);
// 将收到的响应消息对象转换为对应的消息类实例.
TransactionResponse bankResponse = (TransactionResponse)response;
// 记录汇出行审核结果,用于调试
LOGINFO("汇出行审核结果是:"+bankResponse.approved);
// 检查汇出行审核结果,如果是批准,则将汇款请求发送给接收行.
if (bankResponse.approved) {
// 使用异步调用方式通知接收行,无需等待返回.
SendRequestAsync("Finance.ToPayToBank", request);
}
return null;
}
}
2.11 业务服务开发
Java业务服务类是com.intersystems.enslib.pex.BusinessService 的子类。它有一个父类定义的属性 – TargetComponentNames, 用于设置发送消息目标的下游业务组件名列表。可以同时发送消息给多个下游业务组件,组件名之间通过逗号分隔。
业务服务可以使用适配器,这时它会根据适配器的设置定期轮询外部系统,例如SQL适配器轮询外部SQL表、文件适配器轮询外部文件夹。但业务服务也可以不使用适配器,而直接被外部系统调用,例如发布为SOAP、RESTful服务的业务服务就不使用适配器。
适配器
执行过程
需要实现的方法
使用专业适配器
适配器的OnTask()方法定期执行获得数据,将数据发送给业务服务的ProcessInput()
OnProcessInput()
使用默认适配器
Ens.InboundAdapter
适配器的OnTask()方法定期执行,并调用业务服务的ProcessInput();
业务服务的OnProcessInput()执行数据获取
OnProcessInput()
不使用适配器
不定期执行,用户代码在需要时通过Director.CreateBusinessService() 创建业务服务,并执行其方法
OnProcessInput()
或其它需要的方法
本示例中的业务服务使用前面Java开发的文件入站适配器,其代码如下:
package Finance;
import java.io.File; // 导入File类.
import java.io.FileNotFoundException; // 导入此类以处理错误.
import java.util.Scanner; // 导入Scanner类读取文本文件.
import Finance.TransactionRequest; // 导入请求消息类.
// 这是一个PEX的业务服务类,从文件读取汇款请求. 将文件内容转换为Finance.TransactionRequest消息对象,并检查运行时变量TargetComponentNames,确定需要把请求消息发送给哪些业务组件.
public class FromFileTransaction extends com.intersystems.enslib.pex.BusinessService {
public String TargetComponentNames; // 用逗号分隔的发送目标组件列表,运行时从配置项获取.
public void OnTearDown() {}
public void OnInit() {}
// 确定适配器
public String getAdapterType() {
return "Finance.PEXInboundAdapter";
}
// OnProcessInput根据业务服务的'call interval' 设置会被定期调用.
public java.lang.Object OnProcessInput(java.lang.Object messageInput) throws java.lang.Exception {
String path = (String)messageInput;
File file = new File(path);
// 创建scanner对象读取文件.
Scanner reader = new Scanner(file);
// 实例化请求消息TransactionRequest对象.
TransactionRequest request = new TransactionRequest();
// 设置消息属性.
request.TransactionAmount = Float.parseFloat(reader.nextLine().split(":")[1]);
String tempString = reader.nextLine();
// 解析嵌套的PaymentProfile对象,并赋值给请求消息的PayFrom属性.
String[] tempStringArray = tempString.split(":");
String[] PaymentProfile = tempStringArray[1].split("\\|");
request.PayFrom.AccountNumber = Integer.parseInt(PaymentProfile[0]);
request.PayFrom.RoutingNumber = Integer.parseInt(PaymentProfile[1]);
request.PayFrom.UserName = PaymentProfile[2];
// 解析PaymentProfile对象,并赋值给PayTo属性.
tempString = reader.nextLine();
tempStringArray = tempString.split(":");
PaymentProfile = tempStringArray[1].split("\\|");
request.PayTo.AccountNumber = Integer.parseInt(PaymentProfile[0]);
request.PayTo.RoutingNumber = Integer.parseInt(PaymentProfile[1]);
// 设置剩余属性.
request.PayTo.UserName = PaymentProfile[2];
request.FromCurrency = reader.nextLine().split(":")[1];
request.ToCurrency = reader.nextLine().split(":")[1];
reader.close();
// 处理后删除文件.
file.delete();
// 获取Split target business component string and send to each component.
String[] targetNames = TargetComponentNames.split(",");
for (String name : targetNames){
SendRequestAsync(name, request);
}
return null;
}
}
2.12 组装互操作产品并进行测试
将这些Java开发的组件组册后,就可以像InterSystems IRIS的本地组件一样使用了。我们将业务操作、业务流程和业务服务依次加入到Production,并配置好相应的配置项:
对于每个业务操作,需要配置一项:
文件路径:输出的文件夹路径
对于业务服务,需要配置两项:
InboundFilePath: 监听的汇款请求文件夹路径
TargetComponentNames: 目标业务流程,这里应该填Finance.ProcessPaymentRequest
下面是用于测试的汇款请求文件内容,把它copy到一个文本文件中保存:
TransactionAmount:59.43
PayFrom:232422|23532532|TJohnson21
PayTo:24224242|423533453|ERichards55
FromCurrency:USD
ToCurrency:USD
启动Production后,可以将测试数据文件copy到业务服务监听到文件夹下。如果成功,应该可以看到这样的消息追踪结果,可以看到,用Java开发的PEX组件运行结果和IRIS自带的组件没有区别:
2.13 需要实现的Java类方法总结
下图总结了用Java开发不同组件时,需要实现的方法,以及这些组件间的调用流程和关系:
完整的规范参见这里。
三 在Java组件中使用Object Script开发的组件
上面是使用Java开发全套互操作产品组件的示例。实际情况下,InterSystems IRIS已经提供了大量适配器、消息和业务组件,而且使用低代码工具 - 例如业务流程建模图形化工具 - 往往更方便,所以通常Java可以使用Object Script开发的大量组件,而无需全部由Java开发。
在低代码开发业务流程时,可以直接在BPL里调用Java PEX开发的业务流程和业务操作,和IRIS本地开发的组件无异。
另外两种典型的用例是Java组件使用Object Script的消息、Java组件使用Object Script的适配器。在Java端使用Object Script类和对象,需要有前面讲的Java外部语言服务器的基础,文档参见这里。
3.1 Java组件使用Object Script的消息
在Java PEX中使用Object Script定义的消息,直接使用IRIS类的反向代理类IRISObject即可。例如在Java PEX业务操作的OnMessage方法中,要获得传入的Object Script消息的属性值,只需要把传入消息对象转换为IRISObject对象,并调用它的getXXX方法获取属性即可,可以这样:
@Override
public Object OnMessage(Object object) throws Exception {
// 处理类型Ens.StringRequest的ObjectScript消息,获取StringValue属性的值
// 使用ObjectScript消息,将Object转换为 IRISObject
IRISObject requestObj = (IRISObject)object;
通过IRISObject的getString方法获取它名为StringValue属性的值
String value = requestObj.getString("StringValue");
...
}
那怎么在Java组件中创建新的Object Script消息实例呢?你需要已经建立了IRIS连接的类型为com.intersystems.jdbc.IRIS的实例。
PEX的Java业务组件类和适配器类都继承于Common类,从Common类继承一个公共属性irisHandle,类型为IRISObject。而irisHandle有一个公共属性iris,类型为com.intersystems.jdbc.IRIS。因此可以通过它来创建Object Script消息实例。例如我们要创建一个类型为Ens.StringContainer的响应消息,并给其StringValue属性赋值:
@Override
public Object OnMessage(Object object) throws Exception {
// 处理类型Ens.StringRequest的ObjectScript消息,获取StringValue属性的值
// 使用ObjectScript消息,将Object转换为 IRISObject
IRISObject requestObj = (IRISObject)object;
String value = requestObj.getString("StringValue");
// 创建一个类型为Ens.StringContainer的ObjectScript响应消息
IRISObject response = (IRISObject)(this.irisHandle.iris.classMethodObject("Ens.StringContainer","%New"));
response.set("StringValue",value+"test me");
return response;
}
3.2 Java业务组件使用Object Script的适配器
如果Java业务服务使用Object Script的适配器,无需做任何处理,适配器会将数据发送给Java业务服务的OnProcessInput方法,而Java业务服务只需要将接收的数据转换为IRISObject类型进行处理即可。
如果是Java业务操作要使用Object Script适配器,则需要调用适配器的方法。调用适配器方法,可以使用Adapter属性的invoke方法调用适配器类的方法,语法是 Adapter.invoke("方法名", 方法参数),例如:
// 使用Object Script的出站文件适配器(EnsLib.File.OutboundAdapter),并调用它的Exists方法检查是否存在文件a.txt
Object obj = Adapter.invoke("Exists", "a.txt");
虽然这里介绍的是使用Java PEX开发互操作产品组件,您也可以使用.net 和Python进行开发,而且任何语言开发的PEX组件都可以一起使用。通过PEX,可以充分利用已有的生态代码和组件快速开发互操作产品。
文章
Hao Ma · 一月 15, 2021
介绍
目前,诸多应用程序通过开放授权框架(OAuth)来安全、可靠、高效地访问各种服务中的资源。InterSystems IRIS目前已兼容OAuth 2.0框架。事实上社区有一篇关于OAuth 2.0和InterSystems IRIS的精彩文章,链接如下。
然而,随着API管理工具的出现,一些组织开始将其用作单点身份验证,从而防止未经授权的请求到达下游服务,并将授权/身份验证复杂性从服务本身分离出来。
您可能知道,InterSystems已经推出了自己的API管理工具,即InterSystems API Management (IAM),以IRIS Enterprise license(IRIS Community版本不含此功能)的形式提供。这里是社区另一篇介绍InterSystems AIM的精华帖。
这是三篇系列文章中的第一篇,该系列文章将展示如何在OAuth 2.0标准下使用IAM简单地为IRIS中的未经验证的服务添加安全性。
第一部分将介绍OAuth 2.0相关背景,以及IRIS和IAM的初始定义和配置,以帮助读者理解确保服务安全的整个过程。
本系列文章的后续部分还将介绍两种使用IAM保护服务的可能的场景。在第一种场景中,IAM只验证传入请求中的访问令牌,如果验证成功,则将请求转发到后端。在第二种场景中,IAM将生成一个访问令牌(充当授权服务器)并对其进行验证。
因此,第二篇将详细讨论和展示场景1中的配置步骤,第三篇将讨论和演示场景2中的配置以及一些最终要考虑的因素。
如果您想试用IAM,请联系InterSystems销售代表。
OAuth 2.0背景
每个OAuth 2.0授权流程基本上都由4个部分组成:
用户
客户端
授权服务器
资源所有者
简单起见,本文使用“资源所有者密码凭证”OAuth流(可以在IAM中使用任何OAuth流)。另外,本文将不指定任何使用范围。
注意:因为资源所有者密码凭证流直接处理用户凭证,所以应该只在客户端应用程序高度受信任时使用。在大多数情况下,客户端应为第一方应用程序。
通常,资源所有者密码凭证流遵循以下步骤:
用户在客户端应用程序中输入凭证(如用户名和密码)
客户端应用程序将用户凭证和自身的标识(如客户端ID和客户端密钥)一起发送到授权服务器。授权服务器验证用户凭证和客户端标识,并返回访问令牌
客户端使用令牌访问资源服务器上的资源
资源服务器首先验证收到的访问令牌,然后再将信息返回给客户端
考虑到这种情况,你可以在两种场景下使用IAM应对OAuth 2.0:
IAM充当验证器,验证客户端应用程序提供的访问令牌,仅在访问令牌有效时才将请求转发给资源服务器;在这种情况下,访问令牌将由第三方授权服务器生成
IAM既充当授权服务器(向客户端提供访问令牌),又充当访问令牌验证器,在将请求重定向到资源服务器之前验证访问令牌。
IRIS和IAM初始定义和配置
本文中使用名为“/SampleService”的IRIS Web应用程序。从下面的截屏中可以看到,这是一个在IRIS中部署的未经身份验证的REST服务:
此外,在IAM端配置了一个名为“SampleIRISService”的服务,其包含一个路由,如以下截屏所示:
再者,在IAM中配置了一个名为“ClientApp”的客户端(初始没有任何凭据),用来识别谁在调用IAM中的API:
经上述配置,IAM将发送到以下URL的每个GET请求代理到IRIS:
http://iamhost:8000/event
此时还没有使用身份验证。所以,如果将一个简单的GET请求(未进行身份验证)发送到URL:
http://iamhost:8000/event/1
我们将获得期望的响应。
本文中,我们使用名为“PostMan”的应用程序发送请求并检查响应。在下面的PostMan截屏中,可以看到简单的GET请求及其响应。
请继续阅读本系列的第2篇,了解如何配置IAM来验证传入请求中的访问令牌。
文章
Hao Ma · 十一月 14, 2022
# ZPM介绍
有Developer听闻了InterSystems的包管理器ZPM, 希望我能介绍一下。正好刚刚看到一个开发者论坛的新闻:[ Open Exchange ZPM is now InterSystems Package Manager ](https://community.intersystems.com/post/zpm-now-intersystems-package-manager-ipm), 觉得更有必要了。
## zpm是什么
简单说:zpm, 全称InterSystems ObjectScript Package Manager, 是一个包管理器, 开发者是Nikolay Soloviev和Dmitry Maslennikov。它先是在开发者社区里得到认可,以至于InterSystems开发者社区最近的一些比赛,要求参赛作品用zpm打包。然后就有了上面的链接的内容:InterSystems决定把它做为自己官方的打包工具, 将它改名字叫IPM(InterSystems Package Manager),同时保持它的开源状况不变。
这里我还是用zpm称呼它。两个原因。1. 操作的命令还是zpm, 所谓ipm,只是官方给的名字。2. ipm新的注册中心还不太了解,而且**到目前为止,IPM的注册中心还只对自己的雇员和付费用户开放**。本文的读者应该都还没来得及付费,所以暂时先放放,还是叫它zpm。
考虑到没有程序员背景的读者而对包管理器不熟悉,啰嗦两句。
### 什么是包管理器
大多数开发工具都有自己的包管理器,Java开发使用MAVEN, Python用PIP, NodeJS使用npm, 它们细节有区别,功能大致是一致的,就是安装管理程序包,最基本的工作是:
1. 找到自己要的程序包。 简单的命令能让你在网上找到它,用名字找,或者其他方法搜索。
2. 安装包。
- 这里面最重要的是发现包之间的依赖。比如你要装一个软件包叫“包饺子”,作者在开发的时候使用了另一个软件叫“和面”,这个“和面”可能是作者自己写的,或者是网上其他人写的,注册在包管理器的。这时候作者在”包饺子“里声明,我依赖”和面“。 那么,当您去下载安装"包饺子“的时候,包管理器会自动的把”和面“也给你下载并安装上。
3. 管理包: 比如升级,删除等等。
### ZPM的特点
没有zpm的时候,人们是怎么传递ObjectScript代码的? 大概是这样:发布者把代码从studio导出成一个XML;接受者拿到这个xml, 然后使用Studio或者iris管理门户把它导入到一个命名空间。
这里面有两个问题:1. 麻烦, 2. 没有打包各种类型文件的能力。通常一个项目,除非是只使用ObjectScript, 多数都用到各种文件:前端的css, html, javascript, 图片; 各种配置文件xml或者yaml, 其他语言的包 (iris支持嵌入式python,以及集成多种编程语言工作)等等。
ZPM是怎么工作的?
1. 作者把自己的数据放在一个公网地址上,比如github; 使用zpm生成一个配置文件(module.xml); 把module.xml发布到zpm的registry, 让别人能找到你的软件包。
2. 使用者在Registry搜寻并下载这个程序包,zpm命令自动把它导入到IRIS的一个命名空间。
为什么能自动导入到iris ? 这里有个ZPM和其他包管理器的很大的区别: **ZPM命令是在IRIS的terminal里执行的, 而不是操作系统上。**
还有一个特点:**zpm的设计假设大家开发代码使用的IDE是VSCode而不是Studio**,这非常关键。Studio上的开发是在服务端的开发,没有一个类应该存在哪个文件目录的概念。VSCode相反,你创建一个类:`Demo.Web.Test`, 那么默认的文件保存是在一个这样的目录下: `./src/Dome/Web/Test.cls`
不遵循这样的目录结构,您要额外做很多手工的调整才能使用zpm保存加载程序包。
这里还有很多问题, 我们后面详细说。
## ZPM的下载安装
您可以从github上的InterSystems-Community用户的[zpm Repo](https://github.com/intersystems-community/zpm/wiki/01.-Getting-started)下载zpm-xxx.xml文件, 其中xxx是版本号, 当前(2022年10月)最新的版本是0.4.0。 把下载的xml文件导入到IRIS的**任何**命名空间。这样安装就成功了。
要下载安装软件的时候,您要先进入安装目标的命名空间(比如下面的USER),然后输入zpm, 也就进入了ZPM的操作界面: *ZPM Shell*
```sh
USER>zpm
=============================================================================
|| Welcome to the Package Manager Shell (ZPM). ||
|| Enter q/quit to exit the shell. Enter ?/help to view available commands ||
=============================================================================
zpm:USER>
```
输入help, 您可以看到帮助文件。(帮助文件很长, 我只贴一小段。)
```sh
zpm:USER>help -v
Available commands:
NOTE: [] around a parameter indicates it is optional
arrange [flags] []
■ Description: Rearranges the resources in a module manifest to follow the standard format
# 此处省略许多行
........
For more detail, run:
help
or
help -v
zpm:USER>
```
接着, 我相信您一定想看看安装命令是怎么执行的,比如这样:
```sh
zpm:USER>help install
install [flags] []
...此处省略若干行...
■ Examples
∙ install HS.JSON 1.x
Installs the most recent 1.x version of HS.JSON available in any configured repository in the current namespace.
zpm:USER>quit
USER>
```
好吧,让我们来下载一个最受欢迎的开发者应用“webTerminal”,了解最基本的zpm操作。
## 最基本的ZPM操作
### 搜索package
输入`zpm:USER>search`或者, 您可以使用`zpm:USER>search -r`,“-r"显示数据包所在的repo的位置。我没有贴在这里是因为显示的内容太宽了。在我的帖子的代码框里显示看上去有点乱。
```sh
zpm:USER>zpm:USER>search
registry https://pm.community.intersystems.com:
alwo-goselector 1.0.1
analytics-okr 1.0.0
...此处省略许多行...
zpm-shields 1.0.1
zpmhub 0.3.1
zpmshow 1.0.3
zpm:USER>
```
除了search, 还有个find命令。 它可以使用*,但无法忽略大小写。
```sh
zpm:USER>find *Webt*
registry https://pm.community.intersystems.com:
zpm:USER>find *webt*
registry https://pm.community.intersystems.com:
webterminal 4.9.6
zpm:USER>
```
### 安装package
```sh
zpm:USER>install webterminal
...(省略若干行)...
WebTerminal package successfully mapped into all namespaces.
[USER|webterminal] Compile SUCCESS
[USER|webterminal] Activate START
[USER|webterminal] Configure START
[USER|webterminal] Configure SUCCESS
[USER|webterminal] Activate SUCCESS
zpm:USER>
```
**到这里, 我来再次总结一下ZPM的最基本的功能:原本您想要使用一个其他开发者使用的程序,您要把它从某处,比如一个帖子,InterSystems的OpenExchange网站,或者一个github的主页上下载程序(XML文件),然后导入到IRIS执行。有了ZPM, 你可以在IRIS的terminal里通过ZPM命令,直接获得这个程序并执行。前提是:作者的程序是用ZPM打包并放在ZPM注册中心。**
来先了解一下ZMP的注册中心
## 注册中心(Registry)
默认安装下, zpm的注册中心是这样的
```sh
zpm:USER>repo -list
registry
Source: https://pm.community.intersystems.com
Enabled? Yes
Available? Yes
Use for Snapshots? Yes
Use for Prereleases? Yes
Is Read-Only? No
Deployment Enabled? No
zpm:USER>
```
这也是当前zpm唯一的一个注册中心(配置私服会在后面介绍), 组册的软件包是最近一些年社区开发者写的各种工具和示例代码。说一下它的当前状况:
- 当前能下载到278个软件包。
- 所有的包都放在了github。
- 包都很新。 这么说吧,release能到2.0的都是凤毛麟角
这里有个让人意外的事。我安装完webterminal并开始使用的时候,浏览器跳出这个提示。 “Welcome to WebTerminal! ...New update is available. ”。这说明这个registry并没有给出最新的webterminal版本。 我有点好奇,去看了一下webterminal的github page, 发现WebTerminal当前的版本是4.9.5。而zpm registry上下载的版本是4.9.2, 发行于2019年。
webterminal是一个前台工具,作者理所当然的的在代码里做了版本更新的检查并提醒了用户。而对于纯后台的ObjectScript语言的代码, 我估计大多数程序员都做不到这一点。 那么如果要保证其他人看到的是新版的软件, 就要求软件的作者,除了更新自己Github上的代码,还要把新版本及时更新在zpm的注册中心上。
文章太长了, 先贴一部分,后面会介绍
- 软件的发布
- 定义软件包的依赖
- 配置私服
*to be continued*
期待
文章
Qiao Peng · 十二月 2, 2022
1.数据的价值
数据的核心价值是帮助我们决策。
我们无时无刻不在决策,大到战略决策——为一家新医院选址,还有战术决策——鉴别产品的目标市场或抵押贷款审批,更频繁的是操作决策——决定患者的手术方案或患者药物的调整。
这些决策要求不同的决策速度,传统的数据中心已经能较好地帮助我们做战略决策、战术决策,甚至一些操作决策。但新的业务需求要求我们的决策速度越来越快,甚至借助机器学习自动为我们做出即时的决策,例如批准还是拒绝一笔信用卡交易或基于算法自动交易。
无论是人工决策还是基于机器学习的自动决策,决策的依据是数据。数据的速度和质量决定了决策的速度和质量。要支持决策,需要数据具有如下特征:
(1)完整 :关联且具有完整上下文;
(2)干净 :数据质量没有问题;
(3)及时 :在决策点上没有延迟。
传统数据中心很难在及时性上满足要求。
2.数据挑战
数字化浪潮下,我们面临更大的数据挑战:
数据规模:数据量已经完全超出了人工处理能力。
数据源多样性:数据源不再仅是数据库,流式引擎的消息、物联网、对象存储......它们还带来了越来越多模型种类的数据。
更多的数据孤岛:更多的系统和应用被建设,进一步增加了数据孤岛现象。
跨部门的数据不一致:统计口径和统计时间的差异,造成财务部门统计的数据,总是和业务部门统计的数据对不上。
数据服务对象变化:现在业务分析师、运营数据消费者、数据工程师、数据科学家和普通人群都是服务对象。
部署需求的多样性:传统本地部署、云部署、混合部署......
而由于技术、法律、经济性等原因,传统的数据集中保存无以为继......
数据库、数据仓库、数据湖,这些传统的数据管理技术应对这些需求和挑战,越来越力不从心。数据库能保持数据的热度(良好的数据存取速度),但支持的模型类型和数据来源有限;数据仓库要统一数据质量与格式(Schema on Write),缺乏灵活性;数据湖可以“以原始形态保存一切数据” (Schema on Read),但各种数据进入这样一个湖,全都变成了无法直接分析利用的冷数据!
应对之道 – 数据编织和智能数据编织
数据编织是正在兴起的数据管理技术以应对数据挑战,Gartner将其定为2022年12大战略技术趋势之首。
那什么是数据编织?
Gartner将数据编织定义为一种设计概念,可作为数据和连接流程的集成层(结构)。通过对现有、可发现和可推理的元数据资产进行持续分析,数据编织能够在所有环境(包括混合云和多云平台)中设计、部署和利用可重复使用的集成数据。
智能数据编织(Smart Data Fabric)则更进一步,在结构中直接嵌入各种分析能力,包括数据探索、商业智能、自然语言处理和机器学习,使企业可以更快、更容易地获得全新洞察,为智能预测和规范性服务及应用提供动力。
Gartner的这个名词解释还是有些抽象,如何理解它?为何数据编织/智能数据编织是解决上述挑战的利器? 如何利用现有的产品真实实现智能数据编织的落地?
InterSystems提供的智能数据编织解决方案
今天,智能数据编织(Smart Data Fabric)正被用于许多行业的实际生产中,为各种企业级、关键任务创新提供动力,包括场景规划和决策支持、法规遵从、实时可见性和警报等,作为全球领先的数据技术提供商,为应对当前数据挑战,特别通过InterSystems IRIS新一代数据平台提供智能数据编织解决方案,整合了许多关键特性和能力,以满足客户实施智能数据编织进行数字化转型的需求,该方案在解决数据挑战的同时,允许现有的遗留应用和数据保持原位,最大限度地利用以前的技术投资,包括现有的数据湖和数据仓库,而不需要“撕裂和替换”任何现有技术。
InterSystems IRIS数据编织解决方案把智能数据编织分为3个阶段:
数据互联互通阶段:有能力实时、双向打通各种数据源,将数据源有机编织在一起。
数据集成阶段:对数据本身进行编织,为多模型数据提供高性能存取和转换、加入数据安全控制、建立数据谱系、抽象为干净和统一的语义层供数据用户使用。
智能利用阶段:对建立了统一语义的数据提供紧贴数据的智能利用能力,例如商业智能分析、自然语言分析、机器学习,并使这些智能增强数据编织本身。
InterSystems IRIS数据平台在单一技术栈内提供智能数据编织的这些能力:互联互通、数据集成、自助服务、智能分析和多云 。
传统数据利用的是多级瀑布模式:数据从数据库到数据湖,再到数据中心,数据大批量、高延时地在异构数据平台间移动和拷贝。这是影响数据时效性、一致性的主要原因。所以InterSystems智能数据编织第一就要解决这个问题,而解决之道就是互联互通和数据集成。
1.互联互通
因为数据源和数据模型的多样性,传统的ETL在能力和时效性上都已不能满足需求,需要更完整的互联互通能力。长期以来,InterSystems是互操作技术的领导者,它提供各种适配器实时接入各种数据源,例如流式处理引擎Kafka,并对遗留系统进行现代化,即便有很多遗留系统作为数据源,依然可以通过它将其数据模型多态化和数据服务现代化。
2.数据集成
数据集成(Integration)不追求将数据放在一起,而是要建立数据间的准确关联,建立具有连续上下文的全息数据,甚至丰富数据。InterSystems提供:
(1)多模型
面对多元数据,Gartner表示,要想成功利用数据编织,企业必须确保数据编织能够动态地(通过元数据驱动设计)支持不同数据交付风格的组合,以支持特定的用例。
InterSystems的多模型数据建模和保存能力,让不同的数据以最适合的模型进行操作,它支持原生的对象、表、键值对和JSON文档。
(2)多语言
如何操作多模型的数据?每个数据用户都有熟悉或适合其用途的语言来使用数据,例如很多场景下,SQL是最简单的使用数据的语言。InterSystems让用户可以用SQL操作一切数据,哪怕它是以键值对建模和保存的。
(3)数据转换
不同的数据用户希望得到不同结构的数据。InterSystems提供图形化的高效数据转换工具,为用户构建干净的、单一可信的数据。
3.自助服务
如何发现、探索、推理数据编织平台中的数据?需要借助统一的语义和自助的服务能力。
(1)统一语义
为了数据完整性,无论是数据仓库还是数据湖,都将数据中心化存储。这造成了很多数据障碍:数据的时效性低、数据的质量参差不齐、数据需求严重依赖IT去清洗关联等等。
InterSystems的自适应分析是一个统一的、抽象的语义层,通过建立虚拟/逻辑数据分析立方体,用户可以使用SQL或BI工具访问这个语义层,而自适应分析自动使用SQL访问后台的多InterSystems IRIS数据平台实例获得数据和分析结果,不需要将数据集中保存到一起。
数据无需集中,因此无需ETL,没有数据抽取拷贝的时间成本开销,提供高时效性的数据;而抽象语义层将多数据源的数据建立逻辑关联,向用户提供干净、完整的语义上下文。
(2)行业语义级的数据编织
医疗健康行业面临相较其它行业更复杂的行业数据,在现实业务中要应对不同的语义表达。编织不同语义的数据源,将数据抽象为非标准语义,这会为后面的数据价值利用增加障碍。
FHIR建立统一行业语义的行业数据内容标准、利用标准行业术语和标识符、定义统一的传输标准、并逐步建立隐私和安全标准,让使用行业语义编织数据成为可能。
InterSystems支持所有FHIR的交互范式,提供FHIR服务器和FHIR资源仓库,并通过FHIR SQL构建器,建立基于SQL的FHIR数据访问能力,用最简单的数据操作支持BI/AI。通过FHIR来搭建具有统一行业语义和生态的数据编织平台。
(3)自助服务
长久以来,由于数据源和数据本身的复杂性,专业IT用户把持着数据的使用,商业用户极度依赖于专业用户才能获取、分析和利用数据。
借助统一语义层和对标准的支持,InterSystems让商业用户使用自己熟悉的工具和语言,例如SQL、BI工具和API来探索数据、操作数据和分析数据。
4.智能分析
为数据编织增加智能, InterSystems提供开放的智能分析能力。包括嵌入平台的机器学习、自然语言分析、商业智能特性,对第三方工具和生态的支持,以及对标准的支持——MDX、UIMA、PMML......
InterSystems提供全SQL操作方式的自动化机器学习,并允许使用第三方的自动化机器学习后台,如DataRobot,从而避免学习不同的API,用最简单的SQL就可以获得丰富的机器学习能力:
5.多云
数据编织平台要能支持所有主要的开发和部署环境,使开发人员和运营团队能够在他们选择的环境中工作。并与现有的基础设施和最佳技术无缝集成,支持最广泛的客户环境和应用要求。
公共云、私有云、本地、混合、裸机和虚拟机环境,InterSystems支持所有部署选项,且都只需要一个API,而不需要对你的应用程序进行修改。
6.单一技术栈而不建议不同产品和技术的堆砌与粘合
这一点至关重要。从整个数字化、信息化行业来看,信息部门尤其是最终用户的人员配置是远远不足的,从信息化部/科技部到我们的服务厂商,大部分从业人员工作负载基本都处在一个饱和甚至过饱和的状态,同时,IT从业人员由于薪酬激励的原因,大部分的中高端IT人才集中在少数行业或者少数头部厂商。针对这种情况,在数智底座的技术选择上,应该采取“少就是多”的策略,选择尽可能少的技术和产品种类,或者说一体化的技术架构,用一套技术体系来支持多种业务应用的实现,从而降低管理和学习成本。
另外一个原因,比如传统闭源厂商,很多软件产品都是收购或者是不同团队部门研发的,不同软件之间也需要集成或者胶水(参考文章:统一技术的高效数据架构能帮助客户节约大量成本)成本也是极其昂贵的。如果是选择开源技术栈,除了集成以外,还要考虑更多的比如技术路线的生命周期持久度,比如今天选择的技术会不会很快就过时了,技术支持如何延续?此外开源技术人员的成本普遍高于传统软件,人员流动也比较强,这也是企业选型必须考虑的问题。
总结
InterSystems的智能数据编织解决方案通过对数据源、数据的编织,避免多级瀑布式的大规模、高延迟的数据拷贝。构建抽象的统一语义层,并借助行业标准语义,建立基于标准的数据编织平台,为用户提供简单易用的数据探索和利用能力。利用全面的智能分析能力提升数据质量和数据价值,并降低数据利用的难度。多云的架构确保了对最广泛的客户环境和应用要求的支持,为数智底座的实施部署铺平了道路。
公告
Michael Lei · 六月 22, 2022
Hi 社区,
这是海外工程师做的一个纯浏览器的代码编辑器CloudStudio. 欢迎大家下载试用:
GitHub 下载:
https://github.com/SeanConnelly/CloudStudio
InterSystems 应用市场下载:https://openexchange.intersystems.com/package/CloudStudio
到Discord 讨论区:https://discord.gg/ZnvdMywsjP
Docker 支持与在线Demo:
要求
已安装 git 和 Docker desktop .
安装
Clone/git 把 repo 导入任何本地目录
git https://github.com/rcemper/Dataset-OEX-reviews.git
启动IRIS容器:
docker-compose up -d --build
如何测试
http://localhost:42773/cloudstudio/CloudStudio.Index.cls
或使用在线Demo
Demo 视频:https://www.youtube.com/watch?v=Am6QAvrPPPg
公告
Claire Zheng · 十一月 22, 2021
亲爱的社区开发者们,大家好!
现在参与Gartner Peer Insight同业评审对我们的产品做出评价,可获得价值 $25 美元的礼品卡。评论观点需中立客观(InterSystems员工不允许参加)并被Gartner审核通过。点击此处开始: https://gtnr.it/3ulVX4K 。
对流程不熟悉的同学,可以参考一下我们此前发布的一篇旧贴。
调研仅花费您很少时间,欢迎大家积极参与! 活动已经截止了。。。
问题
Botai Zhang · 四月 13, 2021
在使用过程中,碰到对接一些国内编码例如:GBK2312等系列的编码格式,碰到这类情况,应该如何处理?各位有没有好的解决方式?期待解答交流! 如果需要在InterSystems IRIS中对不同的编码的数据进行转换,可以使用函数$ZCVT。 例如将变量tStr的unicode值转换为GB2312:
s tOutput=$ZCVT(tStr,"O","GB2312") 感谢回复!这种方式尝试过,但是,$ZCVT并不支持GB2312。
用GB18030,它向后兼容GB2312
文章
YuHao Wan · 十一月 1, 2022
### 0. 算法概述
SM3密码杂凑算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准。该算法于2012年发布为密码行业标准(GM/T 0004-2012),2016年发布为国家密码杂凑算法标准(GB/T 32905-2016)。
SM3适用于商用密码应用中的数字签名和验证,是在[SHA-256]基础上改进实现的一种算法,其安全性和SHA-256相当。SM3和MD5的迭代过程类似,也采用Merkle-Damgard结构。消息分组长度为512位,摘要值长度为256位。
整个算法的执行过程可以概括成四个步骤:**消息填充、消息扩展、迭代压缩、输出结果**。
### 1. 消息填充
SM3的消息扩展步骤是以512位的数据分组作为输入的。因此,我们需要在一开始就把数据长度填充至512位的倍数。具体步骤如下:
1、先填充一个“1”,后面加上k个“0”。其中k是满足(n+1+k) mod 512 = 448的最小正整数。
2、追加64位的数据长度。

### 2. 消息分组扩展
将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)...B(n−1)
其中n=(l+k+65)/512。
SM3的迭代压缩步骤没有直接使用数据分组进行运算,而是使用这个步骤产生的132个消息字。(一个消息字的长度为32位/4个字节/8个16进制数字)概括来说,先将一个512位数据分组划分为16个消息字,并且作为生成的132个消息字的前16个。再用这16个消息字递推生成剩余的116个消息字。

### 3. 迭代压缩
SM3使用消息扩展得到的消息字进行迭代运算。

初值IV被放在A、B、C、D、E、F、G、H八个32位变量中,整个算法中最核心、也最复杂的地方就在于**压缩函数**。压缩函数将这八个变量进行64轮相同的计算。

### 4. 输出结果
将得到的A、B、C、D、E、F、G、H八个变量拼接输出,就是SM3算法的输出。

### 5. 附录


### 6. Caché实现
```
/// SM3密码杂凑算法是中国国家密码管理局2010年公布的中国商用密码杂凑算法标准
/// 该算法于2012年发布为密码行业标准(GM/T 0004-2012),2016年发布为国家密码杂凑算法标准(GB/T 32905-2016)。
/// 对长度为l(l < 2^64)比特的消息m,SM3杂凑算法经过填充和迭代压缩,生成杂凑值,杂凑值长度为256比特。
Class Utility.SM3 Extends %RegisteredObject
{
/// Creator: wyh
/// CreatDate: 2022-11-01
/// Description:SM3加密
/// Input: msg:原文
/// Output: 16进制密文
/// Debug: w ##class(Utility.SM3).Hashsm3("{""appId"":""60C90F3B796B41878B8D9C393E2B6329"",""nonceStr"":""1234567890"",""timestamp"":""60C90F3B796B41878B8D9C393E2B6329"",""version"":""V2.0.0""}F2D8D966CD3D47788449C19D5EF2081B")
ClassMethod Hashsm3(msg)
{
#; 初始值IV =7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e
s V(0) = "01110011100000000001011001101111 01001001000101001011001010111001 00010111001001000100001011010111 11011010100010100000011000000000 10101001011011110011000010111100 00010110001100010011100010101010 11100011100011011110111001001101 10110000111110110000111001001110"
#; 1. 消息填充
s m = ..s2m(msg)
#; 2. 消息分组
#; 将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)...B(n−1)
#; 其中n=(l+k+65)/512。
s n = $l(m)/512
f i = 0 : 1 : n-1 d
.s B(i) = $e(m, 512 * i + 1, 512 * (i + 1))
#; 3. 迭代压缩
#; 对m′按下列方式迭代:
#; FOR i=0 TO n-1
#; V(i+1) = CF(V(i),B(i))
#; ENDFOR
#; 其中CF是压缩函数,V(0)为256比特初始值IV,B(i)为填充后的消息分组,迭代压缩的结果为V(n)。
.s V(i+1) = ..CF(V(i) ,B(i))
#; 4. 杂凑输出
#; ABCDEFGH = V(n)
#; 输出256比特的杂凑值y = ABCDEFGH。
s rtn = ""
f i = 1 : 1 : 8 d
.s bit = $p(V(n), " ", i)
.s num = ..bs2n(bit)
.s hex = $ZHEX(num)
.i $l(hex) < 8 d
..f j = 1 : 1 : 8 - $l(hex) d
...s hex = "0" _ hex
.s rtn = rtn _ hex
s rtn = $zcvt(rtn, "L")
return rtn
}
/// 1. 消息填充
/// 将填充后的消息m′按512比特进行分组:m′ = B(0)B(1)...B(n−1)
/// 其中n=(l+k+65)/512
ClassMethod s2m(msg)
{
s len = $l(msg)
s r = ""
f i = 1 : 1 : len d
.s num = $ascii($e(msg, i))
.s bs = ..n2bs(num)
.s r = r _ bs
s rtn = r
s rtn = rtn _ "1"
s k = 512 - (64 + ($l(r) + 1)) # 512
f i = 1 : 1 : k d
.s rtn = rtn _ "0"
s lenbs = ..n2bs($l(r))
s t = 64 - $l(lenbs)
f i = 1 : 1 : t d
.s rtn = rtn _ "0"
s rtn = rtn _ lenbs
return rtn
}
/// 3. 迭代压缩
/// 令A,B,C,D,E,F,G,H为字寄存器,SS1,SS2,TT1,TT2为中间变量,压缩函数V(i+1) = CF(V(i),B(i)), 0
文章
Hao Ma · 十一月 22, 2023
介绍
由于InterSystems最近宣布从2023.2版本开始停止对InterSystems Studio的支持,转而独家开发Visual Studio Code(VSC)IDE的扩展,相信后者比Studio提供了更优越的体验,我们很多开发者都已切换或开始使用 VSC。很多人可能想知道如何打开终端进行操作,因为VSC没有像Studio那样的输出面板,也没有集成的功能来打开IRIS终端,除非下载InterSystems开发的插件。
概括
介绍
解决方案
对于至少具有 IRIS 2020.1 或 IRIS IRIS 2021.1.2 的用户– 使用 Web 终端
对于至少具有 IRIS 2023.2 的用户 – 使用 WebSocket 终端
对于使用基于 Docker 的 IRIS 的用户
对于在本地计算机上使用 2023.2 之前的 IRIS 版本的用户
对于使用 SSH 连接在基于远程服务器的 IRIS 上进行编码的用户
解决方案
在 VSC 中打开终端的方法有多种,具体取决于您使用的具体配置,我在这里总结了适合任何情况的最佳解决方案:
对于至少具有 IRIS 2020.1.1 或 IRIS 2021.1.2 的用户 – 使用 Web 终端
至少拥有 IRIS 2020.1.1 或 IRIS 2021.1.2 且被允许安装外部扩展的用户(某些人可能由于公司有关第三方应用程序的政策而不允许安装),可能会发现 VSC 的 Web 终端扩展很有用。谁不知道, Web 终端是一个基于 Web 的 InterSystems 产品终端,使用 ObjectScript(例如 IRIS、Caché、Ensemble、HealthShare、TrakCare)构建,允许在浏览器中使用更高级版本的终端( 这里是项目页面)。通过此 VSC 扩展,只需单击一下即可直接从 VSC 启动基于 Web 的终端。
要打开 Web 终端,请单击: InterSystems Tools > 选择一个名称空间 > 单击以下图标之一 ( , )在 VSC 终端面板或浏览器上打开 Web 终端(按 Alt 更改默认图标):
对于至少具有 IRIS 2023.2 的用户 – 使用 WebSocket 终端
至少拥有 IRIS 2023.2 的用户可以利用最新版本的 VSC 扩展中包含的新“ WebSocket 终端”功能,并且不需要其他解决方法。
要打开 WebSocket 终端,请单击: InterSystems Tools > 选择一个名称空间 > 单击 Web 终端旁边的图标。
对于使用基于 Docker 的 IRIS 的用户
在 Docker 中使用 IRIS 环境并使用 VSC 的人员可以直接在 Docker 环境中启动终端会话。
单击状态栏中的 Docker 语音,然后选择Open Terminal in Docker 。
我要感谢@Evgeny.Shvarov 有关这一点的图片和解释。
对于在本地计算机上使用 2023.2 之前的 IRIS 版本的用户
对于使用在本地计算机上运行的 IRIS 版本的用户,可以在 VSC 中设置专用的 IRIS 终端:
打开设置.json 文件。您可以通过多种方式找到它,例如单击“视图”> “命令面板”> 输入:“设置”>打开用户设置 (JSON)
在“ terminal.integrated.profiles.windows ”下添加以下代码:
"terminal.integrated.profiles.windows" :{ "IRIS Terminal" : { "path" : [ "C:\\InterSystems\\IRISHealth\\bin\\irissession.exe" ], "args" : [ "IRISHEALTH" ], "icon" : "terminal-cmd" } }
注意:插入irissession.exe的正确路径。
C。要从 VSC 打开终端,请导航至:终端>新终端>启动配置文件... > IRIS 终端。
d.终端菜单中现在应该可以使用“IRIS Terminal”语音:
对于使用 SSH 连接在基于远程服务器的 IRIS 上进行编码的用户
对于使用基于可通过 SSH 连接(例如使用PuTTY )访问的远程服务器(例如公司服务器)的 IRIS 版本的人员来说,可以使用远程 - SSH VSC扩展将 VSC 直接连接到服务器。为此:
安装远程 - SSH:编辑配置文件 VSC 扩展;
单击“远程资源管理器”图标 在侧边栏中;
选择“打开 SSH 配置文件”
并打开配置文件,路径为: C:\Users\<用户名>\.ssh\config
在配置文件中插入以下代码:
Host my-putty-connection HostName < IP address or server name > User < username > IdentityFile < private key path on your local machine > Port < port >
IP 地址和端口对应于 PuTTY 中指定的主机名和端口,用户名是用于访问远程服务器的用户凭据,IdentityFile 是 PuTTY 私钥的文件路径。
注意:VSC 无法读取 PuTTY (.ppk) 生成的私钥的原始格式。要通过 PuTTY 在 VSC 和远程服务器之间建立连接,您必须复制原始私钥并将新版本转换为 .pem 格式。为了进行转换:
启动 PuTTYgen 应用程序
在“文件”菜单下,单击“加载私钥”
选择 .ppk 格式的私钥,然后选择“打开”
在“转换”菜单下,单击“导出 OpenSSH 密钥”(强制使用新文件格式)。
设置扩展名为 .pem 的新名称,然后单击“保存”按钮。
将此新 .pem 文件的路径链接到 VSC 中的IdentifyFile 参数
保存文件。几秒钟后,新连接应出现在“远程资源管理器”面板中;
单击“在新窗口中连接... ”以在新的 VSC 窗口中打开 SSH 连接:
选择远程计算机的操作系统(仅在第一次访问时)
在新窗口中,导航至:终端>新终端(或使用快捷键 Ctrl + ò 或 Ctrl + Shift + ò)。
您现在已连接到远程计算机,并且可以在 VSC 中使用其 IRIS 终端。
注意:此操作仅在您之前通过 PuTTY 启动远程连接时有效,并且在 PuTTY 关闭或未连接到远程服务器时不起作用。此操作不会启动 PuTTY,它仅允许 VSC 连接到 PuTTY 建立的隧道。
要通过 VSC 启动 PuTTY 连接,您可以使用批处理文件(在 Windows 上)。提供的connect_remote.bat文件使用 PuTTY 附带的 Plink 命令来启动会话:
@echo off set SESSION="<your saved session name>" plink -load %SESSION%
要启动会话,只需在 VSC 终端中键入.\connect_remote.bat以打开远程连接并插入您的凭据。
注意:后一种方法使您可以访问支持所有 VSC 快捷方式的终端版本!欢迎回来 Ctrl+V,再见 Shift+Insert 🎉 @Hao.Ma Thank you for translating my article. I hope you liked it 🙂
公告
Michael Lei · 一月 9, 2022
a {color:#2a2e78;}
嘿,社区。 这里是2021年度开发社区问题摘要。 让我们来看看InterSystems开发人员提出的最受欢迎的问题。
统计
✓ 2021年提出了980 个问题✓ 社区总共提出了5,699 问题
最多浏览问题
WINDOWS ODBC CACHE 驱动 by Fernando Zañartu
2,113
SOAP 错误 CONTENT-TYPE 返回 text/html 而不是 text/xml by Kurro Lopez
741
如何用xmlns 和 xsi:type 属性解析xml by water huang
733
ODBC 驱动 by Brian Bechard
667
VS Code中的意外Token错误 by David Hockenbroch
646
Log4j 脆弱性 by JOSE PALAU
597
如何在SQL查询中获得行编号? by Anderson Negreli
541
httpRequest POST 文件上传by Emanuel Lazar
527
Log4Shell Apache 影响 / Intersystems产品by Andy Stobirski
486
Intersystems Cache Studio 下载 by Joseph Lovato
461
如何在httpResponse对象中设置HTTP Response 状态编码 by Mike Yackanich
441
JSON解析空值null values in by Lucas Macori
398
如何快速简单从老的Dot Scoping转化为新的Parentleses Scoping? by Dominic Chui
397
从Caché 数据库到 IRIS数据库的转化. by Сергей Марушко
383
JSON Web Token令牌 授权与不记名令牌Tokensby Neil Thaiss
371
在另一个命名空间中调用类的方法 by Nigel Salm
371
超出License 限制? by yeung elijah
364
锁 /解锁 by Matjaz Murko
352
JWT/OAuth2.0 by M C
344
转化 ISO-8859-1 输入文件 by Michoel Reach
332
显示所有英文社区问题 »
显示所有中文社区问题 »
讨论最多的
Debugging功能不见了 by Anna Golitsyna
24
在 %SYS 命名空间外获得用户属性 by Evgenii Ermolaev
22
从 VS studio终端运行Python脚本 by Akshay Pandey
20
VS Code中的意外Token错误 by David Hockenbroch
20
JSON对象上的SQL 搜索索引. by Güvenal
20
锁 /解锁 by Matjaz Murko
19
IRIS - 原生 API 和 .NET Provider - 回归到 Cache .net Provider ?by Emanuel Lazar
18
&sql(.....) 不工作且返回SQLCODE -400 by prashanth ponugoti
18
修改 %Stream 内容 by Marlin Mixon
17
收到错误 #9406 by Rick Prichett
16
在VSCode转化 ObjectScript格式 by Julian Matthews
16
从Caché 数据库到 IRIS数据库的转化. by Сергей Марушко
15
Ensemble用SQL批量插入 by Jimmy Christian
14
#5003 没有实施by Gary Koester
14
动态 SQL 参数化 UPDATE vs INSERT的问题 by Jonathan Anglin
14
如何区分命名空间 Globals 和 Routines 数据库 ? by Muhammad Waseem
14
如何测试从虚拟文档到FLR的转化 by Werner Beukes
14
第一个REST 操作 - 定制Header by Scott Roth
14
vscode 新 routines 没有显示 by Paul Price
14
显示 %GlobalCharacterStream by Rochdi Badis
13
显示所有英文社区问题 »
显示所有中文社区问题 »
文章
Weiwei Gu · 八月 14, 2023
在提交的 WRC case中(Intersystems 全球技术支持响应中心),我们经常看到客户提出有关新 Web 网关设置的问题,其中管理门户加载一半,但不显示图像。本文将解释为什么会出现此错误,以及如何修复它。本说明主要针对服务 InterSystems IRIS 实例的 Web 网关,但相同的说明也应适用于服务 Caché 实例的 CSP 网关。
问题:
您刚刚在独立的 Web 服务器上安装了 Web Gateway。当你去加载管理门户时,你发现它无法显示或加载图像,如下所示:
为什么会发生这种情况:
问题是,为了完整加载管理门户,InterSystems IRIS 必须加载许多 .js、.css 和 .png 文件(静态文件)。如果您看到像上面这样的管理门户页面,请随时打开浏览器的开发人员工具小程序,导航到“网络”选项卡,并确认未提供各种 .js、.css 和 .png 组件:
最初安装 Web Gateway 时,我们仅为以下扩展设置映射:
.csp .cls .zen .cxw
这些是客户在自己的自定义应用程序中最常使用的文件扩展名类型,以及用于为 Web Gateway 管理门户提供服务的 .cxw 扩展名。如果您想要加载其他管理门户组件,则必须注册其他文件类型以由 Web 网关提供服务。
如何解决该问题:
要使管理门户完全显示,您必须配置 Web 网关以提供其他文件类型。对于 IIS,您可以为 .js、.png、.css 等扩展名添加单独的映射,也可以添加通配符映射。可以在此处找到有关注册 IIS 的其他文件类型的文档:https: //docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls ?KEY=GCGI_win#GCGI_registering
如果您在 Unix / Linux 系统上的 Apache 之上运行 Web Gateway,您有几个选择。您可以通过添加其他文件扩展名(如 IIS 上的情况)来配置此功能,也可以添加 CSP 位置指令。请参阅此处的文档了解完整详细信息: https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls ?KEY=GCGI_ux,位于“使用 CSP 注册其他文件类型”下
文章
姚 鑫 · 五月 2, 2021
# 第一章 简介global
InterSystems IRIS®的核心功能之一是其多维存储引擎。此功能允许应用程序以紧凑、高效的多维稀疏数组存储数据。这些数组称为全局数组。
本章介绍:
- 什么是全局变量(`globals` ),以及可以对其执行的操作。
- 全局变量的逻辑和物理结构,包括在分布式数据库体系结构中使用全局变量。
- 如何使用全局变量在应用程序中存储和检索数据。
- 如何使用全局变量。
# 特点
全局变量提供了一种在持久的多维数组中存储数据的易于使用的方法。
例如,可以使用名为`^Settings`的全局变量将值`“Red”`与键`“Color”`相关联:
```java
SET ^Settings("Color")="Red"
```
可以利用全局变量的多维特性来定义更复杂的结构:
```java
SET ^Settings("Auto1","Properties","Color") = "Red"
SET ^Settings("Auto1","Properties","Model") = "SUV"
SET ^Settings("Auto2","Owner") = "Mo"
SET ^Settings("Auto2","Properties","Color") = "Green"
```
全局变量具有以下功能:
- 简单易用-全局变量和其他编程语言变量一样易于使用。
- 多维-可以使用任意数量的下标指定全局内节点的地址。
例如,在 `^Settings("Auto2","Properties","Color")`中,下标`Color`是全局设置中的第三级节点。
下标可以是整数、数字或字符串值,并且不需要是连续的。
- 稀疏-用于寻址全局节点的下标高度压缩,不需要连续的值。
- 高效-全局变量上的操作(插入、更新、删除、遍历和检索)都经过高度优化,可实现最高性能和并发性。还有用于特殊操作(如批量插入数据)的其他命令。有一组特殊的全局变量是为临时数据结构设计的(例如,用于对记录进行排序)。
- 可靠-InterSystems IRIS数据库提供了许多机制来确保存储在全局数据库中的数据的可靠性,包括逻辑级和物理级日志记录。执行数据库备份操作时,将备份存储在全局数据库中的数据。
- 分布式IRIS提供了多种方法来控制存储在全局数据库中的数据的物理位置。可以定义用于存储全局的物理数据库,或将全局的部分分布到多个数据库中。使用InterSystems IRIS的分布式数据库功能,可以在数据库和应用程序服务器系统网络中共享全局数据。此外,通过镜像技术,存储在一个系统上的全局数据库中的数据可以自动复制到另一个系统上。
- **并发-全局支持多个进程之间的并发访问。在单个节点(数组元素)中设置和检索值始终是原子的:不需要锁定即可保证可靠的并发访问。此外,InterSystems IRIS支持一组强大的锁定操作,可用于为涉及多个节点的更复杂情况提供并发性。使用对象或SQL访问时,会自动处理此并发。**
- **事务性-InterSystems IRIS提供定义事务边界的命令;可以启动、提交或回滚事务。在回滚的情况下,事务内对全局变量所做的所有修改都将被撤消;数据库的内容将恢复到事务前的状态。通过将各种InterSystems IRIS锁定操作与事务结合使用,可以使用全局变量执行传统的`ACID`事务。(`ACID`事务提供原子性、一致性、隔离性和持久性。)。使用对象或SQL访问时,事务会自动处理。**
注意:本文档中描述的全局变量不应与另一种类型的InterSystems IRIS数组变量混淆:进程私有全局变量。进程私有全局变量不是持久的;它们仅在创建它们程序期间持续。进程私有全局变量也不是并发的;它们只能由创建它们的进程访问。进程专用全局可以通过其多字符名称前缀:`^||`或`^|"^"|`轻松地与全局区分开来。
# 例如
一个简单的例子就可以展示全局变量的易用性和性能。下面的程序示例创建一个`10,000`个节点的数组(如果存在,则首先将其删除)并将其存储在数据库中。可以尝试这样做,以了解全局变量的性能:
```java
/// w ##class(PHA.TEST.Global).GlobalSimple()
ClassMethod GlobalSimple()
{
Set start = $ZH // get current time
Kill ^Test.Global
For i = 1:1:10000 {
Set ^Test.Global(i) = i
}
Set elap = $ZH - start // get elapsed time
Write "Time (seconds): ",elap
q ""
}
```
```java
DHC-APP> w ##class(PHA.TEST.Global).GlobalSimple()
Time (seconds): .00307
```
我们还可以看到迭代和读取数组中的值需要多长时间(确保首先运行上面的示例来构建数组):
-读取持久数组-
```java
/// w ##class(PHA.TEST.Global).ReadGlobalSimple()
ClassMethod ReadGlobalSimple()
{
Set start = $ZH // get current time
Set total = 0
Set count = 0
// get key and value for first node
Set i = $Order(^Test.Global(""),1,data)
While (i '= "") {
Set count = count + 1
Set total = total + data
// get key and value for next node
Set i = $Order(^Test.Global(i),1,data)
}
Set elap = $ZH - start // get elapsed time
Write "Nodes: ",count,!
Write "Total: ",total,!
Write "Time (seconds): ",elap,!
q ""
}
```
```java
DHC-APP>w ##class(PHA.TEST.Global).ReadGlobalSimple()
Nodes: 10000
Total: 50005000
Time (seconds): .001879
```
# 在应用程序中使用
在InterSystems IRIS应用程序中,全局变量有多种使用方式,包括:
- 作为对象和SQL引擎共享的底层存储机制。
- 作为用于为对象和SQL数据提供各种索引(包括位图索引)的机制。
- 作为用于执行不适合进程存储器的某些操作的工作空间。例如,当没有预先存在的索引可用于排序数据时,SQL引擎使用临时全局变量对数据进行排序。
- 用于在对象或SQL访问方面难以表达或效率低下的持久性对象或SQL表上执行专用操作。例如,可以定义一个方法(或存储过程或Web方法)来对表中保存的数据执行专门的分析。通过使用方法,这样的操作是完全封装的;调用者只需调用该方法。
- 实现特定于应用程序的自定义存储结构。许多应用程序需要存储难以用关系表示的数据。使用全局变量,可以定义自定义结构,并通过对象方法将其提供给外部客户端。
- 用于InterSystems IRIS系统使用的各种特殊用途的数据结构,例如配置数据、类定义、错误消息和可执行代码。
全局变量不受关系模型的限制。
它们提供了开发针对特定应用程序优化的定制结构的自由。
对于许多应用程序来说,明智地使用全局变量可能是提供性能的秘密武器,而这种性能是关系应用程序开发人员梦寐以求的。
无论应用程序是否直接使用全局变量,了解它们的操作都是有用的。
理解全局及其功能将帮助设计更高效的应用程序,并为确定应用程序的最佳部署配置提供帮助。
文章
Jingwei Wang · 九月 22, 2021
为什么要连接系统?
连接系统可以让一个系统处理来自非本系统的信息。例如,以下场景需要连接系统:
为了提高效率,最初设计为执行单一功能的系统需要集成。例如,您可以通过集成跟踪库存、订购材料、记录销售和控制运输的各个系统来提高效率。
系统合并后,在不同机构中执行相同功能的系统需要协同工作才能使统一的机构有效。
将系统连接在一起时,您可能会面临一些挑战,例如:
不同系统使用不同的通信协议:一个系统可能使用TCP,另一个系统使用SOAP,第三个系统使用REST。
不同系统使用不同格式或基于不同标准的不同消息。
需要保证消息成功传递到正确的系统,并能够检测和纠正故障。
必须监控传输消息的系统,如果一次消息过多,则为消息提供一个队列,并监控整体系统性能以确保没有任何障碍。
虽然可以编写自定义应用程序来连接系统,但开发一款InterSystems IRIS® 产品要容易得多,也快得多。
InterSystems IRIS 提供了一个框架,允许连接系统,并最大限度地减少或消除对自定义代码的需求。
Production介绍
InterSystems IRIS Production是一个集成框架,用于轻松连接系统和开发互操作性应用程序。产品Production提供包含各种消息格式和通信协议的内置连接。您可以轻松添加其他格式和协议,并通过编写代码或使用图形向导定义业务逻辑和消息转换。产品提供消息的持久存储,允许跟踪消息的路径并审核消息是否成功传递。一个Production由业务服务(BS)、业务流程(BP)和业务操作(BO)组成:
业务服务(BS)与外部系统连接并接收Production来自外部系统的消息。
业务流程(BP)允许您定义业务逻辑,包括路由和消息转换。
业务操作(BO)与外部系统连接并将消息发送给它们。
将系统连接在一起时,让所有系统互相理解它们的消息和文档是有挑战性的。例如,思考以下问题:
您有两个独立的系统:一个是从多个联网设备采集数据,另一个是跟踪损坏的设备和维修进程的工单系统。
当前程序依赖于人工干预来监控设备并启动维修进程。这导致了拖延情况且不可靠。
您的任务是将两个系统连接在一起:监控正在收集的数据并自动启动修复进程。您知道如何检测数据收集系统中的故障设备并知道如何启动维修,尽管两个系统所存储的数据代表同一项目,但是两个系统的存储数据格式并不兼容。
您还需要记录数据收集系统启动维修时的操作。
可以使用InterSystems IRIS 产品解决这个问题。它提供了一个定义接口的框架,该接口接收来自数据采集系统的消息,将消息转换为维修系统可以理解的消息,然后将消息发送到维修系统。它还存储消息路径。
下面以一个简单的Production作为示例
出于演示目的,本文档中的Production使用文件适配器(file adapter)并将外部系统表示为文件。由于处理外部系统的大部分工作是由InterSystems IRIS 提供的适配器完成的,因此开发一款可以连接到含有 REST、TCP、SOAP 或HTTP 的外部系统的Production的过程与使用文件适配器开发产品非常相似。
使用文件适配器(File Adaptor)创建Production
在本节中,您将使用入站文件适配器和出站文件适配器创建Production。可以使用 InterSystems IRIS 中内置的业务服务(BS)、业务流程(BP)和业务操作(BO),因此您无需下载任何代码。
尝试一下!使用文件适配器创建产品
想要尝试一下InterSystems IRIS 互操作性功能的在线视频演示吗?查看互操作行快速入门!
用前须知
要使用该程序,您需要一个正在运行的InterSystems IRIS 实例。您的选择包括多种类型的已授权的和免费的评估实例;该实例不需要由您正在工作的系统托管(尽管它们必须相互具有网络访问权限)。如果您还没有一个可以使用的实例,如何部署每种类型实例的有关信息,请参阅InterSystems IRIS Basics: Connecting an IDE中的部署 InterSystems IRIS。
关于如何用Visual Studio 连接到您的InterSystems IRIS 实例,请参考InterSystems IRIS 连接信息和.Net IDEs。
创建支持互操作的命名空间(Namespace)
为了创建一个production,必须有支持互操作的命名空间。如果您已经创建了启用互操作的命名空间, 则可以将其用于该production。要创建新的支持互操作的命名空间,请遵照以下流程(首次安装InterSystems IRIS 时
创建的命名空间不支持互操作):
在浏览器中为实例打开Management Portal (管理门户)。
选择系统管理 > 配置 > 系统配置 > 命名空间,进入命名空间页面。
在命名空间页面,选择新建命名空间 ;根据系统配置指南中“配置InterSystems IRIS”一章中,对于“Create/Modify a Namespace(创建/修改命名空间)”说明,确保选中
Enable namespace for interoperability productions(为互操作性产品启用命名空间)复选框。
点击靠近页面顶部的保存按键,然后在结果日志的结尾选择关闭。
创建含有业务服务 (BS)和业务操作(BO)的简单production
在这一步中,您将:
创建一个新的production。
在该production中添加一项业务服务(BS)和两项业务操作(BO)。
配置业务服务(BS)和业务操作(BO)。
现在,您应该创建在托管InterSystems IRIS实例的系统上运行此production所需的四个目录。具体处理方法取决于所用的实例类型,如下所示:
对于ICM 部署的实例,使用带有-machine 和-interactive 选项的 icmexec命令,打开正在运行该实例的容器的bash shell ,例如:
icm exec -command bash -machine MYIRIS-AM-TEST-0004 -interactive
然后,您可以在容器文件系统上创建目录。
对于任何容器化实例,无论是授权版还是社区版,请使用 docker exec -it container_name bash 命令打开该容器的bash shell (社区版的容器名称是try-iris )。然后在容器文件系统上创建4个目录
对于InterSystems Learning Labs(学习实验室),在集成IDE中使用命令行终端,在共享文件夹下创建新文件夹;您可以在/home/project/shared 路径下的Management Portal(管理门户)中浏览这些文件夹。
对于已安装的实例,在本地文件系统上创建4个目录。
本文本假定以下是Windows 系统上已安装实例的目录路径;替换您创建的实际目录的路径。
c:\Practice\In
c:\Practice\Out
c:\Practice\PDFsOut
c:\Practice\Work
在管理门户中,创建一个新的production:
选择Interoperability( 互操作性),如果出现提示,请选择一个支持互操作的命名空间。
选择Interoperability ( 互操作性)> 列表 > Production。
如果一个产品当前正在命名空间中运行,请打开它,然后选择停止。返回产品列表页面。
选择新建,创建一个新的产品。
指定包名称(例如 TEST)和production名称(例如 FileProd)。您将创建可用于任何目的的通用production。选择OK创建该产品。
向该产品添加一项业务服务(BS)和两项业务操作(BO):
选择服务旁边的加号符号以显示业务服务向导。
在服务类下拉菜单,选择EnsLib.File.PassthroughService 。
指定服务名FileService。
清空立即启用复选框。
选择确定。
对两项业务操作(BO)重复这些步骤。从选择操作旁边的 加号符号以显示业务操作向导开始。对这两项操作使用 EnsLib.File.Pa ssthroughOperation 类。将一项操作名称命名为WriteFileOp ,另一项命名为WritePDFsOp。
配置这项业务服务(BS)和两项业务操作(BO):
选择您在产品配置图中创建的业务服务(BS),并在设置选项卡:
a. 选择启用复选框。
在文件路径字段,输入c:\Practice\In。
在存档路径字段,输入c:\Practice\Work。
在工作路径字段,输入c:\Practice\Work。
在接收消息的目标名称字段,选择WriteFileOp。
其他字段为默认值。
选择应用。
为两项业务操作(BO)中的每一项指定设置。选择产品图中的操作,然后:
a. 选择启用复选框。
在文件路径字段,对于 WriteFileOp 操作输入c:\Practice\Out,对于 WritePDFsOp 操作输入 c:\Practice\PDFsOut。
其他字段为默认值。
选择应用。
启动Production & 跟踪消息
启动该production后,您将复制一个文件到 FileService 的导入目录。您能查看 WriteFileOp 的导出目录中的文件,并通过该production跟踪消息。请注意,运行这个production时不使用WritePDFsOp 操作。要启动production并跟踪消息:
通过选择开始启动产品。
将任一文件复制到c:\Practice\In 目录。如果该产品配置正确,应该会出现以下情况:
几秒钟后,文件从 c:\Practice\In 目录移动到 c:\Practice\Work 目录。文件名称规范将后附时间戳。例如, 如果原始文件是hello.txt,工作文件可能名称为hello.txt_2018-05-07_17.24.57.056 。
文件的新版本被写入c:\Practice\Out 目录。它还附加了一个时间戳。
产品图中的圆圈应保持绿色。如果圆圈变成红色,则表示产品中存在错误。遍历前面的步骤并确保这些目录存在。
在production配置页面选择FileService,选择消息选项卡。它列出了通过该产品的每条消息。选择转到消息查看器。
在消息查看器中选择一条消息,然后选择跟踪选项卡。它将显示从FileService 转到WriteFileOp 操作的消息。
选择正文选项卡,它将显示消息类型和消息中的字段:
请注意,消息类型是Ens.StreamContainer,其中一个字段是OriginalFilename。
将路由器添加到Production中
在本步骤中,将向产品添加路由业务流程和规则。然后,您将一个文件复制到导入目录,并查看显示消息通过路由器的跟踪。在Management Portal(管理门户)中:
选择Interoperability( 互操作性) >配置>Production进入Production 配置 页面,然后选择流程旁边的加号符号以显示业务流程向导。在向导中:
在业务流程类下拉菜单,选择EnsLib.MsgRouter.RoutingEngine。
选择自动创建规则复选框。
指定业务流程名称为FileRouter。
清空Enabled( 启用)复选框。
选择确定。
在对话框中选择OK以批准规则类名称
在Production配置页面选择FileRouter,然后在设置选项卡:
a. 选择启用复选框。
选择应用。
选择业务规则名称右侧的放大镜。这将启动规则编辑器,并显示在您创建业务流程时自动生成的规则。
在规则编辑器中,您将创建一条规则,将PDF 文件发送到WritePDFsOp 操作,并将所有其他文件发送到WriteFileOp 操作。规则如下所示
要创建此规则:
双击规则中的 constraint (约束)值。
在 源 字段输入FileService。
在消息类字段输入Ens.StreamContainer。
选择OK。
在 规则辅助中选择rule( 规则) 然后选择when。
选择 when 条件值,并在规则图上方的文本框内输入Document.OriginalFilename Contains ".pdf",然后选择确定。
选择图中的 when 子句,然后在规则辅助选择 send(发送)。
双击 target 值并选择WritePDFsOp 配置项。
选择图中的 when 子句,然后在规则辅助 选择 otherwise。
选择图中的 otherwise 子句,然后在规则辅助选择 send( 发送)。
双击 send 子句的 target 值并选择WriteFileOp 配置项。
选择保存。
返回到Production配置页面,选择FileService 并在 Settings 选项卡:
选择FileRouter 为接收消息的目标名称。
清空WriteFileOp 复选框。
然后选择应用。
您的productioin现已完成。FileService 将所有消息发送到FileRouter 业务流程(BP)。FileRouter 将根据规则将消息发送到WritePDFsOp 或WriteFileOp 操作。
如果你将hello.pdf 复制到c:\Practice\In 目录,它将被发送到 c:\Practice\PDFsOut 目录,但是,如果您复制test.txt 到c c:\Practice\In 目录,它将被发送到c:\Practice\Out 目录。您还可以查看消息跟踪,消息跟踪可以显示通过文件路由器的消息路径。例如,hello.pdf 的跟踪可能如下:
了解有关互操作性产品的更多信息
有关产品的更多信息,请参阅:
介绍互操作性production
开发产品production
配置production
制定业务规则
文章
姚 鑫 · 三月 5, 2021
# 第四章 标识符
# 标识符
标识符是SQL实体的名称,例如表、视图、列(字段)、模式、表别名、列别名、索引、存储过程、触发器或其他SQL实体。
标识符名称在其上下文中必须是唯一的;
例如,同一模式中的两个表或同一表中的两个字段不能具有相同的名称。
但是,不同模式中的两个表或不同表中的两个字段可以具有相同的名称。
在大多数情况下,相同的标识符名称可以用于不同类型的SQL实体;
例如,一个模式、该模式中的表以及该表中的字段都可以具有相同的名称,而不会产生冲突。
但是,同一个模式中的表和视图不能具有相同的名称。
InterSystems IRIS®数据平台SQL标识符遵循一组命名约定,根据标识符的使用,这可能会受到进一步的限制。
标识符不区分大小写。
标识符可以是简单标识符,也可以是分隔符。
InterSystems SQL默认支持简单标识符和分隔标识符。
# 简单标识符
简单标识符有以下语法:
```
simple-identifier ::= identifier-start { identifier-part }
identifier-start ::= letter | % | _
identifier-part ::= letter | number | _ | @ | # | $
```
## 命名约定
标识符`start`是SQL标识符的第一个字符。
它必须是下列之一:
- 大写或小写字母。
字母定义为通过ObjectScript `$ZNAME`函数验证的任何字符;
默认情况下,这些字母是大写字母A到Z (ASCII 65-90),小写字母a到z (ASCII 97-122),以及带有重音标记的字母(ASCII 192-255,不包括ASCII 215和247)。
InterSystems IRIS可以在SQL标识符中使用任何有效的Unicode(16位)字母字符。
简单的标识符是不区分大小写的(不过,请参见下面的内容)。
按照惯例,它们用首字母大写来表示。
日语区域设置不支持标识符中的重音拉丁字母字符。
日语标识符可能包含(除了日语字符之外)拉丁字母字符A-Z和a-z(65-90和97-122),以及希腊大写字母字符(913-929和931-937)。
- 一个下划线(`_`)。
- 百分号(`%`)。InterSystems IRIS以%字符开头的名称(以`%Z`或`%z`开头的除外)保留为系统元素,不应用作标识符。
标识符部分是SQL标识符的任何后续字符。这些剩余字符可能由零个或多个字符组成:
- 字母(包括Unicode字符)。
- 数字。数字被定义为数字0到9。
- 下划线(`_`)。
- At标志(`@`)。
- 井号(`#`)。
- 美元符号(`$`)。
一些符号字符也用作运算符。**在SQL中,`#`符号用作模运算符。在SQL中,下划线字符可以用来连接两个字符串;提供这种用法是为了与ObjectScript兼容,首选的SQL串联运算符是`||`。** 将符号解释为标识符字符总是优先于将其解释为运算符。任何关于符号字符作为运算符的正确解析的歧义都可以通过在运算符前后添加空格来解决。
简单标识符不能包含空格或非字母数字字符(上面指定的符号字符除外)。系统间SQL导入工具从导入的表名中删除空格。
注意:SQL游标名称不遵循标识符命名约定。
InterSystems SQL包含不能用作简单标识符的保留字。
有关这些保留词的列表,
要测试一个单词是否是保留单词,请使用`$SYSTEM.SQL.IsReservedWord()`方法。
但是,带分隔符的标识符可以与SQL保留字相同。
任何不遵循这些命名约定的标识符都必须在SQL语句中表示为带分隔符的标识符。
## 字母
**默认情况下,InterSystems SQL标识符不区分大小写。
InterSystems SQL通过将标识符转换为所有大写字母后比较它们来实现这一点。**
这对名称的实际使用情况没有影响。
(注意,SQL的其他实现可能会以不同的方式处理标识符的大小写敏感性。
因此,建议避免使用基于案例的标识符。)
**请注意,系统间SQL中的游标名称和密码是区分大小写的。**
## 测试有效标识符
InterSystems IRIS提供了`%SYSTEM.SQL`的`IsValidRegularIdentifier()`方法。它测试字符串是否是有效的标识符。它测试字符用法和保留字。它还执行200个字符的最大长度测试(这是用于避免错误输入的任意长度;这不是标识符验证)。以下对象脚本示例显示了此方法的使用:
```java
/// d ##class(PHA.TEST.SQL).Identifiers()
ClassMethod Identifiers()
{
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("Fred")
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%Fred#123")
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%#$@_Fred")
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("_1Fred")
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%#$")
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("1Fred")
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("Fr ed")
WRITE !,$SYSTEM.SQL.IsValidRegularIdentifier("%sqlupper")
}
```
```java
DHC-APP>d ##class(PHA.TEST.SQL).Identifiers()
1
1
1
1
1
0
0
0
```
前三个方法调用返回1,表示有效的标识符。第四个和第五个方法调用也返回1;这些是有效的标识符,尽管它们不能用作表名或字段名。最后三个方法调用返回0,表示标识符无效。其中两个是无效的,因为它们违反了字符规则——在这些情况下是以数字开头或包含空格。最后一次方法调用返回0,因为指定的字符串是保留字。请注意,这些规则测试是最低要求;它们不能证明标识符对所有的SQL使用都有效。
这个方法也可以作为存储过程从ODBC或JDBC调用:`%SYSTEM.SQL_IsValidRegularIdentifier("nnnn")`。
## 名称空间的名字
命名空间名称(也称为数据库名称)遵循标识符命名约定,并对标点字符和最大长度有额外的限制。
命名空间名称可以作为带分隔符的标识符,并且可以与SQL保留字相同。
但是,相同的命名空间名称标点限制适用于简单标识符和分隔标识符。
## 标识符和类实体名称
通过去除非字母数字字符,SQL表名、视图名、字段名、索引名、触发器名和过程名用于生成相应的持久类实体。
生成的类实体和全局变量的名称遵循这些规则。
注意:命名空间名称和SQL模式名称以及相应的包名称不遵循这些规则。
- 仅在包含标点字符方面不同的标识符是有效的。
因为类对象名称不能包含标点字符,InterSystems IRIS通过去掉所有标点字符来生成相应的唯一对象名称。
如果去掉标识符的标点字符会导致非唯一的类对象名称,InterSystems IRIS将最后一个字母数字字符替换为一个递增的字符后缀,从而创建一个唯一的名称。
对于表、视图、字段、触发器和过程类方法名,这是一个以0开头的整数后缀。
例如,`myname`和`my_name`生成`myname`和`mynam0`,添加我的`#name`生成`mynam1`。
如果生成的惟一名称的数量大于10 (`mynam9`),则通过替换以(`mynamA`)开头的大写字母后缀生成额外的名称。
因为表和视图共享相同的名称空间,所以表或视图的后缀计数器都是递增的。
对于索引名,这个后缀是一个大写字母,以`a`开头。例如,`myindex`和`my_index`生成`myindex`和`myindeA`。
如果定义了一个以后缀字符结束的名称(例如`my_name0`或`my_index`), InterSystems IRIS将通过递增到下一个未使用的后缀来处理惟一名称的生成。
- 第一个字符为标点字符,第二个字符为数字的标识符对于表名、视图名或过程名无效。
它们对字段名和索引名有效。
如果SQL字段名或索引名的第一个字符是标点字符(`%`或`_`),第二个字符是数字,InterSystems IRIS将追加小写的`“n”`作为相应属性名的第一个字符。
- 完全由标点字符组成的标识符,或以两个下划线字符(`__name`)开头的标识符,或包含两个井号(`nn##nn`)的标识符作为SQL实体名称通常是无效的,应该在所有上下文中避免使用。
可以将SQL标识符中的特定字符转换为相应对象标识符中的其他字符。
在允许的标识符字符规则不同的环境中,这有助于标识符的使用。
使用 `%SYSTEM.SQL`的`SetDDLIdentifierTranslations()`方法。
要确定当前设置,调用`$SYSTEM.SQL.CurrentSettings()`。
在DDL运行时将SQL标识符转换为对象标识符时,“From”字符串中的字符被转换为“to”字符串中的字符。
### 在类定义中指定SQL名称
定义投射SQL实体的持久化类时,每个SQL实体的名称与其对应的持久化类定义元素的名称相同。
要使SQL表、字段或索引名称不同,可以使用`SqlTableName`、`SqlFieldName`或`SqlName`(对于索引)关键字在类定义中指定SQL名称。
例如:
```
Property LName As %String [SqlFieldName = "Family#Name"];
```
```
Index NameIdx As %String [SqlName = "FullNameIndex"];
```
## 标识符长度注意事项
**SQL标识符的最大长度为128个字符。当InterSystems IRIS将SQL标识符映射到相应的对象实体时,它会创建最多96个字符的相应属性、方法、查询或索引名称。如果前96个字符的两个SQL标识符相同,InterSystems IRIS会将相应对象名称的第96个字符替换为整数(从0开始)以创建唯一名称。**
# 分隔标识符
分隔标识符的语法如下:
```java
delimited-identifier ::= " delimited-identifier-part { delimited-identifier-part } "
delimited-identifier-part ::= non-double-quote-character | double-quote-symbol
double-quote-symbol ::= ""
```
带分隔符的标识符是由分隔符字符括起来的唯一标识符。InterSystems SQL支持双引号(`“`)作为分隔符,分隔符一般用于避免简单标识符的命名限制。
请注意,InterSystems SQL使用单引号字符(`‘`)来分隔文字。因此,必须使用双引号字符(`“`)指定分隔标识符,必须使用单引号字符(`‘`)指定文字。例如,`’7‘`是数字文字`7`,但`”7“`是分隔标识符。当SQL语句用双引号括起来时(例如,在动态SQL中),该字符串中的双引号字符必须是双引号。
**SQL空字符串应始终指定为一对单引号字符`‘’`。启用分隔标识符支持时,一对双引号字符`“”`将被解析为无效的分隔标识符,并生成`SQLCODE-1`错误。**
## 分隔标识符有效名称
分隔的标识符必须是唯一的名称。带分隔符的标识符不区分大小写;按照惯例,标识符用首字母大写表示。
分隔标识符可以与SQL保留字相同。分隔标识符通常用于避免与SQL保留字的命名冲突。
分隔标识符几乎可以包含任何可打印字符,包括空格。大多数分隔的标识符名称不能包含以下字符:逗号(`,`)、句点(`.`)、插入符号(`^`)和两个字符的箭头序列(`->`);但是分隔的标识符角色名称和用户名可以包含这些字符。分隔的标识符类名可以包含句点(`.`)。任何分隔的标识符都不能以星号(`*`)开头。以下术语不能用作分隔标识符:`%vid`。违反这些命名约定会导致`SQLCODE-1`错误。
用作表、架构、列或索引名的分隔标识符必须能够转换为有效的类实体名称。因此,它必须至少包含一个字母数字字符。以数字(或标点符号后跟数字)开头的分隔标识符会生成带有字母`“n”`前缀的相应类实体名称。
以下示例显示了对列名和表名使用分隔标识符的查询:
```java
SELECT "My Field" FROM "My Table" WHERE "My Field" LIKE 'A%'
```
为表名指定分隔标识符时,必须分别分隔表名和架构名。因此,`“schema”`。`“tablename”`或`schema`。`“tablename”`是有效的标识符,但是`“schema.tablename”`不是有效的标识符。
## 禁用分隔标识符支持
默认情况下,启用对定界标识符的支持。
禁用分隔标识符支持时,双引号内的字符将被视为字符串文字。
可以使用带有`SUPPORT_DELIMITED_IDENTIFIERS`关键字的`SET OPTION`命令在系统范围内设置分隔标识符支持。
可以使用`%SYSTEM.SQL`类的`SetDelimitedIdentifiers()`方法在系统范围内设置分隔标识符支持。
若要确定当前设置,请调用`$SYSTEM.SQL.CurrentSettings()`。
# SQL保留字
SQL包含一长串不能用作标识符的保留字。 实用性很高的文章,👍
问题
Johnny Wang · 七月 13, 2021
各位老师好!
如下两图,是HL7信息体,在形成消息之前,我们一般会先制定文档,包括消息题、消息段、阈值;但是最终在Ensemble中形成的消息是怎么一个过程? 制定好的消息文档可以转换成IRIS可以读取的格式,导入到IRIS中成为消息Schema结构。在处理消息时,可以配置接口应用我们指定的消息Schema结构去处理消息。更多细节可参见文档:HL7 Schemas and Available Tools | Routing HL7 Version 2 Messages in Productions | InterSystems IRIS for Health 2023.1