Web Services 提示与技巧: 设计可重用的 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: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 ="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: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: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: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 >

重用级别

如果您定义的 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 错误定义非常有用。希望您已了解了本文中介绍的操作方式。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值