11

当客户端调用 Web 服务而不在 SOAP 正文中传递前缀时,我的 Web 服务无法处理客户端的请求,如下所示:

<soap:Body> 
 <GetPatientResultsRequest xmlns="http://urlA"> 
  <PatientIdentification> 
      <PersonCivilRegistrationIdentifier xmlns="http://UrlB"/> 
  </PatientIdentification> 
  <Period> 
    <From>2012-05-26</From> 
     <To>2012-06-26</To> 
   </Period> 
 </GetPatientResultsRequest> 
</soap:Body>

错误是和其他对应的Java对象GetPatientResultsRequest为空。

似乎当 Body 中没有前缀时,反序列化没有正确发生。我的 Web 服务只有在 SOAP Body 有一个前缀时才能响应

<soap:Body> 
 <m:GetPatientResultsRequest xmlns:m="http://urlA">
  <PatientIdentification> 
      <PersonCivilRegistrationIdentifier xmlns="http://UrlB"/> 
  </PatientIdentification> 
  <Period> 
    <From>2012-05-26</From> 
     <To>2012-06-26</To> 
   </Period> 
 </m:GetPatientResultsRequest> 
</soap:Body>

谁能让我知道该怎么做,以便我的 Web 服务可以接受各种类型的 SOAP 请求(即在正文中带有和不带有前缀)?

我正在使用 JAX-WS (SOAP 1.1)

4

1 回答 1

11

Web 服务定义了调用它时必须遵循的契约。您发布的示例中只有一条消息与该合同匹配,因此一条有效,另一条无效。

在您的第一条消息中,您定义了一个默认命名空间(因为xmlns包装器中的属性),并且所有没有取消声明它并且没有前缀的元素都在同一个命名空间中,因为它们从它们的父级继承。

在您的第二条消息中,您有一个显式前缀声明,并且只有包装器位于该名称空间中,其他元素不在名称空间中,并且不从父级继承默认元素(因为xmlns缺少属性)。

正如我一开始所说,Web 服务定义了一个契约。修改客户端以发送正确的消息而不是更改服务以接受来自客户端的错误消息更有意义。

要控制元素的名称空间,您需要使用Web 服务和客户端targetNamespace的 JAX-WS 注释上的值。

这是一个示例,可以查看更改目标命名空间时代码和消息格式的差异。我将为此使用一个基本的 WSDL:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:tns="http://tempuri.org" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
targetNamespace="http://tempuri.org" 
name="CalculatorWS">
  <wsdl:types>
    <xs:schema targetNamespace="http://tempuri.org">
      <xs:element name="add" type="tns:add" />
      <xs:element name="addInput" type="tns:addInput" />
      <xs:element name="addResponse" type="tns:addResponse" />
      <xs:element name="addOutput" type="tns:addOutput" />
      <xs:complexType name="add">
        <xs:sequence>
          <xs:element name="addInput" type="tns:addInput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addInput">
        <xs:sequence>
          <xs:element name="a" type="xs:int" />
          <xs:element name="b" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addResponse">
        <xs:sequence>
          <xs:element name="addOutput" type="tns:addOutput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addOutput">
        <xs:sequence>
          <xs:element name="result" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="add">
    <wsdl:part name="parameters" element="tns:add" />
  </wsdl:message>
  <wsdl:message name="addResponse">
    <wsdl:part name="parameters" element="tns:addResponse" />
  </wsdl:message>
  <wsdl:portType name="CalculatorWS">
    <wsdl:operation name="add">
      <wsdl:input message="tns:add" />
      <wsdl:output message="tns:addResponse" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="CalculatorWSPortBinding" type="tns:CalculatorWS">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    <wsdl:operation name="add">
      <soap:operation soapAction="http://tempuri.org/add" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="CalculatorWSService">
    <wsdl:port name="CalculatorWSPort" binding="tns:CalculatorWSPortBinding">
      <soap:address location="http://localhost:8080/WebServices/CalculatorWS" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

这定义了如下消息:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
        xmlns:tem="http://tempuri.org">
   <soapenv:Body>
      <tem:add>
         <addInput>
            <a>?</a>
            <b>?</b>
         </addInput>
      </tem:add>
   </soapenv:Body>
