Я работаю над проектом Spring Boot, где мне нужно использовать веб-службу SOAP. Я использовал wsdl2java для генерации клиентского кода. Однако у меня возникли проблемы со сгенерированной структурой сообщения запроса SOAP.
Вот ожидаемый запрос SOAP от SOAP-UI:
<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 или 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?Спасибо. Любая помощь будет принята с благодарностью!




На ваш первый вопрос: чтобы изменить префиксы пространства имен (SOAP-ENV на Soapenv), вам необходимо реализовать ClientInterceptor и установить для него значение 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});
На ваш второй вопрос: да, вы можете использовать package-info.java и добавить XmlNs, когда вам нужно изменить другие префиксы в теле мыла на namespaceURI.
Большое спасибо за ответ и уделенное время, чтобы ответить на этот вопрос.