搜索​​​​

清除过滤器
文章
姚 鑫 · 六月 10, 2021

第三章 指定输出的字符集

# 第三章 指定输出的字符集 # 指定输出的字符集 若要指定要在输出文档中使用的字符集,可以设置Writer实例的Charset属性。选项包括`“UTF-8”`、`“UTF-16”`以及InterSystems IRIS支持的其他字符集。 # Writing the Prolog XML文件的序言(根元素之前的部分)可以包含文档类型声明、处理指令和注释。 ## 影响Prolog的属性 在`writer`实例中,以下属性会影响`prolog`: ### Charset 控制两件事`:XML`声明中的字符集声明和(相应的)输出中使用的字符集编码。 ### NoXmlDeclaration 控制输出是否包含XML声明。在大多数情况下,默认值是0,这意味着已经编写了声明。如果没有指定字符集,并且输出定向到字符串或字符流,则默认为1,并且不写入任何声明。 ## 生成文档类型声明 在根元素之前,可以包含文档类型声明,该声明声明了文档中使用的模式。 要生成文档类型声明,需要使用`WriteDocType()`方法,该方法有一个必选参数和三个可选参数。 就本文档而言,文档类型声明包括以下可能的部分: ```java ``` 如这里所示,文档类型有一个名称,根据XML规则,该名称必须是根元素的名称。 声明可以包含外部子集、内部子集或两者。 external_subset 部分指向其他地方的DTD文件。 本节的结构是以下任何一种: ```java PUBLIC public_literal_identifier PUBLIC public_literal_identifier system_literal_identifier SYSTEM system_literal_identifier ``` 这里`public_literal_identifier`和`system_literal_identifier`是包含DTD uri的字符串。 注意,DTD可以同时具有公共标识符和系统标识符。 下面是一个文档类型声明示例,它包含一个同时使用公共标识符和系统标识符的外部子集: ```java ``` internal_subset部分是一组实体声明。 下面是一个文档类型声明的示例,它只包含一组内部声明: ```java !ENTITY city (#PCDATA)> !ENTITY player (#PCDATA)> ] > ``` `WriteDocType()`方法有四个参数: - 第一个参数指定文档类型的名称,用于在这个XML文档中使用。 这是必需的,而且必须是有效的XML标识符。 还必须将此名称用作本文档中根级别元素的名称。 - 可选的第二个和第三个参数指定声明的外部部分,如下所示: WriteDocType参数 第二个参数 | 第三个参数| 其他部分 ---|---|--- “publicURI” |null| PUBLIC “publicURI” “publicURI” |“systemURI”| PUBLIC “publicURI” “systemURI” null |“systemURI”| SYSTEM “systemURI” - 可选的第四个参数指定声明的内部部分。如果此参数非空,则将其括在方括号`[]`中,并适当地放在声明的末尾。没有添加其他字符。 ## 编写处理指令 要将处理指令写入`XML`,请使用`WriteProcessingInstruction()`方法,该方法有两个参数: 1. 处理指令(也称为目标)的名称。 2. 指令本身是一个字符串。 该方法将以下内容写入XML: ```java ``` 例如,要编写以下处理指令: ```java ``` 为此,可以按如下方式调用`WriteProcessingInstruction()`方法: ```java set instructions="type=""text/css"" href=""mystyles.css""" set status=writer.WriteProcessingInstruction("xml-stylesheet", instructions) ``` ## 指定默认命名空间 在编写器实例中,可以指定默认命名空间,该命名空间仅应用于没有`Namespace`参数设置的类。有几个选项: - 可以在输出方法中指定默认命名空间。四个主要的输出方法(`RootObject()`、`RootElement()`、`Object()`或`Element()`)都接受名称空间作为参数。只有在类定义中未设置`Namespace`参数时,才会将相关元素分配给`Namespace`。 - 可以为编写器实例指定总体默认命名空间。为此,请为编写器实例的`DefaultNamespace`属性指定值。 ```java Class Writers.BasicDemoPerson Extends (%RegisteredObject, %XML.Adaptor) { Parameter XMLNAME = "Person"; Property Name As %Name; Property DOB As %Date; } ``` 默认情况下,如果我们只是导出此类的对象,我们会看到如下所示的输出: ```java Persephone MacMillan 1976-02-20 ``` 相反,如果我们在编写器实例中`将DefaultNamespace`设置为`"http://www.person.org",`然后导出一个对象,则会收到如下所示的输出: ```java Persephone MacMillan 1976-02-20 ``` 在本例中, `` 元素使用默认名称空间,否则不会分配给名称空间。
文章
姚 鑫 · 六月 9, 2021

第二章 从对象写入XML输出

# 第二章 从对象写入XML输出 本章介绍如何从InterSystems IRIS对象生成XML输出。 # 创建XML编写器概述 InterSystems IRIS提供了用于为InterSystems IRIS对象生成`XML`输出的工具。可以指定XML投影的详细信息,如将对象投影到`XML`中所述。然后创建一个`Writer`方法,该方法指定`XML`输出的整体结构:字符编码、对象的显示顺序、是否包括处理指令等。 基本要求如下: - 如果需要特定对象的输出,则该对象的类定义必须扩展`%XML.Adaptor`。除了少数例外,该对象引用的类还必须扩展`%XML.Adaptor`。 - 输出方法必须创建`%XML.Writer`的实例,然后使用该实例的方法。 下面的终端会话显示了一个简单的示例,在该示例中,我们访问启用了XML的对象并为其生成输出: ```java /// d ##class(Sample.Person).Populate(100) /// w ##class(PHA.TEST.Xml).Obj2Xml(1) ClassMethod Obj2Xml(ID) { s obj = ##class(Sample.Person).%OpenId(ID) s xml = ##class(%XML.Writer).%New() s xml.Indent=1 s status = xml.RootObject(obj) q "" } ``` ```java DHC-APP>w ##class(PHA.TEST.Xml).Obj2Xml(1) yaoxin 111-11-1117 1990-04-25 889 Clinton Drive St Louis WI 78672 9619 Ash Avenue Ukiah AL 56589 濮氶懌 111-11-1115 Red Orange Yellow Green Red Orange Yellow 31 ``` # 创建输出方法 输出方法按照指定的顺序逐段构造一个XML文档。输出方法的整体结构取决于需要输出完整的XML文档,还是仅仅输出一个片段。 ## 输出方法的整体结构 方法应按以下顺序执行以下部分或全部操作: 1. 如果使用的对象可能无效,请调用该对象的`%ValidateObject()`方法并检查返回的状态。如果对象无效,则XML也将无效。 **`%XML.Writer` 在导出对象之前不会对其进行验证。这意味着,如果刚刚创建了一个对象,但尚未对其进行验证,则该对象(以及XML)可能是无效的(例如,因为缺少必需的属性)。** 2. 创建`%XML.Writer`类的实例,并根据需要设置其属性。 特别是,需要设置以下属性: - `Indent` 缩进-控制输出是在缩进和换行中生成(如果缩进等于1),还是作为单个长行生成(如果缩进等于0)。后者是默认设置。 - `IndentChars` 缩进字符-指定用于缩进的字符。默认值为两个空格的字符串。如果缩进为0,则此属性无效。 - `Charset` 字符集-指定要使用的字符集。 为了提高可读性,本文档中的示例使用缩进等于1。 3. 指定输出目标。 默认情况下,输出写入当前设备。要指定输出目标,请在开始编写文档之前调用以下方法之一: - `OutputToDevice()`-将输出定向到当前设备。 - `OutputToFile()`-将输出定向到指定文件。可以指定绝对路径或相对路径。请注意,该目录路径必须已经存在。 - `OutputToString()`-将输出定向到字符串。稍后,可以使用另一种方法来检索此字符串。 - `OutputToStream()`-将输出定向到指定的流。 4. 启动文档。可以使用`StartDocument()`方法。请注意,如果尚未通过`StartDocument()`启动文档,则以下方法会隐式启动文档:`Write()`、`WriteDocType()`、`RootElement()`、`WriteComment()`和`WriteProcessingInstruction()`。 5. 可以选择写入文档的序言行。可以使用以下方法: - `WriteDocType()` - 编写DOCTYPE声明。 - `WriteProcessingInstructions()`-编写处理指令。 6. 可以选择指定默认命名空间。编写器将其用于没有定义的XML命名空间的类。 7. 可以选择将命名空间声明添加到根元素。为此,可以在启动根元素之前调用几个实用程序方法。 8. 启动文档的根元素。详细信息取决于该文档的根元素是否对应于InterSystems IRIS对象。有两种可能性: - 根元素可能直接对应于InterSystems IRIS对象。如果要为单个对象生成输出,通常会出现这种情况。 在本例中,使用`RootObject()`方法,该方法将指定的启用XML的对象作为根元素写入。 - 根元素可能只是一组元素的包装器,而这些元素是InterSystems IRIS对象。 在本例中,使用`RootElement()`方法,该方法插入具有指定名称的根级元素。 9. 如果使用`RootElement()`方法,请调用方法来为根元素内的一个或多个元素生成输出。可以按照选择的任何顺序或逻辑在根元素中编写任何元素。有几种方法可以编写单个元素,并且可以结合使用这些技术: - 可以使用`object()`方法,该方法写入启用XML的对象。可以指定此元素的名称,也可以使用由对象定义的默认值。 - 可以使用`element()`方法,该方法使用提供的名称写入元素的开始标记。然后,可以使用`WriteAttribute()`、`WriteChars()`、`WriteCData()`等方法编写内容、属性和子元素。子元素可以是另一个`Element()`,也可以是`Object()`。使用`EndElement()`方法指示元素的结束。 - 可以使用`%XML.Element`并手动构造元素。 10. 如果使用的是`RootElement()`方法,请调用`EndRootElement()`方法。此方法关闭文档的根元素,并根据需要减少缩进(如果有)。 11. 如果文档是从`StartDocument()`开始的,请调用`EndDocument()`方法关闭文档。 12. 如果将输出定向到字符串,请使用`GetXMLString()`方法检索该字符串。 还有许多其他可能的组织,但请注意,某些方法只能在某些上下文中调用。具体地说,一旦开始一个文档,在结束第一个文档之前,不能开始另一个文档。如果这样做,`Writer`方法将返回以下状态: ```java #6275: Cannot output a new XML document or change %XML.Writer properties until the current document is completed. #6275:在当前文档完成之前,无法输出新的XML文档或更改%XML。Writer属性。 ``` `StartDocument()`方法的作用是:显式启动文档。如前所述,其他方法隐式启动文档:`write()`、`WriteDocType()`、`RootElement()`、`WriteComment()`和`WriteProcessingInstruction()`。 注意:这里描述的方法旨在使够向XML文档写入特定的单元,但在某些情况下,可能需要更多的控制。在`%XML.Writer`提供了一个额外的方法`Write()`,可以使用该方法将任意字符串写入输出中的任何位置。 此外,还可以使用`Reset()`方法重新初始化编写器属性和输出方法。如果已经生成了一个XML文档,并且希望在不创建新的编写器实例的情况下生成另一个文档,这将非常有用。 ## 错误检查 **%XML.Writer的大多数方法都会返回状态。应该在每个步骤之后检查状态,并在适当的情况下退出。** ## 插入注释行 如前所述,使用`WriteComment()`方法插入注释行。可以在文档中的任何位置使用此方法。如果尚未启动XML文档,此方法将隐式启动文档。 ## 示例 ```java /// w ##class(PHA.TEST.Xml).Write() ClassMethod Write() As %Status { s obj = ##class(Sample.Person).%OpenId(1) set writer=##class(%XML.Writer).%New() set writer.Indent=1 set status=writer.OutputToDevice() if $$$ISERR(status) { do $System.Status.DisplayError(status) quit $$$ERROR($$$GeneralError, "输出目标无效") } set status=writer.RootObject(obj) if $$$ISERR(status) { do $System.Status.DisplayError(status) quit $$$ERROR($$$GeneralError, "写入根对象时出错") } quit status } ``` 请注意,此方法使用`OutputToDevice()`方法将输出定向到当前设备(默认目标)。这不是必需的,但仅用于演示目的。 当然,输出取决于所使用的类,但可能如下所示: ```java DHC-APP>w ##class(PHA.TEST.Xml).Write() xiaoli 111-11-1111 test 2662 1 ``` ## 有关缩进选项的详细信息 如前所述,可以使用编写器的缩进属性来获取包含附加换行符的输出,以获得更好的可读性。此格式没有正式规范。本节介绍`%XML.Writer`使用的规则。如果缩进等于`1`: - 任何只包含空格字符的元素都会转换为空元素。 - 每个元素都放在自己的行上。 - 如果某个元素是前一个元素的子元素,则该元素相对于该父元素缩进。缩进由`IndentChars`属性确定,该属性默认为两个空格。
文章
姚 鑫 · 六月 8, 2021

