Java? API for XML-based RPC (JAX-RPC) 支持 SOAP with Attachments (Sw/A) 规范,而 Java API for XML Web Services (JAX-WS) 支持 Sw/A 以及新推出的消息传输优化机制(Message Transmission Optimization Mechanism,MTOM)规范。本文是本系列的第 5 部分,将通过分析 Web 服务描述语言(Web Services Description Language,WSDL)和映射 Java 接口示例对这两个附件模型进行比较。
引言
JAX-RPC 的附件模型为 Sw/A,自从编写 JAX-RPC 后,就推出了一个新的附件模型:MTOM。JAX-WS 和 JAX-RPC 一样提供了 Sw/A 支持,但还增加了对 MTOM 的支持。JAX-WS 通过 Java Architecture for XML Binding (JAXB) 规范支持 MTOM,此规范包括用于对 Sw/A 和 MTOM 附件进行封送和取消封送。在本文中,我们将通过示例对这两个模型进行分析。请注意:本文仅对 WSDL 和 Java 编程模型进行比较,连接级别的消息比较需由读者自行完成。
JAX-RPC 和 Sw/A 示例
清单 1 给出了摘自多年前所撰写的关于附件提示(请参见参考资料)的 WSDL。清单 2 显示了对应的 Java 接口(即从此 WSDL 生成的 JAX-RPC 映射)。
清单 1. JAX-RPC Sw/A WSDL
<definitions
targetNamespace=”http://attachment.tip/”>
<types/>
<message name=”sendImage”>
<part name=”image” type=”xsd:base64Binary”/>
</message>
<message name=”sendImageResponse”/>
<message name=”sendOctet”>
<part name=”octet” type=”xsd:base64Binary”/>
</message>
<message name=”sendOctetResponse”/>
<portType name=”AttachmentTip”>
<operation name=”sendImage”>
<input message=”tns:sendImage”/>
<output message=”tns:sendImageResponse”/>
</operation>
<operation name=”sendOctet”>
<input message=”tns:sendOctet”/>
<output message=”tns:sendOctetResponse”/>
</operation>
</portType>
<binding name=”AttachmentBinding” type=”tns:AttachmentTip”>
<soap:binding style=”rpc” transport=”http://schemas.xmlsoap.org/soap/>
<operation name=”sendImage”>
<soap:operation soapAction=””/>
<input>
<mime:multipartRelated>
<mime:part>
<soap:body parts=”” namespace=”http://attachment.tip/” use=”literal”/>
</mime:part>
<mime:part>
<mime:content part=”image” type=”image/jpeg”/>
</mime:part>
</mime:multipartRelated>
</input>
<output>
<soap:body namespace=”http://attachment.tip/” use=”literal”/>
</output>
</operation>
<operation name=”sendOctet”>
<soap:operation soapAction=””/>
<input>
<mime:multipartRelated>
<mime:part>
<soap:body parts=”” namespace=”http://attachment.tip/” use=”literal”/>
</mime:part>
<mime:part>
<mime:content part=”octet” type=”application/octet-stream”/>
</mime:part>
</mime:multipartRelated>
</input>
<output>
<soap:body namespace=”http://attachment.tip/” use=”literal”/>
</output>
</operation>
</binding>
<service name=”AttachmentService”>
<port binding=”tns:AttachmentBinding” name=”AttachmentTip”>
<soap:address location=”http://localhost:9080/SwAService/services/AttachmentTip”/>
</port>
</service>
</definitions>
清单 2. JAX-RPC Sw/A Java 接口
package tip.attachment;
import java.awt.Image;
import java.rmi.Remote;
import java.rmi.RemoteException;
import javax.activation.DataHandler;
public interface AttachmentTip extends Remote {
public void sendImage(Image image) throws RemoteException;
public void sendOctet(DataHandler octet) throws RemoteException;
}
从 WSDL 生成的 Java 接口映射相当简单:sendImage 操作的 image/jpeg 部分映射为 java.awt.Image 参数;sendOctet 操作的 application/octet-stream 映射为 javax.activation.DataHandler 参数。不过此映射有一定的代价:多用途 Internet 邮件扩展(Multipurpose Internet Mail Extensions,MIME)类型信息不在 WSDL 接口部分中(portType、message 和 types 部分)。您必须自己对绑定进行分析,以找到 MIME 信息。这很不方便,因为相同 WSDL 接口的不同绑定可能会采用不同的类型,从而映射到不同的 Java 接口。如果从 WSDL 接口到 Java 接口之间存在一对一映射关系,这就要好得多。如果有多个绑定,每个都映射到一个实现,则所有绑定都实现相同的 Java 接口。使用 Sw/A 时不能做到这一点;从 WSDL 到 Java 的映射不是一对一的。
Sw/A 的第二个问题是,它本身对 Document/literal Wrapped WSDL 行业惯例遵循性并不好(您会注意到清单 1 中的 WSDL 是 rpc/literal WSDL)。要将 Sw/A 内容添加到 Document/literal Wrapped 消息,除了单个操作包装外,还需要指定其他消息部分。
MTOM 是否解决了这些问题?接下来我们就要对此进行讨论。
JAX-WS 和 MTOM 示例
在清单 3 中,我们将清单 1 的 Sw/A WSDL 修改为了等效的 MTOM WSDL。
清单 3. JAX-WS MTOM WSDL
<definitions
http://schemas.xmlsoap.org/wsdl/”>http://schemas.xmlsoap.org/wsdl/“
http://schemas.xmlsoap.org/wsdl/soap/”>http://schemas.xmlsoap.org/wsdl/soap/“
http://attachment.tip/”>http://attachment.tip/“
http://www.w3.org/2001/XMLSchema”>http://www.w3.org/2001/XMLSchema“
targetNamespace=”http://attachment.tip/“>
<types/>
<message name=”sendImage”>
<part name=”image” type=”xsd:base64Binary”/>
</message>
<message name=”sendImageResponse”/>
<message name=”sendOctet”>
<part name=”octet” type=”xsd:base64Binary”/>
</message>
<message name=”sendOctetResponse”/>
<portType name=”AttachmentTip”>
<operation name=”sendImage”>
<input message=”tns:sendImage”/>
<output message=”tns:sendImageResponse”/>
</operation>
<operation name=”sendOctet”>
<input message=”tns:sendOctet”/>
<output message=”tns:sendOctetResponse”/>
</operation>
</portType>
<binding name=”AttachmentBinding” type=”tns:AttachmentTip”>
<soap:binding style=”rpc” transport=”http://schemas.xmlsoap.org/soap/>
<operation name=”sendImage”>
<soap:operation soapAction=””/>
<input>
<soap:body namespace=”http://attachment.tip/” use=”literal”/>
</input>
<output>
<soap:body namespace=”http://attachment.tip/” use=”literal”/>
</output>
</operation>
<operation name=”sendOctet”>
<soap:operation soapAction=””/>
<input>
<soap:body namespace=”http://attachment.tip/” use=”literal”/>
</input>
<output>
<soap:body namespace=”http://attachment.tip/” use=”literal”/>
</output>
</operation>
</binding>
<service name=”AttachmentService”>
<port binding=”tns:AttachmentBinding” name=”AttachmentTip”>
<soap:address location=”http://localhost:9080/MTOMService/services/AttachmentTip”/>
</port>
</service>
</definitions>
清单 3 中的 MTOM WSDL 和清单 1 中的 Sw/A WSDL 的唯一区别在于绑定。MTOM 绑定不包含 MIME 信息。事实上,通过 WSDL 并不能说明您所处理的是附件,WSDL 的绑定看起来就像一个普通绑定。
清单 4 显示了对应的 Java 接口,即从此 WSDL 生成的 JAX-RPC 映射。
清单 4. JAX-WS MTOM Java 接口
package tip.attachment;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService(name = “AttachmentTip”, targetNamespace = ”http://attachment.tip/”)
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface AttachmentTip {
@WebMethod
public void sendImage(
@WebParam(name = “image”, partName = “image”)
byte[] image);
@WebMethod
public void sendOctet(
@WebParam(name = “octet”, partName = “octet”)
byte[] octet);
}
因为此 WSDL 是普通 WSDL,没有关于附件的信息,因此最终得到的 Java 接口也会反映出这一点。对于类型为 base64Binary(或 hexBinary)的部分,JAX-WS 将其映射为 byte[] 类型的参数。对于 MTOM,会从 WSLD 提取类型的全部 MIME 信息,并需要由客户机或服务器运行时对内容进行恰当的格式化。
Sw/A 和 MTOM 的比较
JAX-RPC Sw/A 部分指出了 Sw/A 的两个缺点:
MIME 类型信息在 WSDL 绑定中,而不是 WSDL 接口中。
很难创建 Document/literal Wrapped 附件 WSDL。
让我们首先讨论一下 Document/literal Wrapped 样式。
Document/literal Wrapped 样式与附件
出于比较目的,我们将清单 3 中的 MTOM WSDL 保留为 rpc/literal WSDL;但要将此 WSDL 转换为 Document/literal Wrapped WSDL 很容易。下一部分的清单 5 显示了清单 3 中的 WSDL 的 Document/literal Wrapped 等效 WSDL(有关各种 WSDL 样式之间的区别的更多信息,请参见参考资料部分)。
绑定中的 MIME 类型信息
因为 MTOM WSDL 的绑定没有任何 MIME 信息,因此不用分析绑定来确定部分类型。在 WSDL 中有生成 Java 接口所需要的全部信息。不过,正如您通过比较清单 2 和清单 4 可以看到的,我们丢失了一些信息。
这两个 WSDL 的接口部分都显示操作中的数据类型为 base64Binary,而 base64Binary 又映射到 byte[]。不过,在 JAX-RPC Sw/A WSDL 中,我们通过绑定了解到部分类型为 MIME 映像和 MIME 八进制流。在 JAX-WS MTOM WSDL 中,此信息丢失了。这可能让人感觉是件坏事,但有一个好处,即接口得到了完全的清理。无论绑定的是什么,接口始终都是一样的。事实上,客户机和服务器代码库的实现者不应考虑参数是否是附件的问题。这仅是 SOAP 消息的一个细节,WSDL 到 Java 映射的编写者已经尽量让程序员不考虑 SOAP 消息的细节。
不过,如果您真的希望知道 MIME 类型(即希望找回所丢失的信息),JAX-WS 提供了一个属性,您可将其注入 XML 元素:expectedContentTypes 中。清单 5 中突出显示的部分就是这个特殊的属性。清单 6 显示了对应的 Java 接口。如果忽略注释,此 Java 接口就完全与清单 2 中的接口相同。
清单 5. JAX-WS MIME 属性
<definitions
targetNamespace=”http://attachment.tip/”>
<types>
<xsd:schema
targetNamespace=”http://attachment.tip/”>
<xsd:element name=”sendImage” type=”tns:sendImage”/>
<xsd:complexType name=”sendImage”>
<xsd:sequence>
<xsd:element
ns1_expectedContentTypes=”image/*”
name=”image”
type=”xsd:base64Binary”/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name=”sendImageResponse” type=”tns:sendImageResponse”/>
<xsd:complexType name=”sendImageResponse”>
<xsd:sequence/>
</xsd:complexType>
<xsd:element name=”sendOctet” type=”tns:sendOctet”/>
<xsd:complexType name=”sendOctet”>
<xsd:sequence>
<xsd:element
ns1_expectedContentTypes=”application/octet-stream”
name=”octet”
type=”xsd:base64Binary”/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name=”sendOctetResponse” type=”tns:sendOctetResponse”/>
<xsd:complexType name=”sendOctetResponse”>
<xsd:sequence/>
</xsd:complexType>
</xsd:schema>
</types>
<message name=”sendImage”>
<part name=”parameters” element=”tns:sendImage”/>
</message>
<message name=”sendImageResponse”>
<part name=”parameters” element=”tns:sendImageResponse”/>
</message>
<message name=”sendOctet”>
<part name=”parameters” element=”tns:sendOctet”/>
</message>
<message name=”sendOctetResponse”>
<part name=”parameters” element=”tns:sendOctetResponse”/>
</message>
<portType name=”AttachmentTip”>
<operation name=”sendImage”>
<input message=”tns:sendImage”/>
<output message=”tns:sendImageResponse”/>
</operation>
<operation name=”sendOctet”>
<input message=”tns:sendOctet”/>
<output message=”tns:sendOctetResponse”/>
</operation>
</portType>
<binding name=”AttachmentBinding” type=”tns:AttachmentTip”>
<soap:binding style=”document” transport=”http://schemas.xmlsoap.org/soap/http”/>
<operation name=”sendImage”>
<soap:operation soapAction=””/>
<input>
<soap:body use=”literal”/>
</input>
<output>
<soap:body use=”literal”/>
</output>
</operation>
<operation name=”sendOctet”>
<soap:operation soapAction=””/>
<input>
<soap:body use=”literal”/>
</input>
<output>
<soap:body use=”literal”/>
</output>
</operation>
</binding>
<service name=”AttachmentService”>
<port binding=”tns:AttachmentBinding” name=”AttachmentTip”>
<soap:address location=”http://localhost:9080/MTOMService/services/AttachmentTip”/>
</port>
</service>
</definitions>
请注意,这个新属性完全包含在 WSDL 接口中。该属性不在绑定中,因此所有类型信息都在您所期望的位置。
清单 6. 从 MIME 属性映射得到的 JAX-WS Java 接口
package tip.attachment;
import java.awt.Image;
import javax.activation.DataHandler;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
@WebService(name = “AttachmentTip”, targetNamespace = ”http://attachment.tip/”)
public interface AttachmentTip {
@WebMethod
@RequestWrapper(localName = “sendImage”,
targetNamespace = “http://attachment.tip/”,
className = “tip.attachment.SendImage”)
@ResponseWrapper(localName = “sendImageResponse”,
targetNamespace = “http://attachment.tip/”,
className = “tip.attachment.SendImageResponse”)
public void sendImage(
@WebParam(name = “image”, targetNamespace = “”)
Image image);
@WebMethod
@RequestWrapper(localName = “sendOctet”,
targetNamespace = “http://attachment.tip/”,
className = “tip.attachment.SendOctet”)
@ResponseWrapper(localName = “sendOctetResponse”,
targetNamespace = “http://attachment.tip/”,
className = “tip.attachment.SendOctetResponse”)
public void sendOctet(
@WebParam(name = “octet”, targetNamespace = “”)
DataHandler octet);
}
正如前面所提到的,JAX-WS 依赖于 JAXB 处理其大部分 Web 服务内容的数据绑定。expectedContentTypes 元素的映射在 JAXB 2.0 规范的附录 H 中定义(请参见参考资料)。JAXB 2.0 映射与 JAX-RPC 映射类似。表 1 对这些映射进行了比较。
表 1. MIME 类型到 Java 类型的映射
MIME 类型 JAX-RPC 映射 JAX-WS/JAXB 映射
image/gif java.awt.Image java.awt.Image
image/jpg java.awt.Image java.awt.Image
text/plain java.lang.String javax.xml.transform.Source
text/xml javax.xml.transform.Source javax.xml.transform.Source
application/xml javax.xml.transform.Source javax.xml.transform.Source
multipart/* javax.mail.internet.MimeMultipart javax.activation.DataHandler
所有其他类型 javax.activation.DataHandler javax.activation.DataHandler
启用/禁用附件支持
MTOM 的另外一个好处是,您能够启用或禁用它。对于 Sw/A,如果某一方不支持发送 Sw/A 附件,就不能遵守 WSDL 定义的契约。另一方面,如果使用清单 3 或清单 5 中给出的类似的 MTOM WSDL,客户机就可以选择将数据作为 MTOM 附件发送或在 SOAP 消息中以内联方式发送。无论客户机选择哪个选项,都仍然可以与 Web 服务交互。MTOM 只是发送内容的一个优化选项,而不是像 Sw/A 一样强制要求使用。
Sw/A 和 JAX-WS
JAX-WS 仍然支持 Sw/A 模型。缺省情况下,JAX-WS 将 Sw/A 附件映射到 Java 接口上的 byte[],就像清单 4 中的示例一样。要获得在 JAX-RPC 中使用的映射,可以使用 enableMIMEContent WSDL 绑定定义(有关更多信息,请参见 JAX-WS 规范的 8.7.5 节)。清单 7 显示了与清单 2 中的接口的 JAX-RPC 版本等效的 JAX-WS 版本。
清单 7. JAX-WS Java 接口,Sw/A 附件从 mime:content 映射
package tip.attachment;
import java.awt.Image;
import javax.activation.DataHandler;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
@WebService(name = “AttachmentTip”, targetNamespace = “http://attachment.tip/”)
@SOAPBinding(style = SOAPBinding.Style.RPC)
public interface AttachmentTip {
@WebMethod
public void sendImage(
@WebParam(name = “image”, partName = “image”)
Image image);
@WebMethod
public void sendOctet(
@WebParam(name = “octet”, partName = “octet”)
DataHandler octet);
}
总结
JAX-RPC 支持 Sw/A 模型。JAX-WS 也支持 Sw/A,但另外还支持新的 MTOM 模型。从多方面而言,MTOM 都比 Sw/A 提高了不少:
创建 Java 接口所必需的全部信息现在都在 WSDL 接口中。
MTOM 可以在 Document/literal Wrapped WSDL 中使用。
MTOM 允许对附件进行优化,但并不像 Sw/A 一样对附件有强制要求。
作者简介
Russell Butek 是 IBM 的一名 SOA 和 Web 服务顾问。他曾是 IBM WebSphere Web 服务引擎的开发人员之一。他也是 JAX-RPC Java Specification Request (JSR) 专家组的成员。他参与了 Apache 的 AXIS SOAP 引擎的实现,并推动 AXIS 1.0 遵守 JAX-RPC。
Nick Gallardo 担任 IBM WebSphere 平台软件工程师,主要负责 Web 服务支持的各个方面。在此之前,他从事 IBM WebSphere 和 Tivoli 平台中其他方面的工作。Nick 于 2001 加入 IBM,此前他曾在德克萨斯州奥斯汀市两家不同的初创技术型公司从事开发工作。
我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。
我原创,你原创,我们的内容世界才会更加精彩!
【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】
微信公众号
TechTarget
官方微博
TechTarget中国
相关推荐
-
JAX-WS 2.0规范(二)
本篇介绍关于JAX-WS 2.0 概要中的其他说明。JAX-WS 2.0也将提出关于实现和使用JAX-RPC 1.0发生的问题:Inclusion in J2SE JAX-WS 2.0准备将JAX-WS……
-
JAX-RPC与JAX-WS:动态调用接口
本系列文章讨论Java API for XML-based RPC(JAX-RPC) 1.1和Java API for XML Web Services (JAX-WS) 2.0,本文是其中的第4部分,将对动态调用模型进行比较……
-
JAX-RPC与JAX-WS:服务端点接口
从整体上看,Java API for XML-based RPC(JAX-RPC) 1.1服务端点接口(SEI)和Java API for XML Web Services(JAX-WS)2.0 SEI是非常相似……
-
JAX-RPC与JAX-WS的比较
JAX-WS 2.0是JAX-RPC 1.1的后续版本。本文将引出对这两个Java Web服务编程模型进行比较的一系列文章。