本文共 19269 字,大约阅读时间需要 64 分钟。
简介: 本文描述 Claim Check 模式,并向您展示如何在 Service Component Architectur 上下文中使用该模式。一个样例应用程序向您展示如何使用 WebSphere® Integration Developer V6.2.0.1 实现模式并在 WebSphere Process Server V6.2.0.1 或更高版本上运行它。
为使应用程序高效运行,您不希望它携带多余数据 —— 应用程序不需要的数据。携带过多的数据有一些负面影响,这包括增加的内存使用率、数据模型的紧耦合,以及 Java™ 环境中增多的垃圾回收。这些会导致更频繁的应用程序版本控制。
但是,您的应用程序很多时候没有仅选择所需数据的权利。例如,您的应用程序可能与标准相符,且需要使用一个行业标准消息格式作为其接口。这往往会很大且很复杂,这样它们才能为设计的业务处理所有用例。然而,您的应用程序只需要该行业标准消息上的少量数据来达到处理目的。幸运的是,应用程序设计人员学习并记录了一种好方法,可以使用 Claim Check 模式处理这个问题。
Claim Check 背后的理念很简单:
使用一个真实类比,当您乘飞机旅行时,要签入托运大件行李且只要在到达中转点或目的地时才领取它们。Claim Check 模式基本上适用于这个生活常识和 IT 有效实践。图 1 从概念上解释了 Claim Check 的运作方式。在图中,“M” 表示一个应用程序的输入消息,“A” 表示输入消息包含的大型附件内容。
在签入期间,附件存储在一个永久性数据存储中且返回一个 “T” 令牌。“T” 要存储在某个地方,在图 1 中,它是作为消息 “M” 的一部分被存储的。然后轻量级消息 “M” 由应用程序处理,在此期间可能发生转换。
应用程序输出一个转换后的消息 “M**”。在进一步处理之前(例如,调用另一个应用程序),当使用令牌 “T” 从数据存储中检索附件 “A” 且将 “A” 附着于转换后的消息 “M**” 时,就发生了签出。注意,图 1 从概念上解释了 Claim Check。
在现实中,应用程序可以在需要附件时签出附件 “A”。“签入” 和 “签出” 组件不一定是应用程序的一部分。签出附件 “A” 之后,不一定会立即从数据存储中删除它。
欲了解关于 Claim Check 模式的更多信息,请参阅 部分中列出的集成模式图书。
在应用 Claim Check 模式时,不管底层平台是什么,都需要考虑以下三方面:
首先,我们使用术语 “附件” 表示希望凭证索取的数据。附件可以是一个 PDF 或 DOC 文件、一个 XLS 电子表格、一幅二进制图像,或一个视频或音频多媒体文件。大多数情况下,您的应用程序根本无需处理附件。因此,最好尽早分离附件并尽可能晚地重新附着它,且仅在需要时才重新附着。一个附件示例是一个大型工程绘图。单个附件 vs. 多个附件 仅表示是否只有一段数据(通常是输入消息中的一个字段)您需要凭证索取,或是否有多段数据您需要凭证索取。
逻辑附件 是指附件在消息中存储时,其字段或位置不是由供附件显式使用的消息架构定义的。一些消息传送标准有在消息内定义显式字段或位置的架构,用于存储附件。一个示例就是 Web 服务标准。当一条消息内一个附件的位置由消息架构良好定义时,我们将该附件看作本文所讲的物理附件。
凭证索取的目的是要提高效率。当应用程序不需要的数据被分离时,应用程序就会在仅携带所需数据的情况下运行,因而更有效。不过,较少的数据不一定表示应用程序可以轻松导航到它需要的数据。如果应用程序要处理的消息有一个复杂的架构,应用程序获取其需要的数据就要做更多的工作。因此,在应用凭证索取模式时,为何不一并考虑最大限度地降低应用程序所需的导航?为此,除了凭证索取应用程序不需要的数据之外,您可以将其余数据映射到一个更小且轻量级的业务对象中,让应用程序处理该业务对象。
应用凭证索取的一个现实示例是,处理遵循某个行业标准(比如 ACORD)的一条的输入消息。应用程序只需要使用大型 ACORD XML 消息的一些分支中的数据子集。可凭证索取大型 ACORD XML 消息的其余分支和消息附件。
本文使用了一个样例场景来展示凭证如何索取逻辑附件和物理附件。本文随带的 展示了样例场景,并包含一个凭证索取服务,您可以将其作为基础来开发自己的应用程序。
客户很多时候会问,他们为何需要使用 Claim Check 模式且何时使用它。毕竟,在使用 64-bit JVMs 时,WebSphere Process Server(以下简称 Process Server)和 WebSphere Enterprise Service Bus (ESB) 都可以利用数千兆字节的堆内存,这表示,它们可以处理上百兆字节的一条消息或几十兆字节的多条消息。一般而言,我们不推荐通过 Process Server 和 WebSphere ESB 传递大容量消息,特别是在它们没有多少用处时。
Process Server 和 WebSphere ESB 拥有显式功能来处理附件,如 一文所述。但是,仅仅因为您可以做某件事情,并不代表您应该去做。
那么何时应用 Claim Check 模式呢?首先,想象您在使用 Process Server 和 WebSphere ESB 构建什么类型的解决方案。相关背景知识,请参阅 。
最关键的问题是:
决策过程参见图 1A 中的流程图。
阐释了逻辑和物理附件的处理。它包含 4 个模块:
ClaimCheck 模块是 Claim Check 服务的一个样例实现。它实现 ClaimCheckIntf 接口,包含三个操作:一个用于签入附件,一个用于签出附件,还有一个用于清理存储附件的永久性数据存储。在 中,文件系统用作持久性数据存储。凭证索取服务使用一个平面文件适配器来从文件系统中读写附件。
当一个调用方需要签入一个附件时,它调用 Claim Check 服务,传入一个 ClaimCheckObject 类型的数据对象。Claim Check 服务返回 TicketEnvelope 类型的一个令牌给调用方。在样例应用程序中,由于文件系统用于存储附件,返回给调用方的令牌是写入附件内容的文件的名称。调用方需要存储令牌,这样一来,稍后就可以使用它从 Claim Check 服务中检索附件。在样例应用程序中,令牌存储在数据对象中,存储在分离附件所基于的同一字段中。最后,当调用方需要签出附件时,它使用令牌调用 Claim Check 服务,附件返回调用方。
尽管样例应用程序为简便而使用文件系统作为永久性数据存储,正如您稍后就看到的,我们在 ClaimCheck 模块内提供了逻辑,来阐释如何使用附加存储类型,比如一个队列或一个数据库。由于我们的样例应用程序中的永久性数据存储和附件不计划长期维护,为了避免不必要的存储尺寸增长,在签出附件之后需要将其清除。Claim Check 服务样例提供了一个操作,支持了客户端在索取附件之后将其从数据存储中删除。客户端需要显式调用这个操作来从数据存储中删除过期的附件数据。
OrderProcessing 模块实现一个简单的中介,将 GenericOrder 和 ProductItem 类型的两个独立对象作为输出,并生成 Order 类型的一个对象作为输出。OrderProcessing 模块内的中介逻辑接受 ProductItem 对象并将其转化成 Order 对象的一个逻辑附件。然后 OrderProcessing 模块使用 Order 对象调用 OrderToShipment 模块。
OrderToShipment 模块包含样例应用程序的大部分逻辑。逻辑分为两个主要部分。第一部分使用 Claim Check 服务处理逻辑附件的签入和签出,而第二部分为物理附件执行同样的功能。
图 2 描述 OrderToShipment 模块中的第一部分逻辑。
ProcessOrderService 导出(在图 2 中标记为 “1”)调用 ClaimCheckDataHandler,这是一个自定义数据处理程序,有一个名为 CheckinConfiguration 的数据处理程序配置。数据处理程序将逻辑附件从 Order 数据对象中分离出来,并调用 Claim Check 服务来签入逻辑附件。当 Claim Check 服务返回一个令牌时,令牌存储在 Order 数据对象中,存储在过去用于存储逻辑附件的同一字段中。CreateShipment 中介将 Order 数据对象转换成 ShipmentRequisition 数据对象。令牌也被复制到 ShipmentRequisition 数据对象中。
ProcessShipment 导入(在图 2 中标记为 “2”)使用另一个名为 CheckoutConfiguration 的数据处理程序配置调用 ClaimCheckDataHandler。数据处理程序使用存储在 ShipmentRequisition 内的令牌调用 Claim Check 服务,以签出逻辑附件。ShipmentRequisition 内的令牌的位置在 CheckoutConfiguration 中指定。当 Claim Check 服务返回逻辑附件时,数据处理程序将逻辑附件附加在 ShipmentRequisition 数据对象上。最后,ProcessShipment 调用 ShipmentProcessing 模块,将其传递给带逻辑附件的 ShipmentRequisition 数据对象。
图 3 描述 OrderToShipment 模块中的第二部分逻辑,该部分处理物理 Web 服务(SOAP) 附件的签入和签出。
OrderToShipment 模块的导出可由任何 Web 服务客户端调用。客户提供一个 Order Web 服务消息,将物理附件作为输入。ProcessIncomingAttachment 中介(在图 3 中标记为 “1”)分离 Web 服务附件并通过调用 Claim Check 服务签入附件。当 Claim Check 服务返回一个令牌时,令牌存储在 Order 数据对象内,存储在过去用于存储物理附件的同一字段中。CreateWSShipment 中介将 Order 数据对象转化为一个 ShipmentRequisition 数据对象。
ProcessOutgoingAttachment 中介(在图 3 中标记为 “2”)使用令牌调用 Claim Check 服务,通过这种方式签出物理附件。当 Claim Check 服务返回物理附件时,ProcessOutgoingAttachment 将物理附件附加到 ShipmentRequisition 数据对象并使用它调用 ShipmentProcessing 模块。
比较图 2 和图 3,会发现前者处理逻辑附件,而后者处理物理附件,除此之外还有两个主要区别。第一个区别是,在图 2 中使用了 OrderProcessing 模块而在图 3 中没有。OrderProcessing 模块在逻辑附件场景中充当测试客户端的角色,以逻辑附件为输入创建一个 Order 数据对象到 OrderToShipment 模块中。
在物理附件场景中,使用 WebSphere Integration Developer(以下简称 Integration Developer)测试客户端发送一个带物理附件的 Web 服务(SOAP)消息是很简单的,因此不需要 OrderProcessing 模块。因此,第一个区别是由于我们尝试使样例应用程序易于测试而出现的,且它对 Claim Check 模式解决方案的设计没有任何意义。图 2 与图 3 的第二个区别在于,对于逻辑附件,自定义数据处理程序用于调用 Claim Check 服务,而对于物理附件,则未使用自定义数据处理程序。
Claim Check 服务由 ProcessIncomingAttachment 和 ProcessOutgoingAttachment 这两个中介调用。这第二个区别对于 Claim Check 模式解决方案的设计很重要。它是因 SCA Web 服务绑定实现的一个当前限制产生的。正如 部分所提,最好尽早分离附件并尽量晚地重新附着它。因此,通过自定义数据处理程序在输出和输入中调用 Claim Check 服务是一个很好的设计。不过,对于一个 Web 服务物理附件,Integration Developer 和 WebSphere ESB 目前不支持同样的方法。因此,我们选择直接从图 3 中的中介调用 Claim Check 服务。
ShipmentProcessing 模块记录样例应用程序处理的结果。它被实现为一个 Java 组件,该组件将接收到的数据写到系统输出上。如果应用程序运行正确,写到测试环境系统输出文件的消息包含数据对象的序列化 XML 内容,包括签出的附件。
在本节中。我们描述 Claim Check 服务实现。我们首先将解释使用的接口和接口上的数据类型。然后,我们将描述 Claim Check 服务中的请求和响应流,然后描述样例应用程序中 Claim Check 使用的底层平面文件数据存储的配置。
将 Claim Check 作为一个名为 “ClaimCheck” 的 SCA 模块予以实现。它使用一个名为 ClaimCheckExport 的 SCA 导出作为入口点,如图 4 所示。
图 5 显示,ClaimCheckExport 通过三个操作将 ClaimCheckIntf 接口公开给客户端:
ClaimCheckObject 有两个元素,如图 6 所示:
TicketEnvelope 有两个元素,如图 7 所示:
中介组件 ClaimCheckAdapterMapper 的请求流实现对于 ClaimCheckIntf 接口上的三个操作都是类似的,且包含两个步骤(见图 8):
中介组件 ClaimCheckAdapterMapper 的请求流实现对于 checkin 和 checkout 操作是类似的(参见图 9 和图 10)。请求流包括平面文件接口 FlatFileImport1 和凭证索取服务接口 ClaimCheckIntf 使用的业务对象的转换。cleanup 操作是一种单向操作,因而没有响应流。
图 11 中对 EIS 平面文件导入绑定组件 FlatFileStore 进行配置,以将 ClaimCheckObject 以 XML 格式写到 C:\FlatFilesAny 的文件系统位置。每个附件的文件名也在 EIS 绑定配置中得到定义。“Default target file name” 定义文件名的常量部分。作为文件名后缀的顺序索引由绑定生成,且存储在 “Sequence file” 指定的文件中。
FlatFileStore 使用特定适配器生成的接口 FlatFileImport1(见图 12)。在 FlatFileImport1 接口定义的操作与 ClaimCheckIntf 接口定义的操作之间有一个一对一的映射(参见 )。文件名由 FlatFileImport1 接口的 Create 操作自动返回。然后样例应用程序将该文件名用作一个索取令牌,用于签出附件。
retrieveFlatFile 操作将包装在 FlatFile 数据对象中的文件名作为输出,然后返回在输出目录中找到的给定名称的文件(参见图 11 中的 “Output directory” 字段)。deleteFlatFile 操作也将包装在 FlatFile 数据对象中的文件名作为输出,然后从输出目录中删除给定名称的文件。
平面文件导入绑定组件 FlatFileStore 是使用 EIS 外部服务发现构建的,该服务通过 File > New > External Service 菜单调用。Integration Developer 文档提供了有关如何创建和使用 EIS 绑定的扩展文档,比如 。
ClaimCheck 模块对于逻辑附件是从一个数据处理程序()被调用,而对于物理附件则是从自定义中介原语()被调用。两种情况都使用 Java 代码来调用 Claim Check 服务。为了封装大部分服务特定调用代码,一个名为 ClaimCheckInvoker 的 Java 类被创建,以供数据处理程序和自定义中介原语作为外观使用。您可以打开以下文件从 J2EE 角度查看 ClaimCheckInvoker 的源码:OrderToShipment/gen/src/text.handler/ClaimCheckInvoker.java.
ClaimCheckInvoker 实现一个以 SCA 引用伙伴名为参数的构造函数(参见 )。checkIn 方法通过调用 Claim Check 服务允许客户端检查附件。checkIn 方法调用自数据处理程序()和自定义中介(),后者以 DataObject 类型的附件作为输入参数,且使用存储类型来签入附件。它使用引用伙伴名定位 Claim Check 服务。然后它创建包装 ClaimCheckObject 数据对象并在包装中设置作为 DataObject 传入的附件。它还设置用于存储附件的存储类型。样例应用程序使用 FlatFile 适配器仅实现文件系统存储类型(“EF”)。最后,Claim Check 服务上的 checkin 操作被调用,且存储附件的文件名返回到调用客户端代码(清单 2)。
public class ClaimCheckInvoker{ //Wrapper Claim Check business object name and its elements private String claimCheckWrapperNamespace = "http://CommonLibrary"; private String claimCheckWrapperName = "ClaimCheckObject"; private String claimCheckDataWrappingElement = "data"; private String claimCheckSerTypeElement = "storetype"; private String serviceRefName; public ClaimCheckInvoker(String claimCheckReferenceName) { serviceRefName = claimCheckReferenceName; } //Other code in the ClaimCheckInvoker class} |
public DataObject checkIn(DataObject attachment, String storetype) |-------10--------20--------30--------40--------50--------60--------70--------80--------9||-------- XML error: The previous line is longer than the max of 90 characters ---------|{ //Get a service manager to locate the service reference. ServiceManager serviceManager = ServiceManager.INSTANCE; //Locate claim check service. Object claimCheckService = serviceManager.locateService(serviceRefName); //Locate a BO factory service to create the input data object. BOFactory boFactory = (BOFactory)serviceManager. locateService("com/ibm/websphere/bo/BOFactory"); System.out.println("Found service object: " + claimCheckService); if (claimCheckService instanceof Service) { //Now we create a new instance of the ClaimCheck service //input data object. DataObject claimCheckDataobject = boFactory.create(claimCheckWrapperNamespace, claimCheckWrapperName); //The attachment data represents a data object itself. So we use //setDataObject method to set the data. claimCheckDataobject. setDataObject(claimCheckDataWrappingElement, attachment); //Set the store type. claimCheckDataobject.setString(claimCheckSerTypeElement, storetype); //Invoke the Claim check service and return the claim token data //object that contains the file name. DataObject claimToken =(DataObject) ((Service)claimCheckService). invoke("checkin", claimCheckDataobject); System.out.println(claimToken); return claimToken; } return null;} |
ClaimCheckInvoker 类实现的另一个方法是 checkOut 方法。checkout 方法接受一个票证作为 DataObject。从数据处理程序()和自定义中介原语()调用了同样的方法。该方法也接受一个 boolean 输入参数,指明签出附件之后是否需要清理存储。它使用引用伙伴名定位 Claim Check 服务,调用 Claim Check 服务上的 checkout 方法,从 Claim Check 服务返回的对象上提取附件,根据需要清理存储,最后将附件返回给调用方。
清单 3 显示了签出附件的 checkout 方法。参考 部分中的项目交换文件,查看另一个 checkout 方法的代码。
public DataObject checkOut(DataObject ticket, boolean performCleanup)|-------10--------20--------30--------40--------50--------60--------70--------80--------9||-------- XML error: The previous line is longer than the max of 90 characters ---------|{ //Get a service manager to locate the service reference. ServiceManager serviceManager = ServiceManager.INSTANCE; //Locate claim check service. Object claimCheckService = serviceManager.locateService(serviceRefName); System.out.println("Claim token passed in: " + ticket.toString()); if (claimCheckService instanceof Service) { //In this case the ticket is a data object itself. if (ticket != null) { //Invoke the operation by passing the operation name and an //input argument. Object checkedOut = ((Service)claimCheckService).invoke("checkout", ticket); //Get the attachment checked out data object from the //wrapper. DataObject utput = ((DataObject) ((DataObject)checkedOut).get(0)). getDataObject(claimCheckDataWrappingElement); System.out.println(output); if (performCleanup) { //If the data handler is configured to clean up the storage //after the checkout then we need to invoke the cleanup //operation ((Service)claimCheckService).invoke("cleanup", ticket); } return output; } } return null;} |
本节解释 如何应用于逻辑附件场景。
该场景的入口点是 OrderProcessing 模块中的中介组件 AddLogicalAttachmentToOrder,如图 13 所示。
AddLogicalAttachmentToOrder 中介组件使用一个单向操作实现 OrderPrepareInterface 接口,该操作接受两个输入参数:GenericOrder 类型的 OrderIn 和 ProductItem 类型的 ProductItemIn(图 14)。
AddLogicalAttachmentToOrder 中介使用一个 XSL 转换将 ProductItemIn 数据对象作为逻辑附件附着到 OrdersInterface 上 Order 类型的 inputOrder 数据对象(见图 15)。图 16 显示了 XSL 转换。注意,除了在 inputOrder 数据对象中创建逻辑附件之外,orderIn 数据对象中的其他字段,比如 id 和 amount,也被复制到 inputOrder 数据对象。
带有附件的 inputOrder 数据对象创建好之后,它被传递给 HTTP 导入绑定组件 ProcessOrder(图 17)。对绑定组件进行配置以调用 OrderToShipment 模块。
请求到达 OrderToShipment 模块的 HTTP 导出绑定组件 ProcessOrderService(图 18)。
ProcessOrderService 导出被配置为使用自定义数据处理程序配置 CheckinConfiguration(图 19),而后者反过来被配置为调用自定义数据处理程序 ClaimCheckDataHandler(图 20)。
自定义数据处理程序配置 CheckinConfiguration 有很多属性:
自定义数据处理程序 ClaimCheckDataHandler 是通过其转换方法调用的。看一下代码中的注释就会明白转换方法的作用(清单 4)。转换方法调用的 ClaimCheckInvoker 在本文前面有介绍。注意,在临近转换方法的末尾,索取令牌(在我们的样例应用程序中,它是用于存储逻辑附件的文件的名称)被存储在 inputOrder 数据对象或临时上下文中。
public Object transform(Object incomingSourceStream, Class |-------10--------20--------30--------40--------50--------60--------70--------80--------9||-------- XML error: The previous line is longer than the max of 90 characters ---------| targetObjectType, Object options) throws DataHandlerException{ System.out.println("Transforming incoming message"); //Use XML Data handler to transform. the data XMLDataHandler handler = new XMLDataHandler(); //Extract attachment from the data object using the configured //element name Object currentObject = handler.transform(incomingSourceStream, targetObjectType, options); DataObject attachment = ((DataObject)((DataObject)currentObject).get(0)). getDataObject(logicalAttachmentElement); //Use claim check invoker to check the logical attachment in ClaimCheckInvoker invoker = new ClaimCheckInvoker(claimCheckReference); //Check in the attachment using the Flat File store type Object fileName = invoker.checkIn(attachment, "FF"); //Store the file name in the Data Object or transient context. if (storeTokenInBo) ((DataObject)((DataObject) currentObject).get(0)). set(logicalAttachmentElement, ((DataObject)fileName).get(0)); else com.ibm.wsspi.session.ContextService.INSTANCE.getContext(). setTransient(((DataObject)fileName).get(0)); System.out.println("Here is the data object with removed logical attachment:"); printDataObject((DataObject)currentObject); return currentObject; } |
参考上面 ,数据处理程序的 transform 方法返回后,更新的 inputOrder 数据对象(逻辑附件被索取令牌替换)被传递给 CreateShipment 中介组件。该中介组件将 inputOrder 数据对象转换成(ShipmentRequisition 类型的)inputShipmentInfo 数据对象。注意,索取令牌从 inputOrder 源数据对象的 productItem 元素移到 inputShipmentInfo 目标数据对象的 productDescription 元素(图 21)。
CreateShipment 中介组件完成转换之后,ProcessShipment HTTP 导入绑定组件被调用(图 22)。这个导入绑定组件被配置为发送一个 XML 格式的 HTTP POST 请求到目标 ShipmentProcessing 模块。另外,绑定组件被设置为使用自定义数据处理程序配置 CheckoutConfiguration。
与前面描述的 CheckinConfiguration 类似,CheckoutConfiguration 包含大量由自定义数据处理程序使用的属性。不过,这种情况是发生在 Claim Check 服务签出附件的过程中。
CheckoutConfiguration 中包含的属性是:
相同的数据处理程序类 ClaimCheckDataHandler 实现 transformInto 方法,该方法是为签出逻辑附件而被调用。transformInto 通过 ClaimCheckInvoker 调用 Claim Check 服务上的 checkOut 方法,将其传递给索取令牌和一个指示是否需要执行清理工作的 boolean 标志。成功签出附件之后,它被重新附着到数据对象 inputShipmentInfo 上。在 transformInto 方法末尾,将数据对象转换为 XML 消息的任务被委托给开箱即用的 XMLDataHandler(清单 5)。
public void transformInto(Object sourceDataObject, Object outputTargetStream, Object options) throws DataHandlerException{ System.out.println("transformInto invoked"); if (sourceDataObject instanceof DataObject) { //Use ClaimCheck service invoker to check out the logical //attachment data. //It uses a reference to the local reference that allows us //to invoke the SCA import. ClaimCheckInvoker invoker = new ClaimCheckInvoker(claimCheckReference); DataObject ticket = null; //Extract claim token from the logical element of the BO or //the context if (storeTokenInBo) ticket = (DataObject) ((DataObject) sourceDataObject). get(logicalAttachmentElement); else ticket = (DataObject) com.ibm.wsspi.session.ContextService.INSTANCE. getContext().getTransient(); //Check out the attachment DataObject attachment = invoker.checkOut(ticket, needsCleanUp); //Re-attach the attachment data to the parent data object ((DataObject) sourceDataObject). setDataObject(logicalAttachmentElement, attachment); } System.out.println("Here is the data object with re-attached logical attachment:"); printDataObject((DataObject) sourceDataObject); //Use XML Data handler to transform. the data XMLDataHandler handler = new XMLDataHandler(); handler.transformInto(sourceDataObject, outputTargetStream, options);} |
在签出附件并将其重新附着于(ShipmentRequisition 类型的)inputShipmentInfo 数据对象之后,ProcessShipment 导入绑定组件发送一个 HTTP POST 请求到 ShipmentProcessing 模块。
参考图 24,当请求到达 ShipmentProcessing 模块时,ShippingHTTPExport 导出绑定组件将输入 XML 消息转换为一个数据对象,并将其传递给 Java 组件 ProcessShipmentComponentStub,该组件将数据对象的内容写到系统输出上。
上面内容详细描述了处理逻辑附件所用的 Claim Check 模式解决方案的样例实现。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/14789789/viewspace-673750/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/14789789/viewspace-673750/