XSD 与 Spring 一起使用,无法使其匹配 WSDL

XSD for use with Spring, can't get it to match WSDL

对于我正在处理的项目,我们需要创建一个 SOAP Web 服务(使用 Spring 启动)。实际的接口和消息格式由 WSDL 定义。问题是根据我对文档的理解(例如 https://www.baeldung.com/spring-boot-soap-web-service),我实际上需要一个 XSD(WSDL 将从中生成)。

由于只有 WSDL,我尝试自己创建 XSD 以供在应用程序中使用。在这里,我 运行 遇到了几个问题,最大的问题是它接受的请求消息不是 WSDL 接受的请求消息。

WSDL 接受简单命名为 payment 的请求,其中我的要求 paymentRequest 作为正文元素的名称。这可能很简单,但我找不到解决方法…

简化的 wsdl:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://xxx.yyy.com" 
                  xmlns:impl="http://xxx.yyy.com" 
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <wsdl:types>
  <schema targetNamespace="http://xxx.yyy.com" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
   <complexType name="XxxTxnResponse">
    <sequence>
     <element name="resultCode" type="xsd:int"/>
    </sequence>
   </complexType>
   <complexType name="XxxToken">
    <sequence>
     <element name="tokenId" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
   <complexType name="PaymentTxnResponse">
    <complexContent>
     <extension base="impl:XxxTxnResponse">
      <sequence>
       <element name="transactionRef" type="xsd:int"/>
       </sequence>
      </extension>
    </complexContent>
   </complexType>
  </schema>
 </wsdl:types>
    <wsdl:message name="paymentRequest">
      <wsdl:part name="posId" type="xsd:string"/>
      <wsdl:part name="amountCents" type="xsd:int"/>
      <wsdl:part name="token" type="impl:XxxToken"/>
    </wsdl:message>
    <wsdl:message name="paymentResponse">
      <wsdl:part name="paymentReturn" type="impl:PaymentTxnResponse"/>
    </wsdl:message>  
   <wsdl:portType name="XxxTxnHost">
      <wsdl:operation name="payment" parameterOrder="posId amountCents token">
         <wsdl:input message="impl:paymentRequest" name="paymentRequest"/>
         <wsdl:output message="impl:paymentResponse" name="paymentResponse"/>
      </wsdl:operation>     
   </wsdl:portType>
   <wsdl:binding name="XxxTxnHostSoapBinding" type="impl:XxxTxnHost">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>    
     <wsdl:operation name="payment">
       <wsdlsoap:operation soapAction=""/>
       <wsdl:input name="paymentRequest">
         <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://xxx.yyy.com" use="encoded"/>
       </wsdl:input>
       <wsdl:output name="paymentResponse">
         <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://xxx.yyy.com" use="encoded"/>
       </wsdl:output>
     </wsdl:operation>     
   </wsdl:binding>
   <wsdl:service name="XxxTxnHostService">
      <wsdl:port binding="impl:XxxTxnHostSoapBinding" name="XxxTxnHost">
         <wsdlsoap:address location="wp.wsdl"/>
      </wsdl:port>
   </wsdl:service>   
</wsdl:definitions>

请求示例:

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xxx="http://xxx.yyy.com">
   <soapenv:Header/>
   <soapenv:Body>
      <xxx:payment soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <posId xsi:type="xsd:string">?</posId>
         <amountCents xsi:type="xsd:int">?</amountCents>
         <token xsi:type="xxx:XxxToken">
            <tokenId xsi:type="xsd:string">?</tokenId>
         </token>
      </xxx:payment>
   </soapenv:Body>
</soapenv:Envelope>

我的简化版xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://xxx.yyy.com"
           xmlns:tns="http://xxx.yyy.com">
    <xs:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
    <xs:complexType name="XxxTxnResponse">
        <xs:sequence>
            <xs:element name="resultCode" type="xs:int"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="XxxToken">
        <xs:sequence>
            <xs:element name="tokenId" nillable="true" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="PaymentTxnResponse">
        <xs:complexContent>
            <xs:extension base="tns:XxxTxnResponse">
                <xs:sequence>
                    <xs:element name="transactionRef" type="xs:int"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="paymentRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="posId" type="xs:string"/>
                <xs:element name="amountCents" type="xs:int"/>
                <xs:element name="token" type="tns:XxxToken"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="paymentResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="paymentReturn" type="tns:PaymentTxnResponse"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

生成的 wsdl:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://xxx.yyy.com" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://xxx.yyy.com" targetNamespace="http://xxx.yyy.com">
  <wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xxx.yyy.com">
    <xs:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
    <xs:complexType name="XxxTxnResponse">
        <xs:sequence>
            <xs:element name="resultCode" type="xs:int"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="XxxToken">
        <xs:sequence>
            <xs:element name="tokenId" nillable="true" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="PaymentTxnResponse">
        <xs:complexContent>
            <xs:extension base="tns:XxxTxnResponse">
                <xs:sequence>
                    <xs:element name="transactionRef" type="xs:int"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="paymentRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="posId" type="xs:string"/>
                <xs:element name="amountCents" type="xs:int"/>
                <xs:element name="token" type="tns:XxxToken"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="paymentResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="paymentReturn" type="tns:PaymentTxnResponse"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>
  </wsdl:types>
  <wsdl:message name="paymentResponse">
    <wsdl:part element="tns:paymentResponse" name="paymentResponse">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="paymentRequest">
    <wsdl:part element="tns:paymentRequest" name="paymentRequest">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="yyy">
    <wsdl:operation name="payment">
      <wsdl:input message="tns:paymentRequest" name="paymentRequest">
    </wsdl:input>
      <wsdl:output message="tns:paymentResponse" name="paymentResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="yyySoap11" type="tns:yyy">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="payment">
      <soap:operation soapAction=""/>
      <wsdl:input name="paymentRequest">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="paymentResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="yyyService">
    <wsdl:port binding="tns:yyySoap11" name="yyySoap11">
      <soap:address location="http://localhost:8206/yyyservice/ws"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

我希望最终解决一些差异(不使用编码是一个),但最大的问题是我的 wsdl 在请求正文中需要 paymentRequest,而原始消息仅使用 payment。响应实际上看起来与预期的相似。

我敢肯定有一些简单的事情我忘记了 do/specify,所以希望你们中的一位能够为我指明正确的方向。

您的绑定定义有所不同。在给定的 wsdl 中指定使用 rpc/encoded,而在您生成的 wsdl 中使用 document/literal。您很可能可以在生成 wsdl 之前设置这些设置。

如果您更改生成的 wsdl,使其使用 prc/encoded,则请求如下所示:

    <SOAP-ENV:Body>
        <m:payment xmlns:m="http://xxx.yyy.com">
            <m:payment>
                <posId xsi:type="xsd:string">String</posId>
                <amountCents xsi:type="xsd:int">0</amountCents>
                <token xsi:type="m:XxxToken">
                    <tokenId xsi:type="xsd:string">String</tokenId>
                </token>
            </m:payment>
        </m:payment>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

https://docs.microsoft.com/en-us/previous-versions/dotnet/articles/ms996486(v=msdn.10)?redirectedfrom=MSDN#understand_topic6

好的,经过反复试验,我设法找到了一个可以使用消息的不同解决方案。

我不喜欢我之前将 paymentRequest 重命名为 payment 的尝试,因为在查看 wsdl 时,我看到操作中缺少所有“输入”部分。这感觉不太好。

但是,通过简单地指定类型

<xs:complexType name="PaymentRequest">
    <xs:sequence>
        <xs:element name="posId" type="xs:string"/>
        <xs:element name="amountCents" type="xs:int"/>
        <xs:element name="token" type="tns:XxxToken"/>
    </xs:sequence>
</xs:complexType>

和元素

<xs:element name="paymentRequest" type ="PaymentRequest">

另外,它起作用了,现在输入部分在 WSDL 中再次正确显示。

再深入一点,主要问题实际上(完全)是由使用 RPC/encoded 而不是 Document/Literal 的原始 WSDL 引起的(正如@martijn 在他的回答中所建议的那样) .事实证明 RPC/encoded 实际上已被弃用(现在已经很多年了……)并且 Spring 似乎不受支持。

所以除非有人知道如何让 Spring 使用 RPC/encoded,否则我想我需要回到要求我开发服务器以与他们的硬件通信的公司并使他们允许 Document/literal 回复(至少)。