第一章 InterSystems XML工具简介

# 第一章 InterSystems XML工具简介 介绍了如何使用 IRIS `XML`工具。 InterSystems IRIS为`XML`处理带来了对象的力量--可以使用对象作为`XML`文档的直接表示,反之亦然。由于InterSystems IRIS包括本机对象数据库,因此可以将此类对象直接用于数据库。此外,InterSystems IRIS提供了用于处理`XML`文档和`DOM`(文档对象模型)的工具,即使它们与任何InterSystems IRIS类无关。 # 用XML表示对象数据 有些InterSystems IRIS `XML`工具主要用于支持`XML`的类。要为类启用`XML`,需要将`%XML.Adaptor`添加到其超类列表中。`%XML.Adaptor`类使能够将该类的实例表示为XML文档。可以添加类参数和属性参数来微调投影。 ![image](/sites/default/files/inline/images/1_48.png) 对于启用了`XML`的类,数据可以采用以下所有形式: - 包含在类实例中。根据类的不同,还可以将数据保存到磁盘,在磁盘中数据可以像其他持久类一样以所有相同的方式使用。 - 包含在`XML`文档中,可以是文件、流或其他文档。 - 包含在`DOM`(文档对象模型)中。 下图概述了用于在这些表单之间转换数据的工具: ![image](/sites/default/files/inline/images/2_28.png) `%XML.Writer`类使能够创建`XML`文档。输出目的地通常是文件或流。确定要包括在输出中的对象,系统根据在类定义中建立的规则生成输出。 `%XML.Reader`类使能够将合适的`XML`文档导入到类实例中。源通常是文件或流。要使用此类,需要指定类名和`XML`文档中包含的元素之间的关联。给定的元素必须具有相应类所需的结构。然后您逐个节点地阅读文档。这样做时,系统会创建该类的内存中实例,其中包含在`XML`文档中找到的数据。 `DOM`也是处理`XML`文档的有用方法。可以使用`%XML.Reader`类读取`XML`文档并创建表示它的`DOM`。在此表示中,`DOM`是一系列节点,可以根据需要在它们之间导航。具体地说,将创建`%XML.Document`的一个实例,该实例表示文档本身并包含节点。然后使用`%XML.Node`检查和操作节点。如果需要,可以使用`%XML.Writer`重新编写XML文档。 InterSystems IRIS `XML`工具提供了许多方法来访问和修改`XML`文档和`DOM`中的数据。 # 创建任意XML 还可以使用InterSystems IRIS `XML`工具创建和使用任意XML-即不映射到任何InterSystems IRIS类的`XML`。要创建任意XML文档,请使用`%XML.Writer`。该类提供了用于添加元素、添加属性、添加命名空间声明等的方法。 要创建任意DOM,请使用`%XML.Document`。该类提供了一个类方法,该方法返回具有单个空节点的DOM。然后根据需要使用该类的实例方法添加节点。 或者使用`%XML.Reader`读取任意XML文档,然后从该文档创建DOM。 # 访问数据 InterSystems IRIS `XML`工具提供了几种访问XML格式数据的方法。下图显示了摘要: ![image](/sites/default/files/inline/images/3_23.png) 对于任何格式良好的XML文档,都可以使用以下类来处理该文档中的数据: - `%XML.TextReader`-可以使用它逐个节点地读取和解析文档。 - `%XML.XPATH.Document`-可以使用它来获取数据,方法是使用引用文档中特定节点的`XPath`表达式。 在InterSystems IRIS中,DOM是`%XML.Document`的实例。该实例表示文档本身并包含节点。可以使用该类的属性和方法从`DOM`中检索值。可以使用`%XML.Node`检查和操作节点。 # 修改XML InterSystems IRIS XML工具还提供了修改`XML`格式数据的方法。下图显示了摘要: ![image](/sites/default/files/inline/images/4_17.png) 对于`XML`文档,可以使用`%XML.XSLT.Transformer`中的类方法执行`XSLT`转换并获得文档的修改版本。 对于DOM,可以使用`%XML.Document`的方法修改`DOM`。例如,可以添加或删除元素或属性。 # SAX解析器 InterSystems IRIS XML工具使用InterSystems IRIS SAX(Simple API For XML)解析器。这是一个内置的SAX XML验证解析器,使用标准`Xerces`库。`SAX`是一个解析引擎,它提供完整的XML验证和文档解析。InterSystems IRIS SAX使用高性能的进程内调入机制与InterSystems IRIS进程通信。使用此解析器,可以使用内置的InterSystems IRIS XML支持或通过在InterSystems IRIS中提供您自己的自定义`SAX`接口类来处理`XML`文档。 对于特殊应用程序,可以创建自定义实体解析器和内容处理程序。 可以使用行业标准的`XMLDTD`或模式验证来验证任何传入的`XML`,并且可以指定要解析的XML项。 # 其他XML工具 InterSystems IRIS `XML`支持包括以下附加工具: - XML架构向导读取XML架构文档,并生成一组支持XML的类,这些类与架构中定义的类型相对应。可以指定一个包来包含类,以及控制类定义详细信息的各种选项。 - `%XML.Schema`类使能够从一组启用了XML的类生成XML架构。 - `%XML.Namespaces`类使能够检查XML命名空间以及其中的类,以查找InterSystems IRIS命名空间。 - `%XML.Security.EncryptedData`类和其他类使能够加密XML文档以及解密加密文档。 - `%XML.Security.Signature`类和其他类使能够对XML文档进行数字签名,以及验证数字签名。 # 使用XML工具时的注意事项 在使用任何类型的XML工具时,至少有三个一般要点需要考虑: - 任何XML文档都有字符编码 - 将XML文档映射到类(文字或`SOAP`编码)有不同的方法 - 应该知道SAX解析器的默认行为 # 输入输出的字符编码 导出XML文档时,可以指定要使用的字符编码;否则,InterSystems IRIS会根据目标选择编码: - **如果输出目标是文件或二进制流,则默认值为`“UTF-8”`**。 - 如果输出目标是字符串或字符流,则默认`为"UTF-16"`。 对于InterSystems IRIS读取的任何`XML`文档,文档的XML声明应该指示该文件的字符编码,并且文档应该按照声明的方式进行编码。例如: ``` ``` 但是,如果文档中未声明字符编码,InterSystems IRIS将假定: - 如果输出目标是文件或二进制流,则默认值为`“UTF-8”`。 - 如果输出目标是字符串或字符流,则默认为`"UTF-16"`。 # 选择文档格式 使用`XML`文档时,必须知道将文档映射到InterSystems IRIS类时要使用的格式。同样,在创建`XML`文档时,需要指定编写文档时要使用的文档格式。`XML`文档格式如下: - 文字表示文档是对象实例的文字副本。在大多数情况下,即使在使用`SOAP`时,也使用文字格式。除非另有说明,否则文档中的示例均使用文字格式。 - 编码的意思是按照`SOAP 1.1`标准或`SOAP 1.2`标准中描述的编码。`SOAP1.1`和`SOAP1.2`的细节略有不同。 以下小节显示了这些文档格式之间的差异。 ## 文字格式 ```java Klingman,Julie G. 1946-07-21 W897 Bensonhurst 60302 Jung,Kirsten K. Xiang,Charles R. Frith,Terry R. ``` ## 编码格式 相比之下,下面的示例以编码格式显示相同的数据: ```java ... Jung,Kirsten K. ... Quixote,Umberto D. ... Chadwick,Mark L. ... Klingman,Julie G. 1946-07-21 W897 Bensonhurst 60302 ... ``` 请注意编码版本中的以下差异: - 输出的根元素包括`SOAP`编码命名空间和其他标准命名空间的声明。 - 本文档包括同一级别的人员、地址和医生元素。`Address`和`Doctor`元素列出了引用它们的`Person`元素使用的唯一`ID`。每个对象值属性都是这样处理的。 - 顶级`Address`和`Doctor`元素的名称与各自类的名称相同,而不是与引用它们的属性名称相同。 - 编码格式不包括任何属性。`GroupID`属性被映射为`Person`类中的属性。在文字格式中,此属性被投影为特性。但是,在编码版本中,属性被投影为元素。 - 对集合的处理方式不同。例如,列表元素具有属性`ENC:arrayType`.。 - 每个元素都有一个`xsi:type`属性的值。 注意:对于`SOAP1.2`,编码版本略有不同。要轻松区分版本,请检查SOAP编码命名空间的声明: - 对于`SOAP1.1,SOAP`编码命名空间为`"http://schemas.xmlsoap.org/soap/encoding/"` - 对于`SOAP1.2,SOAP`编码命名空间为`"http://schemas.xmlsoap.org/wsdl/soap12/"` 除非解析器可以使用这些其他模式,否则验证将失败。特别是对于WSDL文档,有时需要下载所有模式并编辑主模式以使用正确的位置。 它尝试解析所有实体,包括所有外部实体。(其他XML解析器也会这样做。)。这一过程可能很耗时,具体取决于它们所在的位置。具体地说,`Xerces `使用网络访问器来解析一些URL,并且实现使用阻塞I/O。因此,不会超时,网络获取可能会在错误条件下挂起,这在实践中很少见。 此外,`Xerces`不支持`https`;也就是说,它不能解析位于`https`位置的实体。 如果需要,可以创建自定义实体解析器,也可以禁用实体解析; # IRIS支持的标准 IRIS XML支持遵循以下标准: - XML 1.0 (https://www.w3.org/TR/REC-xml/) - Namespaces in XML 1.0 (https://www.w3.org/TR/REC-xml-names/) - XML Schema 1.0 (https://www.w3.org/TR/xmlschema-0/, https://www.w3.org/TR/xmlschema-1/, https://www.w3.org/TR/xmlschema-2/) - XPath 1.0 as specified by https://www.w3.org/TR/xpath - SOAP 1.1标准第5节指定的SOAP 1.1编码。 - SOAP1.2编码,如第3节第2部分: Adjuncts (https://www.w3.org/TR/soap12-part2/) of the SOAP 1.2 standard. - XML Canonicalization Version 1.0 (also known as inclusive canonicalization), as specified by https://www.w3.org/TR/xml-c14n. - XML Exclusive Canonicalization Version 1.0 as specified by https://www.w3.org/TR/xml-exc-c14n/, including the InclusiveNamespaces PrefixList feature (https://www.w3.org/TR/xml-exc-c14n/#def-InclusiveNamespaces-PrefixList) - XML Encryption (https://www.w3.org/TR/xmlenc-core/) InterSystems IRIS支持使用RSA-OAEP或RSA-1.5进行密钥加密,并支持使用AES-128、AES-192或AES-256对邮件正文进行数据加密。 - XML Signature using Exclusive XML Canonicalization and RSA SHA-1 (https://www.w3.org/TR/xmldsig-core/) InterSystems IRIS提供两个XSLT处理器: - Xalan处理器支持XSLT 1.0。 - Saxon处理器支持XSLT 2.0。 **注意:InterSystems IRIS不支持在一个元素中有多个名称相同的属性,每个属性位于不同的名称空间中。**
文章
Lele Yang · 六月 8, 2021

