我正在开发一个 Spring Boot 项目,我需要使用 SOAP Web 服务。我使用
wsdl2java
生成客户端代码。但是,我遇到了生成的 SOAP 请求消息结构的问题。
这是来自 SOAP-UI 的预期 SOAP 请求:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:uri="http://uri.org/">
<soapenv:Header/>
<soapenv:Body>
<uri:GetPolicy>
<uri:policyId>12345</uri:policyId>
</uri:GetPolicy>
</soapenv:Body>
</soapenv:Envelope>
但是,我的 Spring Boot 应用程序生成以下 SOAP 请求:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
<ns3:GetPolicy xmlns:ns2="http://schemas.data.org/PolicyServicesLibrary" xmlns:ns3="http://uri.org/" xmlns:ns4="http://schemas.microsoft.com/Serialization/Arrays" xmlns:ns5="http://schemas.microsoft.com/Serialization/">
<ns3:policyId>12345</ns3:policyId>
</ns3:GetPolicy>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
差异包括如下,当我尝试时,由于请求 SOAP 负载不正确而收到错误。
soapenv
vs SOAP-ENV
)。这是我的
GetPolicy
课程:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"policyId"
})
@XmlRootElement(name = "GetPolicy")
public class GetPolicy {
@XmlElementRef(name = "policyId", namespace = "http://uri.org/", type = JAXBElement.class, required = false)
protected JAXBElement<String> policyId;
public JAXBElement<String> getPolicyId() {
return policyId;
}
public void setPolicyId(JAXBElement<String> value) {
this.policyId = value;
}
}
并且,这是我执行请求的配置和代码:
@Autowired
private WebServiceTemplate webServiceTemplate;
ObjectFactory factory = new ObjectFactory();
GetPolicy request = factory.createGetPolicy();
request.setPolicyId(factory.createGetPolicyPolicyId("12345"));
webServiceTemplate.setMarshaller(jaxb2Marshaller);
webServiceTemplate.setUnmarshaller(jaxb2Marshaller);
webServiceTemplate.setDefaultUri("SOAP_SERVER_URL");
JAXBElement<GetPolicyResponse> response = (JAXBElement<GetPolicyResponse>) webServiceTemplate.marshalSendAndReceive(request, new SoapActionCallback("SOAP_ACTION"));
return response.getValue();
我还确保了
package-info.java
中正确的包级命名空间定义:
@jakarta.xml.bind.annotation.XmlSchema(
namespace = "http://uri.org/",
elementFormDefault = jakarta.xml.bind.annotation.XmlNsForm.QUALIFIED
)
package my.package.name;
尽管有这些配置,生成的 SOAP 请求仍具有不正确的命名空间前缀,并包含其他命名空间。另外,我知道通过添加
XmlNs
我可以解决前缀问题,但我有多个 namespaceURI
应该与相同的 prefix
匹配。这就是我坚持的地方。
问题:
soapenv
作为命名空间前缀而不是 SOAP-ENV
?谢谢你。任何帮助将不胜感激!
对于您的第一个问题,更改您需要实现 ClientInterceptor 的名称空间前缀(SOAP-ENV 到soapenv)并将其设置为
WebServiceTemplate
。
import jakarta.xml.soap.*;
import lombok.SneakyThrows;
import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
public class Interceptor implements ClientInterceptor {
@SneakyThrows
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
changePrefix(messageContext);
return true;
}
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
// if you need to change in the response call the method 'changePrefix' here
return true;
}
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
// if you need to change in the fault response call the method 'changePrefix' here
return true;
}
public void afterCompletion(MessageContext messageContext, Exception e) throws WebServiceClientException {
}
private void changePrefix(MessageContext messageContext) throws SOAPException {
SaajSoapMessage soapMessage = (SaajSoapMessage) messageContext.getRequest();
SOAPEnvelope soapEnvelope = soapMessage.getSaajMessage().getSOAPPart().getEnvelope();
SOAPHeader soapHeader = soapEnvelope.getHeader();
SOAPBody soapBody = soapEnvelope.getBody();
SOAPFault soapFault = soapBody.getFault();
soapEnvelope.removeNamespaceDeclaration(soapEnvelope.getPrefix());
soapEnvelope.addNamespaceDeclaration("soapenv", soapEnvelope.getNamespaceURI());
soapEnvelope.setPrefix("soapenv");
if (soapHeader != null) soapHeader.setPrefix("soapenv");
if (soapBody != null) soapBody.setPrefix("soapenv");
if (soapFault != null) soapFault.setPrefix("soapenv");
}
}
要将其设置为
webServiceTemplate
,您可以创建一个Bean或任何您喜欢的方法,将创建的拦截器添加到new ClientInterceptor[]
数组中,
webServiceTemplate.setInterceptors(new ClientInterceptor[]{interceptor});
对于第二个问题,是的,当您需要更改 Soap Body 中的其他前缀为
package-info.java
时,您可以使用 XmlNs
并添加 namespaceURI
。