问题描述
对于我正在从事的项目,我们需要创建一个SOAP Web服务(使用Spring boot)。实际的接口和消息格式由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
。该响应实际上看起来与预期的相似。
我确定我忘记做/指定了一些简单的事情,所以希望你们中的一个能够指出正确的方向。
解决方法
您的绑定定义有所不同。在给定的wsdl中,指定使用rpc / encoded,而在生成的wsdl文档/文本中使用。您很有可能可以在生成wsdl之前设置这些设置。
如果您更改生成的wsdl以使其使用prc /编码,则请求看起来像:
<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>
,
好吧,经过一番尝试和错误之后,我设法找到了一种可以使用消息的其他解决方案。
我不喜欢以前尝试将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 /编码而不是Document / Literal的原始WSDL(完全由@martijn在他的回答中建议的)引起的。事实证明,RPC /编码实际上已被弃用(现在已经有很多年了……),并且似乎不受Spring的支持。
因此,除非有人知道如何让Spring使用RPC /编码,否则我想我需要回到要求我开发服务器以与其硬件通信并使其允许文档/文字响应的公司(网址为至少)。