FAQ 常见问题系列--应用篇 升级系统后打开管理门户SMP报错5001

如果您在升级了系统之后,打开SMP时看到如下报错,ERROR #5001: 对象的服务器版本与客户端发送的版本不一致: %ZEN.Component.vgroup 一般情况下,这个报错是由浏览器缓存中残留的过期信息造成的,可以通过清除浏览器缓存来解决。 如果清除浏览器缓存之后仍然未能解决此问题,请您前往系统安装目录, 如:d:\InterSystems\IRIS\CSP\broker,查看css/js文件的时间戳在本次更新安装之后是否并没有相应地更新,如果没有,请您做以下尝试,1)在IRIS中更改数据库IRISLIB, 之前的版本是CACHELIB, 取消只读装载,方法如下,打开管理门户SMP, 系统管理->配置->本地数据库,选择要更改的数据库,取消"只读方式挂载",点击【保存】。2)重新编译%Zen组件,w ##class(%SYSTEM.OBJ).Compile("%ZEN.Component.vgroup")此时,再次前往,d:\InterSystems\IRIS\CSP\broker,会看到相关的css/js文件时间戳已经更新。3)恢复上述数据库的只读装载。 如果以上办法仍然未能解决您的问题,建议您联系WRC,寻求Support的进一步帮助。
文章
姚 鑫 · 六月 6, 2021

Caché 网络实用工具

# Caché 网络实用工具 # [第一章 发送HTTP请求☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117108190) # [第二章 设置和获取HTTP标头☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117148255) # [第三章 发送HTTP请求☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117195938) # [第四章 收发电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117214514) # [第五章 向邮件添加附件☆](https://yaoxin.blog.csdn.net/article/details/117248548) # [第六章 从POP3服务器提取电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117278414) # [第七章 从POP3服务器提取电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117320147) # [第八章 处理收到的电子邮件☆](https://yaoxin.blog.csdn.net/article/details/117350781) # [第九章 创建、编写和阅读MIME邮件☆](https://yaoxin.blog.csdn.net/article/details/117378600) # [第十章 使用FTP☆☆☆☆☆](https://yaoxin.blog.csdn.net/article/details/117394438) # [第十一章 发送和接收IBM WebSphere MQ消息☆](https://yaoxin.blog.csdn.net/article/details/117409322) # [第十二章 IBM WebSphere MQ检索邮件☆](https://yaoxin.blog.csdn.net/article/details/117435132) # [第十三章 使用SSH☆](https://yaoxin.blog.csdn.net/article/details/117459391) # [第十四章 其他InterSystems %Net工具☆☆☆](https://yaoxin.blog.csdn.net/article/details/117508484) # [第十五章 Caché WebSocket☆☆☆](https://yaoxin.blog.csdn.net/article/details/117548341) # 前言 手册帮助程序员使用%Net包中的一些关键类,这些类为许多有用的Internet协议提供了易于使用的接口。因为这个包的类文档相当广泛,所以本手册提供了一个快速、有条理的概述,而不是深入研究每个参数、属性和方法。熟悉本手册中提到的协议和第三方工具。 # 预告 下一期系列将用一个月的时间连载,**《Caché XML》**,敬请期待。 # 交流群 - QQ群号:410039091 - 笔者QQ:454115408 - 公众号:技术理科直男 - [intersys版主:姚鑫](https://cn.community.intersystems.com/user/236891/posts) ![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f9VqwzNP-1608850948003)(3E1D939266954ED48BDAEA9B8086B11E)\]](https://img-blog.csdnimg.cn/20201225070433434.png) # 大型免费课程,进群410039091获取课程目录 - 适合所有阶段程序员,总有一款你遗漏的知识点! ![在这里插入图片描述](https://img-blog.csdnimg.cn/20210606224558577.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3lhb3hpbjUyMTEyMw==,size_16,color_FFFFFF,t_70#pic_center)
文章
姚 鑫 · 六月 2, 2021

第十四章 其他InterSystems %Net工具

# 第十四章 其他InterSystems %Net工具 下面是`%Net`中其他一些有用类的简短列表: # %Net.URLParser InterSystems IRIS提供了一个实用程序`类%Net.URLParser`,可以使用它将URL字符串解析为其组成部分。例如,当您重定向HTTP请求时,这很有用。 该类包含一个类方法`Parse()`,它接受一个包含`URL`值的字符串,并通过引用返回一个包含`URL`各部分的数组。例如: ```java /// w ##class(PHA.TEST.HTTP).URLParser() ClassMethod URLParser() { Set url = "https://www.google.com/search?q=Java+site%3Adocs.intersystems.com&oq=Java+site%3Adocs.intersystems.com" Do ##class(%Net.URLParser).Parse(url,.components) zw components } ``` ``` DHC-APP>w ##class(PHA.TEST.HTTP).URLParser() components("fragment")="" components("host")="www.google.com" components("netloc")="www.google.com" components("params")="" components("path")="/search" components("query")="q=Java+site%3Adocs.intersystems.com&oq=Java+site%3Adocs.intersystems.com" components("scheme")="https" ``` 返回时,组件将包含此URL各部分的数组: Element | Value |Description ---|---|--- `components("fragment")` | `null` |URL的片段(#字符后面) `components("host")` | `www.google.com` |URL请求的主机 `components("netloc")` | w`ww.google.com` | URL的网络地址 `components("params")` | |URL中包含的URL参数 `components("path")` | `/search` | URL的文件路径 `components("query")` | `q=Java+site%3Adocs.intersystems.com&oq=Java+site%3Adocs.intersystems.com` |URL中包含的查询字符串 `components("scheme")` | https | 此URL指定的传输方案 # %Net.Charset 可以使用`%Net.Charset`表示InterSystems IRIS内的MIME字符集,并将这些字符集映射到InterSystems IRIS区域设置。此类包括以下类方法: - `GetDefaultCharset()`返回当前InterSystems IRIS区域设置的默认字符集。 - `GetTranslateTable()`返回给定输入字符集的InterSystems IRIS转换表的名称。 - `TranslateTableExists()`指示是否已加载给定字符集的转换表。 # %Net.TelnetStream 可以使用`%Net.TelnetStream`模拟`Windows NT Telnet.exe`的握手行为。 # %Net Security Classes `%Net`包提供了许多用于身份验证和安全性的类。
文章
TZ Zhuang · 六月 2, 2021

