Web Services 提示与技巧: 设计可重用的 WSDL 错误定义

重用WSDL错误定义
本文介绍了如何在WSDL中重用错误定义,包括不同级别的重用策略:WSDL内的重用、WSDL间的重用及对象重用,并探讨了在不同情况下如何有效地实现错误定义的重用。

可重用的错误定义模板

在详细介绍如何重用错误定义之前,让我们先看一个可重用错误定义的示例。清单 1 显示了 XML 模式,清单 2 显示了 WSDL。


清单 1. 用于可重用错误定义的模板模式
< xsd:schema
targetNamespace ="urn:SchemaTemplates"
xmlns:xsd
="http://www.w3.org/2001/XMLSchema" >
< xsd:complexType name ="Fault" >
< xsd:sequence >
< xsd:element minOccurs ="0" name ="reason" type ="xsd:string" />
</ xsd:sequence >
</ xsd:complexType >
</ xsd:schema >

清单 2. 可重用错误定义的模板 WSDL
<wsdl:definitions
targetNamespace="urn:WSDLTemplates"
xmlns:tns
="urn:WSDLTemplates"
xmlns:wsdl
="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap
="http://schemas.xmlsoap.org/wsdl/soap/">
<wsdl:types>
<xsd:schema
targetNamespace="urn:WSDLTemplates"
xmlns:tns
="urn:WSDLTemplates"
xmlns:t
="urn:SchemaTemplates"
xmlns:xsd
="http://www.w3.org/2001/XMLSchema">
<xsd:importnamespace="urn:SchemaTemplates"schemaLocation="Fault.xsd"/>
<xsd:elementname="op1"type="tns:op1"/>
<xsd:complexTypename="op1">
<xsd:sequence>
<xsd:elementname="input"type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:elementname="op1Response"type="tns:op1Response"/>
<xsd:complexTypename="op1Response">
<xsd:sequence>
<xsd:elementname="output"type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:elementname="fault"type="t:Fault"/>
</xsd:schema>
</wsdl:types>
<wsdl:messagename="op1RequestMsg">
<wsdl:partname="op1Parameters"element="tns:op1"/>
</wsdl:message>
<wsdl:messagename="op1ResponseMsg">
<wsdl:partname="op1Result"element="tns:op1Response"/>
</wsdl:message>
<wsdl:messagename="faultMsg">
<wsdl:partname="fault"element="tns:fault"/>
</wsdl:message>
<wsdl:portTypename="Interface">
<wsdl:operationname="op1">
<wsdl:inputname="op1Request"message="tns:op1RequestMsg"/>
<wsdl:outputname="op1Response"message="tns:op1ResponseMsg"/>
<wsdl:faultname="fault"message="tns:faultMsg"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="Binding"type="tns:Interface">
<soap:binding
style="document"
transport
="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operationname="op1">
<soap:operationsoapAction=""/>
<wsdl:inputname="op1Request">
<soap:bodyuse="literal"/>
</wsdl:input>
<wsdl:outputname="op1Response">
<soap:bodyuse="literal"/>
</wsdl:output>
<wsdl:faultname="fault">
<soap:faultuse="literal"name="fault"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="Service">
<wsdl:portname="Port"binding="tns:Binding">
<soap:addresslocation="http://www.example.org/"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

重用级别

如果您定义的 WSDL 符合此模式,则可以获得可重用的错误定义。但是可重用性具有许多级别。您没有必要遵守此处介绍的全部可重用性。让我们看一下这些级别。

WSDL 内重用(Intra-WSDL)

WSDL 内重用 是本地级别的重用:即 WSDL 文件中的重用。要实现 WSDL 内重用,请避免不必要的关联;特别是,避免将操作名称放入错误名称中。这听起来非常容易,但是一些工具可创建此类错误名称。例如,可能将消息名称生成为 op1_faultMsg。使用工具和图形编辑器可以非常容易地完成许多繁锁的工作,但是它们生成的内容有时可能不是您需要的。如果错误定义包含操作名称,那么在创建新的操作(例如 op2),并需要重用 op1 的错误时,在 op2 中引用 op1_faultMsg 看起来就有些奇怪了。您可以创建名为 op2_faultMsg 的另一个 WSDL 消息,它可引用 op1_faultMsg 引用的同一模式元素,但这是不必要的额外开销。如果将错误的消息名称与操作名称分离,则可以重用该消息,并且看起来也不感到陌生(请参见清单 3)。


清单 3. 将 op2 添加到 WSDL

