XSD用于与Spring配合使用,无法使其与WSDL匹配。

huangapple go评论62阅读模式
英文:

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

问题

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

因为只有WSDL,我尝试自己创建XSD以在应用程序中使用。在这里,我遇到了一些问题,最大的问题是它接受的请求消息并不是WSDL接受的那些。

WSDL接受的请求只是以 payment 为名称,而我的需要将 paymentRequest 作为主体元素的名称。这可能是一个简单的问题,但我找不到如何解决这个问题的方法...

简化后的WSDL:
(以下是WSDL的简化版本,略去了具体内容)

示例请求:
(以下是示例请求的内容,略去了具体内容)

我的简化XSD:
(以下是你的简化XSD,略去了具体内容)

生成的WSDL:
(以下是生成的WSDL,略去了具体内容)

在解决这个问题时,你可能需要检查以下几点:

  1. 消息名称匹配: 确保你的XSD和WSDL中的消息名称完全匹配,包括大小写和命名空间。

  2. 元素和类型定义: 确保XSD中的元素和类型与WSDL中的定义匹配,包括数据类型、命名空间等。

  3. 参数顺序: 确保WSDL中的操作的参数顺序与你的XSD和实际请求的参数顺序一致。

  4. 命名空间: 确保XSD和WSDL中的命名空间一致,特别是在消息、元素和类型的定义中。

  5. 绑定: 确保生成的WSDL绑定部分正确地指向了你的服务实现,而且输入和输出的消息引用了正确的消息。

根据你提供的信息,以上是我能够理解的要点。如果你遇到了问题,可以逐一检查这些方面,看看是否有不匹配的地方。

英文:

For the project I'm working on we need to create a SOAP web service (using Spring boot). The actual interface and message format is defined by a WSDL. The problem is that from what I understand from the documentation (e.g. https://www.baeldung.com/spring-boot-soap-web-service), I actually need an XSD (the WSDL will be generated from that).

Since there is only the WSDL, I tried to create the XSD myself for use in the application. Here I have run in to a couple of problems, the biggest problem being that the request messages it accepts aren't the ones that are accepted by the WSDL.

The WSDL accepts requests which simply are named payment where mine require paymentRequest as the name of the body element. This is probably something simple, but I can't find how to fix this…

Simplified 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>

Example request:

<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>

My simplified 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>

Generated 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>

There are a number of differences which I hope to solve in the end (no use of encoded is one), but the biggest problem is the fact that my wsdl requires paymentRequest in the request body, whereas the original message uses just payment. The response actually looked similar to what is expected.

I'm sure there something simple I have forgotten to do/specify, so hopefully one of you is able to point me in the right direction.

答案1

得分: 1

在您的绑定定义中存在差异。在给定的wsdl中指定了使用rpc/encoded,而在您生成的wsdl文档中使用了document/literal。很可能您可以在生成wsdl之前设置这些设置。

如果您修改生成的wsdl以使用rpc/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://learn.microsoft.com/en-us/previous-versions/dotnet/articles/ms996486(v=msdn.10)?redirectedfrom=MSDN#understand_topic6

英文:

There is a difference in your bindings definitions. In the given wsdl there is specified that rpc/encoded is used while in your generated wsdl document/literal is used. Most likely you can set these settings before generating the wsdl.

If you alter the generated wsdl so it uses the prc/encoded the request looks like:

	<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>

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

答案2

得分: 0

好的,经过大量的试验和错误,我成功找到了另一种解决方案,通过这种解决方案我能够消费这些消息。

我并不喜欢之前的尝试,当时我将 paymentRequest 重命名为 payment,因为当我查看 wsdl 时,我发现所有操作中都缺少了“input”部分。这让我感觉不好。

然而,仅仅通过指定类型就解决了问题

<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 中正确显示了输入部分。

进一步探索后,主要问题实际上是由原始 WSDL 使用 RPC/encoded 而不是 Document/Literal(正如 @martijn 在他的回答中建议的)。事实证明,RPC/encoded 实际上已经被弃用(相当多年了...),似乎 Spring 也不支持它。

所以,除非有人知道如何让 Spring 使用 RPC/encoded,我想我需要重新与那家要求我开发用于与其硬件通信的服务器的公司联系,并让他们允许使用 Document/literal 响应(至少要允许)。

英文:

OK, after loads of trial and error, I managed to find a different solution with which I was able to consume the messages.

I didn't like my earlier attempt where I renamed paymentRequest to just payment since when looking at the wsdl, I saw all the “input” parts missing from the operations. This didn't feel good.

However, by simply specifying the type

<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>

and the element

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

separately, it worked, and now with the input parts showing properly again in the WSDL.

Digging around a little more, it follows the main issue is actually (fully) caused by the original WSDL using RPC/encoded instead of Document/Literal (as already suggested by @martijn in his answer). As it turns out RPC/encoded is actually deprecated (quite a number of years now…) and doesn't seem to be supported by Spring.

So unless someone knows how to get Spring to use RPC/encoded, I guess I need to go back to the company that is asking me to develop a server to communicate with their hardware and make them allow Document/literal responses (at least).

huangapple
  • 本文由 发表于 2020年10月13日 05:01:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/64325290.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定