</soapenv:Envelope>

和:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
       xmlns:tem="http://tempuri.org">
   <soapenv:Body>
      <tem:addResponse>
         <addOutput>
            <result>?</result>
         </addOutput>
      </tem:addResponse>
   </soapenv:Body>
</soapenv:Envelope>

看到包装器上的命名空间前缀了吗?这是因为元素是在http://tempuri.org命名空间中声明的,而其他元素则不是,也不在命名空间中。

您甚至可以从命名空间中删除所有元素。从 WSDL 中剥离目标名称空间,使其看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions 
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" 
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
name="CalculatorWS">
  <wsdl:types>
    <xs:schema>
      <xs:element name="add" type="add" />
      <xs:element name="addInput" type="addInput" />
      <xs:element name="addResponse" type="addResponse" />
      <xs:element name="addOutput" type="addOutput" />
      <xs:complexType name="add">
        <xs:sequence>
          <xs:element name="addInput" type="addInput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addInput">
        <xs:sequence>
          <xs:element name="a" type="xs:int" />
          <xs:element name="b" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addResponse">
        <xs:sequence>
          <xs:element name="addOutput" type="addOutput" />
        </xs:sequence>
      </xs:complexType>
      <xs:complexType name="addOutput">
        <xs:sequence>
          <xs:element name="result" type="xs:int" />
        </xs:sequence>
      </xs:complexType>
    </xs:schema>
  </wsdl:types>
  <wsdl:message name="add">
    <wsdl:part name="parameters" element="add" />
  </wsdl:message>
  <wsdl:message name="addResponse">
    <wsdl:part name="parameters" element="addResponse" />
  </wsdl:message>
  <wsdl:portType name="CalculatorWS">
    <wsdl:operation name="add">
      <wsdl:input message="add" />
      <wsdl:output message="addResponse" />
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="CalculatorWSPortBinding" type="CalculatorWS">
    <soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />
    <wsdl:operation name="add">
      <soap:operation soapAction="http://tempuri.org/add" />
      <wsdl:input>
        <soap:body use="literal" />
      </wsdl:input>
      <wsdl:output>
        <soap:body use="literal" />
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="CalculatorWSService">
    <wsdl:port name="CalculatorWSPort" binding="CalculatorWSPortBinding">
      <soap:address location="http://localhost:8080/WebServices/CalculatorWS" />
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

这个新的 WSDL 将对应于如下消息:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <add>
         <addInput>
            <a>?</a>
            <b>?</b>
         </addInput>
      </add>
   </soapenv:Body>
</soapenv:Envelope>

和:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <addResponse>
         <addOutput>
            <result>?</result>
         </addOutput>
      </addResponse>
   </soapenv:Body>
</soapenv:Envelope>

在这种情况下没有前缀。

现在wsimport.exe在两个 WSDL 上使用,您将看到我在开始时谈到的目标名称空间,即对此的更改:

@WebService(name = "CalculatorWS", targetNamespace = "http://tempuri.org")
public interface CalculatorWS {
    @WebMethod(action = "http://tempuri.org/add")
    @WebResult(name = "addOutput", targetNamespace = "")
    @RequestWrapper(localName = "add", targetNamespace = "http://tempuri.org", className = "your.pack.age.Add")
    @ResponseWrapper(localName = "addResponse", targetNamespace = "http://tempuri.org", className = "your.pack.age.AddResponse")
    public AddOutput add(
        @WebParam(name = "addInput", targetNamespace = "")
        AddInput addInput);
}

对此:

@WebService(name = "CalculatorWS", targetNamespace = "")
public interface CalculatorWS {
    @WebMethod(action = "http://tempuri.org/add")
    @WebResult(name = "addOutput", targetNamespace = "")
    @RequestWrapper(localName = "add", targetNamespace = "", className = "your.pack.age.Add")
    @ResponseWrapper(localName = "addResponse", targetNamespace = "", className = "your.pack.age.AddResponse")
    public AddOutput add(
        @WebParam(name = "addInput", targetNamespace = "")
        AddInput addInput);
}

控制targetNamespace,您将控制消息的外观。

于 2012-09-05T21:09:16.367 回答