.
.
.
< wsdl:operation name ="op2" >
< wsdl:input name ="op2Request" message ="tns:op2RequestMsg" />
< wsdl:output name ="op2Response" message ="tns:op2ResponseMsg" />
< wsdl:fault name ="fault" message ="tns:faultMsg" />
</ wsdl:operation >
.
.
.

WSDL 间重用

WSDL 间重用 是 WSDL 之间的重用,其中多个 WSDL 可以使用同一错误定义。这里需要避免两种情况:

  • 显然,在 WSDL 的类型部分中不能定义您的错误定义。在 WSDL 类型部分中直接定义的任何内容仅对该 WSDL 可视。其他 WSDL 不可重用这些内容。
  • 第二种情况比较难,需要考虑到编程语言的映射。请看一下错误类型。因为 fault 包含单一字符串字段,您可能更愿意采用简单的路由,并将字符串直接放入错误元素中,而不是通过 t:Fault 获得该字符串。某些工具可创建此类错误(请参见清单 4)。

清单 4. 简单的错误定义
.
.
.
< xsd:schema ... >
.
.
.
< xsd:element name ="fault" type ="xsd:string" />
</ xsd:schema >
.
.
.
< wsdl:message name ="faultMsg" >
< wsdl:part name ="fault" element ="tns:fault" />
</ wsdl:message >
.
.
.

当重用模式元素和模式类型时,请考虑 WSDL 要映射的编程语言。语言映射(如 Java™ API for XML-based RPC (JAX-RPC))以直接的方式将模式类型映射到语言构造。但是如何映射元素并不总是显而易见的。对于 JAX-RPC,错误定义可映射为一个异常类。如果使用类型定义错误,则从该错误的类型名称和命名空间映射该异常的名称和包。如果仅将错误定义为一个元素,则从消息名称映射异常的名称,从消息的命名空间映射数据包(请参见清单 5)。因此,错误定义仅在消息的封闭命名空间中可重用,没有普遍的可重用性。您可以定义重用现有错误元素的另一个错误消息,但是 JAX-RPC 仍将其映射为另一个异常;它不重用现有异常。


清单 5. 清单 4 中 WSDL 的 Java 签名
                
public String op1(String input) throws RemoteException, WSDLTemplates.FaultMsg;

对象重用

重用的最后一个级别更抽象一些。按以往方法定义一个错误,它不仅是一种错误,而且是一种数据类型。当错误数据必须位于 SOAP 错误的外部时,这特别有用,。例如,如果您在处理批操作时。在简单的操作中,您将有一组输入和一组输出。此操作的批量版本将包含输入集的数组和输出集的数组。如果操作的非批量版本也可以抛出错误,则应通过一种方法将错误数据插入输出数组。在定义与本文中类似的错误时,此操作非常容易。清单 6清单 7 显示了一个批量示例。它从清单 1清单 2 中 XML Schema Definition (XSD) 和 WSDL 的基础上构建,并添加一个称为 batchOp1 的 op1 批量版本以及它的其他数据类型。