FAQ 常见问题系列--系统管理篇 如何进行数据库备份

InterSystems产品有四种备份方法:(1) 外部备份(2) 在线备份(3) 冷备份(4) 传统的并行外部备份有关这些方法的细节请参考在线文档 https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_BACKUP 以下是对每种备份方法的简要描述: (1) 外部备份外部备份是InterSystems推荐的最佳备份方式。外部备份一般是对数据库文件所在的存储创建快照的方式来实现。创建快照可以在多个层面进行,例如存储层面,操作系统层面,等等,因此这些相关技术和工具一般由第三方来提供。在做快照前,一定要先停止对数据库文件的写入(InterSystems IRIS的IRIS.DAT,Caché/Ensemble的CACHE.DAT)。但是用户进程可以继续对内存进行更新,而不需要中断。InterSystems提供了停止对数据库文件写入的方法,用户可以把这个加入到快照工具的脚本里。外部备份一般包括以下几步:1. 使用Backup.General.ExternalFreeze()方法来停止对数据库文件的写入。2. 使用第三方快照工具来对文件系统创建快照。3. 使用Backup.General.ExternalThaw()方法来恢复对数据库文件的写入。4. 把快照拷贝到备份介质上(用于存储备份的磁盘,磁带,等等)。5. 删除快照。 (2) 在线备份在线备份是InterSystems自己特有的备份方式,可实现无宕机备份。但是,在线备份只能备份数据库文件(InterSystems IRIS的IRIS.DAT,Caché/Ensemble的CACHE.DAT),并且会把所有需要备份的数据库文件中的数据块写入到一个.cbk的备份文件。因此如果想要使用在线备份来备份整个系统环境,除了数据库文件外,还需要额外备份很多系统文件,例如InterSystems产品的安装目录,WIJ文件,主日志和备日志目录等等。在线备份包括3种类型:1. 全备份 -- 把所有使用的数据块写入到一个.cbk文件。2. 累积备份 -- 从上一次全备份起,所有变化过的数据块写入到一个.cbk文件。恢复时,需要和上一次全备份一起恢复。3. 增量备份 -- 从上一次备份起,所有变化过的数据块写入到一个.cbk文件。恢复时,需要和上一次全备份及中间所有备份一起恢复。在线备份的这些特性,并不适用于作为数据量大的生产系统的备份方案。 (3) 冷备份冷备份是在数据库系统正常停机状态下,所做的外部备份,即拷贝文件系统到存储介质。 (4) 传统的并行外部备份传统的并行外部备份是一种在特殊情况下才可行的备份方法。一般需要满足以下条件:1. 数据库在一个集群里,并且不能有宕机时间。2. 没有快照功能。3. 在线备份不能满足需求。并行外部备份结合了数据库文件(*.DAT)拷贝和在线备份里增量备份的功能。其步骤如下:1. 在数据库中设置备份启动标志。2. 拷贝数据库文件(*.DAT)。3. 对该拷贝时间内被修改的数据进行在线备份的增量备份。具体使用情况和详情也请参考在线文档 https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=GCDI_backup#GCDI_backup_methods_ext_concurrent 最新版本InterSystems IRIS for Health示例:===============================================================1. 设置标志,开始备份数据库。Set ^ClearOK=$CLRINC^DBACK("QUIET")2. 拷贝操作系统上的数据库文件(*.DAT)。3. 运行下面的命令,表明你已经使用了一个外部备份工具。Set x=$$BACKUP^DBACK("","E","Dirty external backup","","","")4. 进行增量备份。Set x=$$BACKUP^DBACK("","I","incremental","test.cbk","Y","bck.log","QUIET","Y","Y")===============================================================InterSystems产品中的上述处理可以做成例程Routine或类方法,并与批处理相结合进行操作。关于传统并行外部备份中使用的^DBACK例程的更多信息,请参考以下文件https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=GCDI_backup#GCDI_backup_util_DBACK_entry_backup
文章
Michael Lei · 六月 1, 2021

使用 InterSystems IRIS 实现 Data Fabric 架构

什么是 Data Fabric? “这是一套用于在公司中实施、管控、管理和执行数据操作的硬件基础架构、软件、工具和资源,功能包括跨所有数据存储平台的数据采集、转换、存储、分发、整合、复制、可用性、安全性、保护、灾难恢复、演示、分析、保存、保留、备份、恢复、归档、召回、删除、监视和容量规划,并可使应用程序的使用满足公司的数据需求”。 (Alan McSweeney) Data Fabric 是一种可利用包括多模型数据库、Analytics、AI、ESB/SOA、微服务和 API 管理在内的所有可用资源和技术创新来获取商业价值的新型数据操作方法。 Data Fabric 原则 Alan McSweeney 列出了以下 Data Fabric 使用原则: 管控、管理和控制 - 无论数据位于何处,均可掌控数据并能够有效管理和管控数据           稳定性、可靠性和一致性 - 使用通用工具和实用工具在所有数据层之间提供稳定可靠的 Data Fabric 安全性 - 符合 Data Fabric、治理自动化、合规性和风险管理方面的各项安全标准   开放、灵活和自由选择 - 能够选择和更改数据存储、访问权限和位置 自动化 - 自动化管理和维护活动、DevOps 和 DevSecOps   性能、恢复、访问和使用 - 应用程序和用户可以在需要时、根据需求以及以适用格式访问数据 一体化 - 所有组件在所有数据层上均可互操作       Data Fabric 架构 McSweeney 设计了一幅在组织内部采用 Data Fabric 的详细概念图,如下所示: 您可以看到,需要采用某些技术才能将数据输入、处理和输出操作融合到一个流程中,进而“编织”数据并为数据使用者提供业务价值。 这些元素可以概括为下图: 数据操作位于数据接收网关 (Data Intake Gateway) 中,使用 ESB 和 API 网关技术捕获、编排、转换、丰富数据,并将数据资产整合到企业数据资产中。 借助 Analytics 和 AI 处理数据操作结果,从而为数据使用者提供数据分析。 由于数据量庞大且种类繁多,以及人们对于“黄金数据”这一“获得真理的唯一渠道”的需求,因此多模型存储库同样是一个重要角色。 InterSystems IRIS 与 Data Fabric InterSystems IRIS 是一款支持在组织内部采用 Data Fabric 架构的 Data Fabric 平台,如下文所示: Data Fabric 组件        InterSystems IRIS 组件 多功能存储库   IRIS 数据库   Java、Python、.NET 和对象脚本中受支持的 SQL Relational 对象 NoSQL 到 JSON – DocDB 可以使用 MDX 多维数据集进行分析 分片支持以支持大数据(与 MongoDB 相同) 企业缓存 – ECP 通过集成总线实现的 MDM RBAC、密码学和标签 Transanalytic 和数据湖 使用 ORM 进行对象脚本的 JDBC、ODBC 或本机 SQL 访问 通过集成总线/服务总线和 API 网关实现数据接收/网关   IRIS 互操作性    REST API 和 API 管理 数据总线 - SOA、EAI、ESB 集成和 EDI 适配器 流程自动化 - BPL 和 DTL、规则 原生集成 Java、.NET 和 C Python 和 JavaScript MFT - 托管文件传输 消息、事件和 JMS 采用 MQTT/API 的物联网 数据抽取/引入、转换和加载     分析和报告实用工具   IRIS Analytics   BI/分析和 ETL (BPL/DTL) 分级面板、分析和数据透视 SQL、MDX 和 Power BI 连接器访问 报告和嵌入式报告 UIMA - 非结构化内容分析 语义和情感分析 实时或计划分析 AutoML – IntegratedML 采用 R 或 Pyhton 的 AI/机器学习 NLP - 自然语言处理 R 、Python 和对象脚本中的统计信息 数据总线和认知流 文本分析 PMML 自适应运营分析 (AtScale) 用户门户 AI 实用工具     ## 结语 InterSystems IRIS 并非简单的数据库或互操作平台,而是帮助您实现 Data Fabric 的核心角色。 如果您使用其他公司的其他解决方案,则需要购买 4 至 7 套解决方案,但使用 InterSystems,您只需要由多模型数据库、ESB/APIM、Analytics 和 AI 组成的一套解决方案即可创建 Data Fabric。 它为您提供了价格低廉、易于使用的优势。 了解详情:
文章
姚 鑫 · 五月 31, 2021

第十二章 IBM WebSphere MQ检索邮件

