Spring Boot集成第三方WSDL时SOAP请求缺失操作元素的咨询
问题:Spring Boot集成RPC/Encoded风格WSDL时请求缺失操作元素
我使用WebServiceGatewaySupport和org.jvnet.jaxb2.maven2:maven-jaxb2-plugin:0.15.1集成第三方WSDL,该WSDL在SoapUI中可正常运行,但Spring Boot直接调用时报错:
Method 'ns2:carsRequest' not implemented: method name or namespace not recognized
排查后发现,Java代码生成的请求未用操作元素包裹请求体:SoapUI生成的成功请求包含<pai:GetListCars>元素,但Java生成的payload缺失该部分,示例如下:
正确请求(SoapUI生成):
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pai="http://my-endpoint.com"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <pai:GetListCars> <ns2:carsRequest xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/"> <lang>EN</lang> </ns2:carRequest> </pai:GetListCars> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
错误请求(Java生成):
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pai="http://my-endpoint.com"> <SOAP-ENV:Header/> <SOAP-ENV:Body> <ns2:carsRequest xmlns:ns2="http://schemas.xmlsoap.org/soap/encoding/"> <lang>EN</lang> </ns2:carRequest> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
对应的第三方WSDL:
<?xml version="1.0" encoding="UTF-8"?> <wsdl:definitions xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://my-endpoint.com" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://my-endpoint.com"> <wsdl:types> <schema targetNamespace="http://my-endpoint.com" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/> <complexType name="CarsRequest"> <sequence> <element name="lang" nillable="true" type="soapenc:string"/> </sequence> </complexType> <complexType name="CarsResponse"> <sequence> <element name="ErrorMessage" nillable="true" type="soapenc:string"/> </sequence> </complexType> </schema> </wsdl:types> <wsdl:message name="GetListCarsResponse"> <wsdl:part name="getListCarsReturn" type="impl:CarsResponse"/> </wsdl:message> <wsdl:message name="GetListCarsRequest"> <wsdl:part name="carRequest" type="impl:CarsRequest"/> </wsdl:message> <wsdl:portType name="Garage"> <wsdl:operation name="GetListCars" parameterOrder="frnreq"> <wsdl:input message="impl:GetListCarsRequest" name="getListVehiclesRequest"/> <wsdl:output message="impl:GetListCarsResponse" name="getListVehiclesResponse"/> </wsdl:operation> </wsdl:portType> <wsdl:binding name="GarageSoapBinding" type="impl:Garage"> <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/> <wsdl:operation name="GetListCars"> <wsdlsoap:operation soapAction=""/> <wsdl:input name="getListVehiclesRequest"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://my-endpoint.com" use="encoded"/> </wsdl:input> <wsdl:output name="getListVehiclesResponse"> <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://my-endpoint.com" use="encoded"/> </wsdl:output> </wsdl:operation> </wsdl:binding> <wsdl:service name="GarageService"> <wsdl:port binding="impl:GarageSoapBinding" name="Garage"> <wsdlsoap:address location="http://localhost:8888"/> </wsdl:port> </wsdl:service> </wsdl:definitions>
不希望修改源WSDL,请问是否有方法添加缺失的元素,或者可以使用其他替代库?
解决方案
一、手动包装请求体(基于现有Spring WS框架)
该WSDL属于RPC/Encoded风格,默认JAXB生成逻辑对这类风格的支持不足,可通过自定义WebServiceMessageCallback手动添加缺失的操作元素:
- 实现自定义回调类:
public class RpcSoapCallback implements WebServiceMessageCallback { private final String operationName; private final String namespaceUri; private final String prefix; public RpcSoapCallback(String operationName, String namespaceUri, String prefix) { this.operationName = operationName; this.namespaceUri = namespaceUri; this.prefix = prefix; } @Override public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { SaajSoapMessage soapMessage = (SaajSoapMessage) message; SOAPBody soapBody = soapMessage.getSaajMessage().getSOAPBody(); // 移除原请求体元素 Node originalRequest = soapBody.getFirstChild(); if (originalRequest == null) return; soapBody.removeChild(originalRequest); // 创建操作元素并包裹原请求体 SOAPElement operationElement = soapBody.addChildElement(operationName, prefix, namespaceUri); operationElement.appendChild(originalRequest); } }
- 调用接口时使用该回调:
CarsRequest request = new CarsRequest(); request.setLang("EN"); CarsResponse response = (CarsResponse) getWebServiceTemplate().marshalSendAndReceive( "http://localhost:8888", request, new RpcSoapCallback("GetListCars", "http://my-endpoint.com", "pai") );
二、更换代码生成插件
maven-jaxb2-plugin对RPC/Encoded风格的支持有限,可替换为对该风格更友好的Apache CXF插件:
在pom.xml中添加配置:
<plugin> <groupId>org.apache.cxf</groupId> <artifactId>cxf-codegen-plugin</artifactId> <version>3.6.2</version> <executions> <execution> <id>generate-soap-client</id> <phase>generate-sources</phase> <configuration> <wsdlOptions> <wsdlOption> <wsdl>src/main/resources/wsdl/your-service.wsdl</wsdl> <extraargs> <extraarg>-p</extraarg> <extraarg>com.your.package.generated</extraarg> <extraarg>-fe</extraarg> <extraarg>jaxws21</extraarg> </extraargs> </wsdlOption> </wsdlOptions> </configuration> <goals> <goal>wsdl2java</goal> </goals> </execution> </executions> </plugin>
生成的客户端代码会自动处理RPC/Encoded风格的请求包装逻辑,直接调用即可,无需手动修改请求体。
内容的提问来源于stack exchange,提问作者BlackDog
相关产品推荐
相关产品推荐