清单 6. 用于批量操作错误的 XSD
< xsd:schema
targetNamespace ="urn:SchemaTemplates"
xmlns:tns
="urn:SchemaTemplates"
xmlns:xsd
="http://www.w3.org/2001/XMLSchema" >
< xsd:complexType name ="Fault" >
< xsd:sequence >
< xsd:element minOccurs ="0" name ="reason" type ="xsd:string" />
</ xsd:sequence >
</ xsd:complexType >
< xsd:complexType name ="Response" abstract ="true" />
< xsd:complexType name ="NormalResponse" >
< xsd:complexContent >
< xsd:extension base ="tns:Response" >
< xsd:sequence >
< xsd:element name ="response" type ="xsd:string" />
</ xsd:sequence >
</ xsd:extension >
</ xsd:complexContent >
</ xsd:complexType >
< xsd:complexType name ="FaultResponse" >
< xsd:complexContent >
< xsd:extension base ="tns:Response" >
< xsd:sequence >
< xsd:element name ="fault" type ="tns:Fault" />
</ xsd:sequence >
</ xsd:extension >
</ xsd:complexContent >
</ xsd:complexType >
</ xsd:schema >
清单 7. 用于批量操作错误的 WSDL
< wsdl:definitions
targetNamespace ="urn:WSDLTemplates"
xmlns:tns
="urn:WSDLTemplates"
xmlns:wsdl
="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap
="http://schemas.xmlsoap.org/wsdl/soap/" >
< wsdl:types >
< xsd:schema
targetNamespace ="urn:WSDLTemplates"
xmlns:tns
="urn:WSDLTemplates"
xmlns:t
="urn:SchemaTemplates"
xmlns:xsd
="http://www.w3.org/2001/XMLSchema" >
< xsd:import namespace ="urn:SchemaTemplates" schemaLocation ="Fault.xsd" />
< xsd:element name ="op1" type ="tns:op1" />
< xsd:complexType name ="op1" >
< xsd:sequence >
< xsd:element name ="input" type ="xsd:string" />
</ xsd:sequence >
</ xsd:complexType >
< xsd:element name ="op1Response" type ="tns:op1Response" />
< xsd:complexType name ="op1Response" >
< xsd:sequence >
< xsd:element name ="output" type ="xsd:string" />
</ xsd:sequence >
</ xsd:complexType >
< xsd:element name ="batchOp1" type ="tns:batchOp1" />
< xsd:complexType name ="batchOp1" >
< xsd:sequence >
< xsd:element name ="input" type ="xsd:string"
maxOccurs
="unbounded" />
</ xsd:sequence >
</ xsd:complexType >
< xsd:element name ="batchOp1Response"
type
="tns:batchOp1Response" />
< xsd:complexType name ="batchOp1Response" >
< xsd:sequence >
< xsd:element name ="output" type ="t:Response"
maxOccurs
="unbounded" />
</ xsd:sequence >
</ xsd:complexType >
< xsd:element name ="fault" type ="t:Fault" />
</ xsd:schema >
</ wsdl:types >
< wsdl:message name ="op1RequestMsg" >
< wsdl:part name ="op1Parameters" element ="tns:op1" />
</ wsdl:message >
< wsdl:message name ="op1ResponseMsg" >
< wsdl:part name ="op1Result" element ="tns:op1Response" />
</ wsdl:message >
< wsdl:message name ="faultMsg" >
< wsdl:part name ="fault" element ="tns:fault" />
</ wsdl:message >
< wsdl:message name ="batchOp1RequestMsg" >
< wsdl:part name ="batchOp1Parameters"
element
="tns:batchOp1" />
</ wsdl:message >
< wsdl:message name ="batchOp1ResponseMsg" >
< wsdl:part name ="batchOp1Result"
element
="tns:batchOp1Response" />
</ wsdl:message >
< wsdl:portType name ="Interface" >
< wsdl:operation name ="op1" >
< wsdl:input name ="op1Request" message ="tns:op1RequestMsg" />
< wsdl:output name ="op1Response" message ="tns:op1ResponseMsg" />
< wsdl:fault name ="fault" message ="tns:faultMsg" />
</ wsdl:operation >
< wsdl:operation name ="batchOp1" >
< wsdl:input name ="batchOp1Request"
message
="tns:batchOp1RequestMsg" />
< wsdl:output name ="batchOp1Response"
message
="tns:batchOp1ResponseMsg" />
</ wsdl:operation >
</ wsdl:portType >
< wsdl:binding name ="Binding" type ="tns:Interface" >
< soap:binding
style ="document"
transport
="http://schemas.xmlsoap.org/soap/http" />
< wsdl:operation name ="op1" >
< soap:operation soapAction ="" />
< wsdl:input name ="op1Request" >
< soap:body use ="literal" />
</ wsdl:input >
< wsdl:output name ="op1Response" >
< soap:body use ="literal" />
</ wsdl:output >
< wsdl:fault name ="fault" >
< soap:fault use ="literal" name ="fault" />
</ wsdl:fault >
</ wsdl:operation >
< wsdl:operation name ="batchOp1" >
< soap:operation soapAction ="" />
< wsdl:input name ="batchOp1Request" >
< soap:body use ="literal" />
</ wsdl:input >
< wsdl:output name ="batchOp1Response" >
< soap:body use ="literal" />
</ wsdl:output >
</ wsdl:operation >
</ wsdl:binding >
< wsdl:service name ="Service" >
< wsdl:port name ="Port" binding ="tns:Binding" >
< soap:address location ="http://www.example.org/" />
</ wsdl:port >
</ wsdl:service >
</ wsdl:definitions >

batchOp1 返回 Response 的数组。Response 是一种抽象类型,因此,您必须使用具体的扩展填充该数组。Response 数组元素可以包含 NormalResponse 对象或 FaultResponse 对象。

批量模型的实际扩展
在实际示例中,您可能有多个错误。要容纳这些错误,可以为错误构建层次结构,然后将所有错误的基类插入 FaultResponse 类型。

总结

尽可能扩展 WSDL 错误定义非常有用。希望您已了解了本文中介绍的操作方式。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值