# 第十二章 IBM WebSphere MQ检索邮件 # 检索邮件 要检索邮件,请执行以下操作: 1. 按照“创建连接对象”中的说明创建连接对象。在这种情况下,请创建`%Net.MQRecv`的实例。`Connection`对象有一个消息队列,可以从中检索消息。 2. 根据需要调用以下方法: - `%Get()`-通过引用返回字符串消息作为第一个参数。 - `%GetStream()`-给定初始化的文件字符流,此方法从队列中检索消息,并将其放入与该流关联的文件中。请注意,必须设置流的`Filename`属性才能对其进行初始化。不支持二进制流。 3. 检查调用的方法返回的值。请参阅“获取错误代码”。请记住,当队列为空时,IBM `WebSphere MQ`返回`2033`。 4. 检索完消息后,调用`Connection`对象的`%Close()`方法以释放动态链接库的句柄。 示例1:`ReceiveString()` 下面的类方法从`mqtest`队列检索消息。 ```java ///Method returns string or null or error message ClassMethod ReceiveString() As %String { Set recv=##class(%Net.MQRecv).%New() Set queue="mqtest" Set qm="QM_antigua" Set chan="S_antigua/TCP/antigua(1414)" Set logfile="c:\mq-recv-log.txt" Set check=recv.%Init(queue,qm,chan,logfile) If 'check Quit recv.%GetLastError() Set check=recv.%Get(.msg) If 'check { Set reasoncode=recv.%GetLastError() If reasoncode=2033 Quit "" Quit "ERROR: "_reasoncode } Quit msg } ``` 示例2:`ReceiveCharacterStream()` 以下方法可以检索更长的消息,因为它使用`%GetStream()`: ```java /// Method returns reason code from IBM WebSphere MQ ClassMethod ReceiveCharacterStream() As %Integer { Set recv=##class(%Net.MQRecv).%New() Set queue="mqtest" Set qm="QM_antigua" Set chan="S_antigua/TCP/antigua(1414)" Set logfile="c:\mq-recv-log.txt" Set check=recv.%Init(queue,qm,chan,logfile) If 'check Quit recv.%GetLastError() //initialize the stream and tell it what file to use //make sure filename is unique we can tell what we received Set longmsg=##class(%FileCharacterStream).%New() Set longmsg.Filename="c:\mq-received"_$h_".txt" Set check=recv.%GetStream(longmsg) If 'check Quit recv.%GetLastError() Quit check } ``` # 更新消息信息 `%Net.MQSend`和`%Net.MQRecv`类还提供以下方法: ### %CorId() (通过引用)更新上次读取的邮件的关联ID。 ### %ReplyQMgrName() (通过引用)更新上次读取的消息的回复队列管理器名称。 ### %ReplyQName() (通过引用)更新上次读取的消息的回复队列名称。 # Troubleshooting 如果在使用IBM `WebSphere MQ`的InterSystems IRIS接口时遇到问题,应该首先确定客户端是否安装正确并且可以与服务器通信。要执行这样的测试,可以使用IBM `WebSphere MQ`提供的示例程序。可执行文件位于IBM `WebSphere MQ`客户端的bin目录中。 以下步骤介绍如何在`Windows`上使用这些示例程序。在其他操作系统上,细节可能会有所不同;请参考IBM文档并检查您的客户端中存在的文件的名称。 1. 创建一个名为`MQSERVER`的环境变量。它的值的格式应该是`channel_name/Transport/server`,其中`channel_name`是要使用的通道的名称,`Transport`是指示要使用的传输的字符串,而`server`是服务器的名称。例如:`S_Antigua/TCP/Antigua` 2. 在命令行中,输入以下命令: ```java amqsputc queue_name queue_manager_name ``` 其中,`QUEUE_NAME`是要使用的队列的名称,`QUEUE_MANAGER_NAME`是队列管理器的名称。例如: ```java amqsputc mqtest QM_antigua ``` 如果`amqsputc`命令无法识别,请确保已更新`PATH`环境变量以包括IBM `WebSphere MQ`客户端的bin目录。 3. 应该会看到几行代码,如下所示: ```java Sample AMQSPUT0 start target queue is mqtest ``` 4. 现在可以发送消息了。只需键入每条消息,然后在每条消息后按Enter键即可。例如: ```java sample message 1 sample message 2 ``` 5. 发送完邮件后,按两次Enter键。然后,将看到如下所示的行: ```java Sample AMQSPUT0 end ``` 6. 要完成此测试,我们将检索发送到队列的消息。在命令行中键入以下命令: ```java amqsgetc queue_name queue_manager_name ``` 其中,`QUEUE_NAME`是要使用的队列的名称,`QUEUE_MANAGER_NAME`是队列管理器的名称。例如: 7. 然后,应该看到一个起始行,后跟之前发送的消息,如下所示: ```java Sample AMQSGET0 start message message ``` 8. 此示例程序短暂等待接收任何其他消息,然后显示以下内容: ```java no more messages Sample AMQSGET0 end ``` 如果测试失败,请参考IBM文档。问题的可能原因包括以下几个方面: - 安全问题 - 队列定义不正确 - 队列管理器未启动
文章
Louis Lu · 五月 30, 2021

如何保存、查询 List 类型数据

