使用附件表示服务接口中的 XML 文档

作者:Sean BrydonSmitha KangathSameer Tyagi

问题描述

开发者在设计 Web 服务交互环境(客户端和服务在其中交换 XML 文档)时,需要选择一种表示服务接口中的 XML 文档的类型。此选择会带来多方面的影响。选定的类型将在 WSDL 服务描述文件和服务实现代码中反映出来。在 Java[TM] 2 Platform, Enterprise Edition(J2EE[TM] 平台)1.4 应用程序中,XML 文档(如订单或发票)是使用基于 XML 的远程过程调用的 Java API (JAX-RPC) 交换的。在设计服务接口时,选择表示 XML 文档的类型时有许多可供考虑的策略: 选择使用附件表示面向文档的服务中的 XML 文档时,此解决方案重点考虑的是设计因素。有关所有这些策略的描述,请参见面向文档的服务项。

解决方案

使用附件表示客户端和服务之间交换的 XML 文档时,让我们首先考虑以下一些问题。可以使用若干个方法交换作为附件的文档。这些不同的方法是由指定附件的类型来选择的。

策略:使用附件打包 XML 文档

此策略将 XML 业务文档表示为 SOAP 消息的附件。使用附件表示的 SOAP 消息 (SwA) 定义了如何使用 MIME Multipart/Related 包发送 XML 消息包含的二进制数据和其他附件。因此,SOAP 消息实际上可以包含一个或多个使用 MIME 编码的附件,通常称为复合消息。以附件而不是以 SOAP 消息正文的形式发送信息,其效率很高,因为 SOAP 消息正文越小,处理的速度越快,并且因为消息只包含了对数据的引用而不是数据本身,因而会减少将数据映射到 Java 对象的转换时间。

JAX-RPC 使用 JavaBeans[TM] 激活框架处理 SOAP 附件。解除将此消息配置为 Java 时,JAX-RPC 运行环境可以使用两种映射技术。

  1. 它可以将熟知的 mime 类型映射到 Java 对象,如表 1 所示,也可以在运行环境中使用内置 DataHandlersDataContentHandlers 执行相反的操作。
  2. 它可以使用 JavaBeans 激活框架将附件映射到 javax.activation.DataHandler,反之亦然。

简单地说,这意味着如果服务端点中的方法使用表 1 中的标准数据类型,则运行环境会将该类型映射到 SOAP 消息的 MIME 附件中。使用 javax.activation.DataHandler 时,可以使用 DataHandler 中的 getContent() 提取附件内容。如果安装的 DataContentHandler 无法识别内容类型,则它会返回包含原始字节的 java.io.InputStream 对象。

MIME

类型

image/gif

java.awt.Image

image/jpeg

java.awt.Image

text/plain

java.lang.String

multipart/*

javax.mail.internet.MimeMultipart

text/xml or application/xml

javax.xml.transform.Source

表 1:MIME 类型到 Java 数据类型的映射

附件所具有的一个问题是在 WSDL 中没有标准的附件规范。此外,供应商之间就使用 SOAP 信封外部的 MIME 包问题未达成一致。WS-I Attachment Profile 1.0 在一定程度上解决了这一问题,它目前定义了附件处理的互操作性要求,并且完全受 J2EE 1.4 SDK(以及 JWSDP 1.4)的支持。从 WSDL 使用 MIME 绑定开始,可以生成可互操作的、符合 WS-I 的、基于附件的 Web 服务。WS-I Attachment Profile 1.0 还定义了一个新类型 "swaRef" 用来引用附件类型,可以使用该类型处理未在 WSDL 中定义的附件。

以下示例描述了一个服务,该服务能够接收作为附件发送给它的 XML 文档。代码示例 1 中的 WSDL 片段显示了 MIME 绑定。

<types>
   <schema xmlns="http://www.w3.org/2001/XMLSchema"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xmlns:wsi="http://ws-i.org/profiles/basic/1.1/xsd" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
    targetNamespace="urn:AttachmentPurchaseOrderService">
    <import namespace="http://ws-i.org/profiles/basic/1.1/xsd" schemaLocation="WS-ISwA.xsd"/>
    <element name="statusmessage" type="wsi:swaRef"/>
    <element name="InvalidPOException" type="string"/>
   </schema>
   </types>

    ...
   
    <message name="AttachmentPurchaseOrderServiceSEI_submitPO">
          <part name="attachment_1" type="xsd:hexBinary"/>
    </message>

    <message name="AttachmentPurchaseOrderServiceSEI_submitPOResponse">
        <part name="response" element="ns1:statusmessage"/>
    </message>
       
    <message name="InvalidPOException">
        <part name="InvalidPOException" element="ns1:InvalidPOException"/>
    </message>
    ...
    <portType name="AttachmentPurchaseOrderServiceSEI">
        <operation name="submitPO">
            <input message="tns:AttachmentPurchaseOrderServiceSEI_submitPO"/>
            <output message="tns:AttachmentPurchaseOrderServiceSEI_submitPOResponse"/>
                        <fault name="InvalidPOException" message="tns:InvalidPOException"/>
        </operation>
    </portType>
   
    <binding name="AttachmentPurchaseOrderServiceSEIBinding" type="tns:AttachmentPurchaseOrderServiceSEI">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="submitPO">
            <input>
                <mime:multipartRelated>       
                                        <mime:part>
                        <soap:body use="literal"/>
                    </mime:part>
                    <mime:part>
                        <mime:content part="attachment_1" type="text/xml"/>
                    </mime:part>
                </mime:multipartRelated>
            </input>
            <output>
                <mime:multipartRelated>
                    <mime:part>
                        <soap:body parts="response"  use="literal"/>
                    </mime:part>
                </mime:multipartRelated>
            </output>
                        <fault name="InvalidPOException">
                <soap:fault name="InvalidPOException" use="literal"/>
            </fault>
        </operation>
    </binding>

代码示例 1:使用附件交换 XML 文档的服务 WSDL 中的代码片段

代码示例 2 的服务端点接口中生成的 submitPO 方法显示了输入参数的标准映射的用法,以及 WS-I Attachment Profile 1.0 实现使用 swaRef 数据类型作为返回值的内容。请注意,使用附件配置文件要求此 Java 服务接口的 Java 实现类必须设置了特定于应用服务器的属性,而对于 J2EE 1.4 SDK,这些属性分别为 com.sun.xml.rpc.attachment.SetAttachmentContext 和 com.sun.xml.rpc.attachment.GetAttachmentContext。使用附件的示例应用程序的设计文档包含了更详细的示例。

public interface AttachmentPurchaseOrderServiceSEI extends Remote {
    public URI submitPO(Source attachment_1) throws
        InvalidPOException, RemoteException;
}
代码示例 2:服务端点接口

使用附件策略的一些弊端是会损害互操作性。并不是所有的工具包都支持 Attachment Profile 1.0。Attachment Profile 1.0 不是 WS-I Basic Profile 1.0 的一部分,但是它将包含在 Basic Profile 的未来版本中。实际上,目前还无法为 .NET 平台提供 MIME 附件支持。因此,如果设计需要由 C# 客户端使用的 Web 服务,则目前使用附件传递 XML 文档不是一个很好的选择。

参考资料

有关本主题的详细信息,请参阅以下资料:

© Sun Microsystems 2005。Java BluePrints Solutions Catalog 中的所有内容受版权保护,未经 Sun Microsystems 的明确书面许可,不得在其他产品中发布。