本文主要总结了在InterSystems IRIS 中如何保存、查询List类型数据 假设我们设计的对象中包含姓名,同时每个姓名下可以包含多个电话。我们可以使用下面方法进行处理。 1. 传统方式 我们可以把每一个姓名和电话放在不同列中。 Class Test.Person Extends %Persistent { Property Name As %String; Property Phone As %String; } 我们使用SQL语句插入数据: insert into Test.Person values ('a','111-111-1111'); insert into Test.Person values ('b','222-111-1111'); insert into Test.Person values ('a','111-222-1111'); insert into Test.Person values ('c','333-111-1111'); insert into Test.Person values ('b','222-222-1111'); 数据在表中是这样的: Name Phone a 111-111-1111 b 222-111-1111 a 111-222-1111 c 333-111-1111 b 222-222-1111 这种情况下,我们可以使用下面的sql语句将结果返回: SELECT distinct %exact(Name) Name, LIST(phone %foreach(Name)) Phonestr FROM test.person Name Phonestr a 111-111-1111,111-222-1111 b 222-111-1111,222-222-1111 c 333-111-1111 我们可以为电话号码创建索引,以提高搜索速度,如下: Index IdxP On Phone; 使用这种方式保存list数据比较简单,当是当list数据非常多时,这种方法会使表格臃肿。 2. 保存在一个字符串字段中,使用分隔符区分 这里我们将所有电话号码保存在一个字符串字段中,每个号码之间用逗号区分 Class Test.Person2 Extends %Persistent { Property Name As %String; Property PhoneStr As %String; } 填充数据后,类似于这样 Name PhoneStr a 111-111-1111,111-222-1111 b 222-111-1111,222-222-1111 c 333-111-1111 d 333-111-1111,222-222-1111 这种情况下我们可以用下面方法实现对每个电话的索引 Index idxP On PhoneStr(ELEMENTS); ClassMethod PhoneStrBuildValueArray(value, ByRef array) As %Status { if value="" { s array(0)=value }else{ s list=$lfs(value,","),ptr=0 while $listnext(list,ptr,item){ s array(ptr)=item } } q $$$OK } 这里用到了一个函数 ClassMethod propertynameBuildValueArray(value, ByRef valueArray) As %Status 其中: value – 需要拆分的内容; valueArray – 返回array类型的值,其中包含拆分的内容,格式为 array(key1)=value1, array(key2)=value2... 这时候我们的数据是这样: USER>zw ^Test.Person2D ^Test.Person2D=4 ^Test.Person2D(1)=$lb("","a","111-111-1111,111-222-1111") ^Test.Person2D(2)=$lb("","b","222-111-1111,222-222-1111") ^Test.Person2D(3)=$lb("","c","333-111-1111") ^Test.Person2D(4)=$lb("","d","333-111-1111,222-222-1111") 索引是这样: USER>zw ^Test.Person2I ^Test.Person2I("idxP"," 111-111-1111",1)="" ^Test.Person2I("idxP"," 111-222-1111",1)="" ^Test.Person2I("idxP"," 222-111-1111",2)="" ^Test.Person2I("idxP"," 222-222-1111",2)="" ^Test.Person2I("idxP"," 222-222-1111",4)="" ^Test.Person2I("idxP"," 333-111-1111",3)="" ^Test.Person2I("idxP"," 333-111-1111",4)="" 这种情况下我们可以通过下面的SQL 语句查找 包含电话号码 333-111-1111 的姓名 select Name from test.person2 where phonestr ['333-111-1111' select Name from test.person2 where phonestr like '%333-111-1111%' 但是当你检查查询计划的时候,却发现它并没有使用任何索引 我们只能通过类似于下面SQL语句的写法才能使用该索引 select Name from test.person2 where for some %element(Phonestr) (%value = '333-111-1111') 类似的还有下面的写法 (%Value %STARTSWITH 'а') (%Value [ 'a' and %Value [ 'b') (%Value in ('c','d')) (%Value is null) 3. 使用 %List 类型 Class Test.Person3 Extends %Persistent { Property Name As %String; Property PhoneList As %List; Index idxP On PhoneList(ELEMENTS); ClassMethod PhoneListBuildValueArray(value, ByRef array) As %Status { if value="" { s array(0)=value }else{ s ptr=0 while $listnext(value,ptr,item){ s array(ptr)=item } } q $$$OK } } 插入数据 insert into Test.Person3 (Name,PhoneList) select 'a', $LISTBUILD('111-111-1111','111-222-1111') insert into Test.Person3 (Name,PhoneList) select 'b', $LISTBUILD('222-111-1111','222-222-1111') insert into Test.Person3 (Name,PhoneList) select 'c', $LISTBUILD('333-111-1111') insert into Test.Person3 (Name,PhoneList) select 'd', $LISTBUILD('333-111-1111','222-222-1111') 数据和索引保存为 USER>zw ^Test.Person3D ^Test.Person3D=4 ^Test.Person3D(1)=$lb("","a",$lb("111-111-1111","111-222-1111")) ^Test.Person3D(2)=$lb("","b",$lb("222-111-1111","222-222-1111")) ^Test.Person3D(3)=$lb("","c",$lb("333-111-1111")) ^Test.Person3D(4)=$lb("","d",$lb("333-111-1111","222-222-1111")) USER>zw ^Test.Person3I ^Test.Person3I("idxP","111-111-1111",1)="" ^Test.Person3I("idxP","111-222-1111",1)="" ^Test.Person3I("idxP","222-111-1111",2)="" ^Test.Person3I("idxP","222-222-1111",2)="" ^Test.Person3I("idxP","222-222-1111",4)="" ^Test.Person3I("idxP","333-111-1111",3)="" ^Test.Person3I("idxP","333-111-1111",4)="" 同样可以使用下面的SQL语句查找包含电话333-111-1111的姓名 select Name from test.person2 where for some %element(phonelist) (%value = '333-111-1111') 4 使用 List Of、Array Of 保存 不需要定义propertynameBuildValueArray函数 Class Test.Person4 Extends %Persistent { Property Name As %String; Property PhoneList As list Of %String; Index idxP On PhoneList(ELEMENTS); } 使用同样的方式插入数据 insert into Test.Person4 (Name,PhoneList) select 'a', $LISTBUILD('111-111-1111','111-222-1111') insert into Test.Person4 (Name,PhoneList) select 'b', $LISTBUILD('222-111-1111','222-222-1111') insert into Test.Person4 (Name,PhoneList) select 'c', $LISTBUILD('333-111-1111') insert into Test.Person4 (Name,PhoneList) select 'd', $LISTBUILD('333-111-1111','222-222-1111') 数据和索引保存为 USER>zw ^Test.Person4D ^Test.Person4D=4 ^Test.Person4D(1)=$lb("","a",$lb("111-111-1111","111-222-1111")) ^Test.Person4D(2)=$lb("","b",$lb("222-111-1111","222-222-1111")) ^Test.Person4D(3)=$lb("","c",$lb("333-111-1111")) ^Test.Person4D(4)=$lb("","d",$lb("333-111-1111","222-222-1111")) USER>zw ^Test.Person4I ^Test.Person4I("idxP"," 111-111-1111",1)="" ^Test.Person4I("idxP"," 111-222-1111",1)="" ^Test.Person4I("idxP"," 222-111-1111",2)="" ^Test.Person4I("idxP"," 222-222-1111",2)="" ^Test.Person4I("idxP"," 222-222-1111",4)="" ^Test.Person4I("idxP"," 333-111-1111",3)="" ^Test.Person4I("idxP"," 333-111-1111",4)="" 使用同样的SQL查询可以得到结果 select Name from test.person4 where for some %element(Phonelist) (%value = '333-111-1111') 引申话题:针对日期字段的索引 日期格式通常是yyyy-mm-dd,我们经常要求按照某年或者某月查询数据,我们可以使用propertynameBuildValueArray函数设定保存的索引方式实现这个目的 Class Test.Person5 Extends %Persistent { Property Name As %String; Property DOB As %Date; Index idxD On (DOB(KEYS), DOB(ELEMENTS)); ClassMethod DOBBuildValueArray(value, ByRef array) As %Status { if value="" { s array(0)=value }else{ s d=$zd(value,3) s array("yy")=+$p(d,"-",1) s array("mm")=+$p(d,"-",2) s array("dd")=+$p(d,"-",3) } q $$$OK } } 插入数据 insert into Test.Person5 (Name,DOB) select 'a', {d '2000-01-01'} union all select 'b', {d '2000-01-02'} union all select 'c', {d '2000-02-01'} union all select 'd', {d '2001-01-02'} union all select 'e', {d '2001-01-01'} union all select 'f', {d '2001-02-01'} 查看数据以及索引保存的内容 USER>zw ^Test.Person5D ^Test.Person5D=6 ^Test.Person5D(1)=$lb("","a",58074) ^Test.Person5D(2)=$lb("","b",58075) ^Test.Person5D(3)=$lb("","c",58105) ^Test.Person5D(4)=$lb("","d",58441) ^Test.Person5D(5)=$lb("","e",58440) ^Test.Person5D(6)=$lb("","f",58471) USER>zw ^Test.Person5I ^Test.Person5I("idxD","dd",1,1)="" ^Test.Person5I("idxD","dd",1,3)="" ^Test.Person5I("idxD","dd",1,5)="" ^Test.Person5I("idxD","dd",1,6)="" ^Test.Person5I("idxD","dd",2,2)="" ^Test.Person5I("idxD","dd",2,4)="" ^Test.Person5I("idxD","mm",1,1)="" ^Test.Person5I("idxD","mm",1,2)="" ^Test.Person5I("idxD","mm",1,4)="" ^Test.Person5I("idxD","mm",1,5)="" ^Test.Person5I("idxD","mm",2,3)="" ^Test.Person5I("idxD","mm",2,6)="" ^Test.Person5I("idxD","yy",2000,1)="" ^Test.Person5I("idxD","yy",2000,2)="" ^Test.Person5I("idxD","yy",2000,3)="" ^Test.Person5I("idxD","yy",2001,4)="" ^Test.Person5I("idxD","yy",2001,5)="" ^Test.Person5I("idxD","yy",2001,6)="" 执行下面 SQL 可以显示所有2月出生的信息 select * from Test.Person5 where for some %element(DOB) (%key='mm' and %value = 2) 这篇文章源自 这里,作者 Vitaliy Serdtsev
文章
姚 鑫 · 五月 30, 2021

第十一章 发送和接收IBM WebSphere MQ消息

# 第十一章 发送和接收IBM WebSphere MQ消息 InterSystems IRIS为IBM `WebSphere MQ`提供了一个接口,可以使用该接口在InterSystems IRIS和IBM `WebSphere MQ`的消息队列之间交换消息。要使用此接口,必须能够访问IBM `WebSphere MQ`服务器,并且IBM `WebSphere MQ`客户端必须与InterSystems IRIS在同一台计算机上运行。 该接口由`%Net.MQSend`和`%Net.MQRecv`类组成,这两个类都是`%Net.abstractMQ`的子类。这些类使用由InterSystems IRIS在所有合适的平台上自动安装的动态链接库。(这是Windows上的`MQInterface.dll`;其他平台的文件扩展名不同。)。反过来,InterSystems IRIS动态链接库需要IBM `WebSphere MQ`动态链接库。 该界面仅支持发送和接收文本数据,不支持二进制数据。 # 使用IBM WebSphere MQ的RIS接口 通常,要使用IBM `WebSphere MQ`的InterSystems IRIS接口,请执行以下操作: 1. 确保有权访问`IBM WebSphereMQv7.x`或更高版本。具体而言: - IBM `WebSphere MQ`客户端必须与InterSystems IRIS安装在同一台计算机上。请注意,安装程序会根据需要更新`PATH`环境变量并添加其他系统变量。 - 确保在安装客户端后重新启动计算机,以便InterSystems IRIS能够识别该客户端。 - 客户端必须能够访问IBM `WebSphere MQ`服务器。 - 将用来访问服务器的用户名必须具有使用队列管理器和计划使用的队列的权限。 2. 创建`%Net.MQSend`或`%Net.MQRecv`的新实例,具体取决于要发送还是接收消息。 3. 连接到IBM `WebSphere MQ`服务器。执行此操作时,您需要提供以下信息: - 队列管理器的名称。 - 要使用的队列的名称。 - 与该队列通信的通道。可以指定IBM `WebSphere MQ`服务器的通道名称、传输机制以及IP地址和端口。 如果正在使用IBM `WebSphere MQ`的身份验证功能,还可以提供名称和密码。 4. 调用`%Net.MQSend`或`%Net.MQRecv`的相应方法来发送或接收消息。 注意:要在64位Linux平台上使用IBM `Websphere MQ`,必须设置`LD_LIBRARY_PATH`以包括`MQ`库的位置。因为必须为任何使用`MQ`接口的InterSystems IRIS进程设置路径,所以如果正在运行后台进程,则必须在启动InterSystems IRIS之前设置该路径,并在运行IRIS终端之前在任何UNIX®终端中设置该路径。 ## 获取错误代码 `%Net.MQSend`和`%Net.MQRecv`的方法如果成功则返回1,如果不成功则返回0。在出现错误的情况下,调用`%GetLastError()`方法,该方法返回IBM `WebSphere MQ`给出的最后一个原因代码。 # 创建连接对象 在可以通过IBM `WebSphere MQ`发送或接收消息之前,必须创建一个`Connection`对象,该对象可以建立到队列管理器的连接、打开通道和打开队列以供使用。有两种方法可以做到这一点: - 可以使用`%Init`方法,该方法接受指定所有所需信息的参数。 - 可以在首次设置指定所有所需信息的属性后使用`%Connect`方法。 ## 使用%Init()方法 要使用`%Init()`方法创建连接对象,请执行以下操作: 1. 创建`%Net.MQSend`(如果要发送消息)或`%Net.MQRecv`(如果要接收消息)的实例。本主题将此实例称为连接对象。 注意:如果收到 ``错误,则表示缺少动态链接库,并且`messages.log`文件(在系统管理器的目录中)有更多详细信息。 2. 如果需要身份验证,请设置`Connection`对象的以下属性: - 用户名-指定有权使用此频道的用户名。 - 密码-指定给定用户的密码。 3. 调用`Connection`对象的`%Init()`方法。此方法按顺序接受以下参数。 a. 指定队列名称的字符串;这应该是指定队列管理器的有效队列。 b. 指定队列管理器的字符串;它应该是IBM `WebSphere MQ`服务器上的有效队列管理器。 如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认队列管理器。或者,如果IBM `WebSphere MQ`已配置为队列管理器由队列名称确定,则系统将使用适合给定队列名称的队列管理器。 c. 指定频道规范的字符串,格式如下: ```java "channel_name/transport/host_name(port)" ``` 这里,`channel_name`是要使用的通道的名称,`Transport`是通道使用的传输,`host_name`是运行IBM `WebSphere MQ`服务器的服务器名称(或IP地址),`port`是该通道应该使用的端口。 传输可以是以下之一:`TCP`、`LU62`、`NETBIOS`、`SPX` 例如: ```java "CHAN_1/TCP/rodan(1401)" ``` ```java "CHAN_1/TCP/127.0.0.1(1401)" ``` 如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认通道规范。或者,如果系统已配置为通道由队列名称确定,则系统使用适合给定队列名称的通道。 d. 一个可选字符串,它指定要向其中写入错误消息的日志文件。默认情况下,不进行日志记录。 4. 检查`%Init()`方法返回的值。如果该方法返回1,则表明连接已成功建立,可以使用`Connection`对象发送或接收消息(具体取决于使用的类)。 ## 使用%Connect()方法 在某些情况下,可能更喜欢单独指定连接的所有详细信息。为此,请使用`%Connect()`方法,如下所示: 1. 创建`%Net.MQSend`(如果要发送消息)或`%Net.MQRecv`(如果要接收消息)的实例。如前所述,本主题将此实例称为连接对象。 注意:如果收到`` 错误,则表示缺少动态链接库,并且`messages.log`文件(在系统管理器的目录中)有更多详细信息。 2. 设置`Connection`对象的以下属性: - `QName`-(必选)指定队列名称;这应该是指定队列管理器的有效队列。 - `QMgr`-指定要使用的队列管理器;它应该是IBM `WebSphere MQ`服务器上的有效队列管理器。 如果省略此参数,系统将使用IBM `WebSphere MQ`中配置的默认队列管理器。或者,如果IBM `WebSphere MQ`已配置为队列管理器由队列名称确定,则系统将使用适合给定队列名称的队列管理器。 3. 或者,通过设置`Connection`对象的以下属性来指定要使用的频道: - `Connection` - 指定IBM `WebSphere MQ`服务器的主机和端口。例如:`"127.0.0.1:1401"`。 - `Channel` - 指定要使用的频道的名称。这必须是IBM WebSphere MQ服务器上的有效通道。 - `Transport` - 指定通道使用的传输。此属性可以是以下之一: `"TCP"`, `"LU62"`, `"NETBIOS"`, `"SPX"` 如果省略这些参数,系统将使用IBM `WebSphere MQ`中配置的默认通道规范。或者,如果系统已配置为通道由队列名称确定,则系统使用适合给定队列名称的通道。 4. 如果频道需要身份验证,请设置`Connection`对象的以下属性: - 用户名-指定有权使用此频道的用户名。 - 密码-指定给定用户的密码。 5. 调用`Connection`对象的`%ErrLog()`方法。此方法接受一个参数,即要用于此连接对象的日志文件的名称。 6. 检查`%ErrLog()`方法返回的值。 7. 调用`Connection`对象的`%Connect()`方法。 8. 检查`%Connect()`方法返回的值。如果该方法返回1,则表明连接已成功建立,可以使用`Connection`对象发送或接收消息(具体取决于您使用的类)。 # 指定字符集(CCSID) 要设置用于消息转换的字符集,请调用`Connection`对象的`%SetCharSet()`方法。指定在IBM `WebSphere MQ`中使用的整数编码字符集`ID(CCSID)`。 - 如果正在发送消息,这应该是这些消息的字符集。如果不指定字符集,则MQ系统假定消息使用为`MQ`客户端指定的默认字符集。 - 如果要检索邮件,则这是要将这些邮件翻译为的字符集。 要获取当前正在使用的`CCSID`,请调用`%charset()`方法。此方法通过引用返回`CCSID`,并返回1或0以指示是否成功. # 指定其他消息选项 要指定消息描述符选项,可以选择设置连接对象的以下属性: - `ApplIdentityData`指定应用程序标识消息描述符选项。 - `PutApplType`指定`PUT Application Type`消息描述符选项。 ## 发送消息 要发送邮件,请执行以下操作: 1. 按照“创建连接对象”中的说明创建连接对象。在这种情况下,请创建`%Net.MQSend`的实例。`Connection`对象有一个消息队列,可以向该队列发送消息。 2. 根据需要调用以下方法: - `%put()`-给定一个字符串,此方法将该字符串写入消息队列。 - `%PutStream()`-给定初始化的文件字符流,此方法将该字符串写入消息队列。请注意,必须设置流的`Filename`属性才能对其进行初始化。不支持二进制流。 - `%SetMsgId()`-给定一个字符串,此方法使用该字符串作为发送的下一条消息的消息ID。 3. 检查调用的方法返回的值。 4. 检索完消息后,调用`Connection`对象的`%Close()`方法以释放动态链接库的句柄。 示例1:`SendString()` 下面的类方法使用队列管理器`QM_antigua`和名为 `S_antigua`的队列通道向队列`mqtest`发送一条简单的字符串消息。通道使用TCP传输,IBM `WebSphere MQ`服务器运行在名为`Antigua`的机器上,并侦听端口1401。 ```java ///Method returns reason code from IBM WebSphere MQ ClassMethod SendString() As %Integer { Set send=##class(%Net.MQSend).%New() Set queue="mqtest" Set qm="QM_antigua" Set chan="S_antigua/TCP/antigua(1414)" Set logfile="c:\mq-send-log.txt" Set check=send.%Init(queue,qm,chan,logfile) If 'check Quit send.%GetLastError() //send a unique message Set check=send.%Put("This is a test message "_$h) If 'check Quit send.%GetLastError() Quit check } ``` 示例2:`SendCharacterStream()` 下面的类方法发送文件字符流的内容。它使用的队列与上一个示例中使用的队列相同: ```java ///Method returns reason code from IBM WebSphere MQ ClassMethod SendCharacterStream() As %Integer { Set send=##class(%Net.MQSend).%New() Set queue="mqtest" Set qm="QM_antigua" Set chan="S_antigua/TCP/antigua(1414)" Set logfile="c:\mq-send-log.txt" Set check=send.%Init(queue,qm,chan,logfile) If 'check Quit send.%GetLastError() //initialize the stream and tell it what file to use Set longmsg=##class(%FileCharacterStream).%New() Set longmsg.Filename="c:\input-sample.txt" Set check=send.%PutStream(longmsg) If 'check Quit send.%GetLastError() Quit check } ``` 示例3:从终端发送消息 以下示例显示了向IBM `WebSphere MQ`队列发送消息的终端会话。这只能在配置了IBM `WebSphere MQ`客户端的计算机上运行。 ```java Set MySendQ = ##class(%Net.MQSend).%New() Do MySendQ.%Init("Q_1", "QM_1","QC_1/TCP/127.0.0.1(1401)","C:\mq.log") Do MySendQ.%Put("Hello from tester") Set MyRecvQ =##class(%Net.MQRecv).%New() Do MyRecvQ.%Init("Q_1", "QM_1","QC_1","C:\mq.log") Do MyRecvQ.%Get(.msg, 10000) Write msg,! ```
文章
姚 鑫 · 五月 29, 2021

第十章 使用FTP

# 第十章 使用FTP IRIS提供了一个类`%Net.FtpSession`,可以使用它从InterSystems IRIS内建立与FTP服务器的会话。 # 建立FTP会话 要建立FTP会话,请执行以下操作: 1. 创建`%Net.FtpSession`的实例。 2. 可以选择设置此实例的属性,以控制会话的常规行为: - `Timeout` 超时指定等待FTP服务器回复的时间(以秒为单位)。 - `SSLConfiguration`指定用于连接的激活的`SSL/TLS`配置(如果有)。如果`FTP`服务器使用HTTPS,请使用此选项。 - `TranslateTable`指定在读取文件内容或写入文件内容时要使用的转换表。 - `UsePASV`启用PASV模式。 - 当`FTP`服务器使用`https`时,`SSLCheckServerIdentity`适用。默认情况下,当`%Net.FtpSession`的实例连接到`SSL/TLS`服务器时,它会检查证书服务器名称是否与用于连接到服务器的DNS名称匹配。如果这些名称不匹配,则不允许连接。 若要禁用此检查,请将`SSLCheckServerIdentity`属性设置为0。 3. 调用`Connect()`方法以连接到特定的FTP服务器。 4. 调用`ascii()`或`binary()`方法将传输模式分别设置为ASCII模式或二进制模式。要查看当前传输模式,请检查实例的Type属性的值。 注意:`%Net.FtpSession`的每个方法都返回一个状态,应该检查该状态。这些方法还设置提供有关会话状态的有用信息的属性的值: - 如果当前已连接,则`CONNECTED`为TRUE,否则为FALSE。 - `ReturnCode`包含上次与FTP服务器通信时的返回代码。 - `ReturnMessage`包含上次与FTP服务器通信时的返回消息。 `Status()`方法返回(通过引用)FTP服务器的状态。 ## 命令的转换表 `%Net.FtpSession`在FTP服务器上查看文件名和路径名时,使用`RFC 2640`中介绍的技术自动处理字符集转换。当`%Net.FtpSession`的实例连接到FTP服务器时,它会使用Feat消息来确定服务器是否使用`UTF-8`字符。如果是,它将命令通道通信切换到`UTF-8`,以便所有文件名和路径名都可以正确地与`UTF-8`相互转换。 如果服务器不支持`FEAT`命令或未报告支持`UTF-8`,`%Net.FtpSession`实例将使用`RAW`模式并读取或写入RAW字节。 在极少数情况下,如果需要指定要使用的转换表,请设置`%Net.FtpSession`实例的`CommandTranslateTable`属性。一般情况下,应该没有必要使用此属性。 # FTP文件和系统方法 一旦建立了FTP会话,就可以调用会话实例的方法来执行FTP任务。`%Net.FtpSession`提供以下读写文件的方法: ### Delete() 删除文件。 ### Retrieve() 将文件从FTP服务器复制到InterSystems IRIS流中,并通过引用返回该流。要使用此流,请使用标准流方法:`Write()`、`WriteLine()`、`Read()`、`ReadLine()`、`Rewind()`、`MoveToEnd()`和`Clear()`。还可以使用流的`Size`属性。 ### RetryRetrieve() 允许继续检索文件,因为给定的流是由上一次使用`Retrieve()`创建的。 ### Store() 将 IRIS流的内容写入FTP服务器上的文件。 ### Append() 将流的内容追加到指定文件的末尾。 ### Rename() 重命名文件。 此外,`%Net.FtpSession`提供了导航和修改FTP服务器上的文件系统的方法:`GetDirectory()`、`SetDirectory()`、`SetToParentDirectory()`和`MakeDirectory()`。 要检查文件系统的内容,请使用`list()`或`NameList()`方法。 - `List()`创建一个流,其中包含其名称与给定模式匹配的所有文件的列表,并通过引用返回该流。 - `NameList()`创建文件名数组并通过引用返回该数组。 还可以使用`ChangeUser()`方法更改为其他用户;这比注销并再次登录要快。使用`Logout()`方法注销。 `System()`方法返回(通过引用)有关托管FTP服务器的计算机类型的信息。 `Size()`和`MDTM()`方法分别返回文件的大小和修改时间。 使用通用`sendCommand()`方法向FTP服务器发送命令并读取响应。此方法可用于发送`%Net.FtpSession`中未明确支持的命令。 # 使用链接的流上载大文件 如果要上传大文件,请考虑使用流接口的`LinkToFile()`方法。也就是说,不是创建流并将文件读入其中,而是创建流并将其链接到文件。在调用`%Net.FtpSession`的`Store()`方法时使用此链接流。 ```java Method SendLargeFile(ftp As %Net.FtpSession, dir As %String, filename As %String) { Set filestream=##class(%FileBinaryStream).%New() Set sc=filestream.LinkToFile(dir_filename) If $$$ISERR(sc) {do $System.Status.DisplayError(sc) quit } //上传的文件将与原始文件同名 Set newname=filename Set sc=ftp.Store(newname,filestream) If $$$ISERR(sc) {do $System.Status.DisplayError(sc) quit } } ``` # 自定义FTP服务器发出的回调 可以自定义`FTP`服务器生成的回调。例如,通过这样做,可以向用户提供服务器仍在处理大型传输的指示,或允许用户中止传输。 要自定义FTP回调,请执行以下操作: 1. 创建`%Net.FtpCallback`的子类。 2. 在这个子类中,实现`RetrieveCallback()`方法,该方法在从FTP服务器接收数据时定期调用。 3. 还要实现`StoreCallback()`方法,在将数据写入FTP服务器时会定期调用该方法。 4. 创建`FTP`会话时(如“建立FTP会话”中所述),将回调属性设置为等于的子类`%Net.FtpCallback`。
文章
姚 鑫 · 五月 27, 2021

第八章 处理收到的电子邮件

# 第八章 处理收到的电子邮件 # 处理收到的电子邮件 本节介绍如何处理通过`%Net.POP3`检索到的电子邮件(`%Net.MailMessage`)。 ## Message Basics 检索电子邮件(`%Net.MailMessage`)后,通常首先确定它是哪种类型的邮件以及如何阅读它;也就是说,它是否是多部分邮件以及各部分是否是二进制的。在此步骤中,您可以使用`ContentType`属性。或者,可以使用`IsBinary`、`IsHTML`和`IsMultiPart`属性,它们间接提供与`contentType`相同的信息。 如果消息是多部分消息,则每个部分都是`%Net.MailMessagePart`的一个实例。 ## Message Headers 消息本身和消息的每个部分都有一组标头。 `%Net.MailMessage`和`%Net.MailMessagePart`类提供的属性使可以轻松访问最常用的标头。例如,`%Net.MailMessage`提供收件人、发件人、主题和日期等属性。`Headers`数组属性允许访问任何自定义标题. 此外,如果已通过`%Net.POP3`检索到消息,则可以使用`GetAttribute()`方法。在给定标头名称和属性的情况下,此方法返回该属性的值。 ## Message Contents 了解常规消息结构后,请使用以下技术检索内容: - 对于多部分消息,请使用`Parts`属性,该属性是部分的数组。`Parts.Count()`给出部件的数量。每个部件的键都是一个整数,从1开始。使用`GetAt()`方法检索给定的部件。消息部分是`%Net.MailMessagePart`的实例。 - 对于二进制消息(或消息部分),请使用`BinaryData`属性。 - 对于文本消息(或消息部分),请使用`TextData`属性。 - 如果`IsHTML`为0,则`TextData`属性为普通文本字符串。 - 如果`IsHTML`为1,则`TextData`属性为HTML文本字符串。 请注意,发送邮件的电子邮件客户端确定邮件中的任何包装。邮件服务器无法控制这一点, ## 其他消息信息 `MessageSize`属性表示邮件的总长度(不包括任何附加的电子邮件)。 以下方法提供有关消息的其他信息: ### GetLocalDateTime() 返回检索消息的日期和时间,并转换为`$HOROLOG`格式的本地时间。 ### GetUTCDateTime() 返回检索消息的日期和时间,并以`$HOROLOG`格式转换为UTC。 ### GetUTCSeconds() 返回自1840年12月31日以来检索消息的日期和时间(秒)。 以下类方法也可用于时间/日期转换: ### HToSeconds() 将`$HOROLOG`格式的日期/时间转换为自1840年12月31日以来的秒的类方法。 ### SecondsToH() 将自1840年12月31日以来的秒数转换为`$HOROLOG`格式的日期/时间的类方法。 示例1:`ShowMsgInfo()` ```java ClassMethod ShowMsgInfo(msg as %Net.MailMessage) { Write "Message details *****",! Write "To (count): ", msg.To.Count(),! Write "From: ", msg.From,! Write "Cc (count): ", msg.Cc.Count(),! Write "Bcc (count): ", msg.Bcc.Count(),! Write "Date: ", msg.Date,! Write "Subject: ", msg.Subject,! Write "Sender: ", msg.Sender,! Write "IsMultipart: ", msg.IsMultiPart,! Write "Number of parts: ", msg.Parts.Count(),! Write "Number of headers: ", msg.Headers.Count(),! Write "IsBinary: ", msg.IsBinary,! Write "IsHTML: ", msg.IsHTML,! Write "TextData: ", msg.TextData.Read(),! Write "BinaryData: ", msg.BinaryData.Read(),! } ``` 此方法产生类似于以下内容的输出: ```java Message details ***** To (count): 1 From: "XXX XXX" Cc (count): 0 Bcc (count): 0 Date: Fri, 16 Nov 2007 11:57:46 -0500 Subject: test 5 Sender: IsMultipart: 0 Number of parts: 0 Number of headers: 16 IsBinary: 0 IsHTML: 0 TextData: This is test number 5, which is plain text. BinaryData: ``` 示例2:`ShowMsgPartInfo()` 以下方法写入有关消息一部分的信息: ```java ClassMethod ShowMsgPartInfo(msg as %Net.MailMessage, partno as %Integer) { Set part=msg.Parts.GetAt(partno) Write "Message part details *****",! Write "Message part: ", partno,! Write "IsMultipart: ", part.IsMultiPart,! Write "Number of parts: ", part.Parts.Count(),! Write "Number of headers: ", part.Headers.Count(),! Write "IsBinary: ", part.IsBinary,! Write "IsHTML: ", part.IsHTML,! Write "TextData: ", part.TextData.Read(),! Write "BinaryData: ", part.BinaryData.Read(),! } ``` 这将产生与以下内容类似的输出(给定的消息与前面显示的不同): ```java Message part details ***** Message part: 1 IsMultipart: 0 Number of parts: 0 Number of headers: 2 IsBinary: 0 IsHTML: 0 TextData: 1 test string BinaryData: ``` 示例3:`ShowMsgHeaders()` 下面的方法写入有关消息头的信息;可以编写一个类似的方法,对消息部分执行相同的操作。 ```java ClassMethod ShowMsgHeaders(msg as %Net.MailMessage) { Set headers=msg.Headers Write "Number of headers: ", headers.Count(),! //iterate through the headers Set key="" For { Set value=headers.GetNext(.key) Quit:key="" Write "Header:",key,! Write "Value: ",value,!! } } ``` 这将产生类似于以下内容的输出: ```java Number of headers: 16 Header: content-class Value: urn:content-classes:message Header: content-type Value: multipart/alternative; boundary="----_=_NextPart_001_01C8286D.D9A7F3B1" Header: date Value: Fri, 16 Nov 2007 11:29:24 -0500 Header: from Value: "XXX XXX" Header: message-id Value: Header: mime-version Value: 1.0 ... ``` # 自动编码和字符翻译 电子邮件部分包含有关使用的字符集和使用的内容传输编码(如果有的话)的信息。作为参考,本节介绍如何使用此信息。 ## 外发电子邮件 `%Net.SMTP`检查每个部分的字符集属性,然后应用适当的转换表。 如果未指定给定部件的字符集属性,InterSystems IRIS将使用UTF-8。 `%Net.SMTP`还检查`ContentTransferEncoding`属性。如果此属性为 `"base64"`或`"quoted-printable"`,则在创建消息时,`%Net.SMTP`会根据需要对正文进行编码。(如果内容传输编码为 `"7bit"` 或 `"7bit"`,则不需要编码。) 重要提示:请注意,如果内容为`“Base64”`编码,则不能包含任何`Unicode`字符。如果要发送的内容包括`Unicode`字符,请确保使用`$ZCONVERT`将内容转换为UTF-8。 ## 传入电子邮件 `%Net.POP3`检查每个邮件部分的`Content-Transfer-Encoding`标头,并根据需要对正文进行解码。 然后`%Net.POP3`检查每个邮件部分的`Content-Type`标头。这会影响消息部分的字符集属性,还会控制在InterSystems IRIS中创建消息部分时使用的转换表。
问题
kun an · 五月 27, 2021

按照官方教程Java QuickStart章节中下载的示例程序 xep方式访问不了

按照此网址的指示 https://gettingstarted.intersystems.com/language-quickstarts/java-quickstart/ 下载quickstarts-java示例代码 运行xepplaystocktsTask1模块程序提示InterSystems XEP is not supported by the specified server 请问有人知道具体原因吗我的server有什么不对吗。 使用客户端的server manager添加server没有server类型的选项,是因为我使用的cache版本目前不支持吗 不知您测试使用的具体是IRIS哪个版本,以及运行在哪个操作系统上。 还有提到的客户端使用的是哪个IRIS版本。低版本的客户端没法连上高版本的IRIS服务端,Caché客户端更加连不上IRIS的服务器。 您好 感谢解答。我使用的是IRISHealth_Community-2020.1.0.217.1-win_x64 运行在windows10上。我在官网教程上下载的示例代码,其余访问方式都运行正常就xep方式报错, 提示指定的server不支持, 不知道都有什么类型的server,哪些server可以支持 请参考下面资料检查是否符合运行需求以及相关配置是否正确:https://docs.intersystems.com/irisforhealth20201/csp/docbook/Doc.View.cls?KEY=BJAVXEP_intro#BJAVXEP_intro_config 其中的检查包括JDK版本、安装时的选项、服务%Service_CallIn是否打开以及环境变量CLASSPATH 的设置
文章
Michael Lei · 五月 26, 2021

Intersystems IRIS 安装手册

https://www.intersystems.com/isc-resources/wp-content/uploads/sites/24/InterSystems-IRIS%E6%95%B0%E6%8D%AE%E5%B9%B3%E5%8F%B0%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97-20200531.pdf 怎么访问不了呢,404 最新版安装指南请参考:Linux 系统IRIS安装总结 谢谢,我问下有虚拟机分区的部分,应该怎么分区呢 看您是什么操作系统,Linux的话可以用fdisk命令进行分区。