Add SoapHeader to org.springframework.ws.WebServiceMessage
How can I add an object into the soap header of a org.springframework.ws.WebServiceMessage
This is the structure I'm looking to end up with:
<soap:Header>
<credentials xmlns="http://example.com/auth">
<username>username</username>
<password>password</password>
开发者_如何学Python </credentials>
</soap:Header>
Basically, you need to use a WebServiceMessageCallback
in your client to modify the message after its creation but before it is sent. To rest of the code has been described pretty accurately by @skaffman so the whole stuff might look like this:
public void marshalWithSoapActionHeader(MyObject o) {
webServiceTemplate.marshalSendAndReceive(o, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
try {
SoapMessage soapMessage = (SoapMessage)message;
SoapHeader header = soapMessage.getSoapHeader();
StringSource headerSource = new StringSource("<credentials xmlns=\"http://example.com/auth\">\n +
<username>"+username+"</username>\n +
<password>"+password"+</password>\n +
</credentials>");
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(headerSource, header.getResult());
} catch (Exception e) {
// exception handling
}
}
});
}
Personally, I find that Spring-WS sucks hard for such a basic need, they should fix SWS-479.
You can do as below:
public class SoapRequestHeaderModifier implements WebServiceMessageCallback {
private final String userName = "user";
private final String passWd = "passwd";
@Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
if (message instanceof SaajSoapMessage) {
SaajSoapMessage soapMessage = (SaajSoapMessage) message;
MimeHeaders mimeHeader = soapMessage.getSaajMessage().getMimeHeaders();
mimeHeader.setHeader("Authorization", getB64Auth(userName, passWd));
}
}
private String getB64Auth(String login, String pass) {
String source = login + ":" + pass;
String retunVal = "Basic " + Base64.getUrlEncoder().encodeToString(source.getBytes());
return retunVal;
}
}
Then
Object response = getWebServiceTemplate().marshalSendAndReceive(request, new SoapRequestHeaderModifier());
You need to cast the WebServiceMessage
to SoapMessage
, which has a getSoapHeader()
method you can use to modify the header. In turn, SoapHeader
has various methods for adding elements, including getResult()
(which can be used as the output of a Transformer.transform()
operation).
I tried many options and finally below one worked for me if you have to send soap header with authentication(Provided authentication object created by wsimport) and also need to set soapaction.
public Response callWebService(String url, Object request)
{
Response res = null;
log.info("The request object is " + request.toString());
try {
res = (Response) getWebServiceTemplate().marshalSendAndReceive(url, request,new WebServiceMessageCallback() {
@Override
public void doWithMessage(WebServiceMessage message) {
try {
// get the header from the SOAP message
SoapHeader soapHeader = ((SoapMessage) message).getSoapHeader();
// create the header element
ObjectFactory factory = new ObjectFactory();
Authentication auth =
factory.createAuthentication();
auth.setUser("****");
auth.setPassword("******");
((SoapMessage) message).setSoapAction(
"soapAction");
JAXBElement<Authentication> headers =
factory.createAuthentication(auth);
// create a marshaller
JAXBContext context = JAXBContext.newInstance(Authentication.class);
Marshaller marshaller = context.createMarshaller();
// marshal the headers into the specified result
marshaller.marshal(headers, soapHeader.getResult());
} catch (Exception e) {
log.error("error during marshalling of the SOAP headers", e);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
return res;
}
You can achieve it by creating key-value map of child elements as well:
final Map<String, String> elements = new HashMap<>();
elements.put("username", "username");
elements.put("password", "password");
Set up namespace and prefix of your child element within the soap header:
final String LOCAL_NAME = "credentials";
final String PREFIX = "";
final String NAMESPACE = "http://example.com/auth";
Then, you can invoke WebServiceTemplate's method marshalSendAndReceive
where you override WebServiceMessageCallback's method doWithMessage as follows:
Object response = getWebServiceTemplate().marshalSendAndReceive(request, (message) -> {
if (message instanceof SaajSoapMessage) {
SaajSoapMessage saajSoapMessage = (SaajSoapMessage) message;
SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
SOAPPart soapPart = soapMessage.getSOAPPart();
if (Objects.nonNull(elements)) {
try {
SOAPEnvelope soapEnvelope = soapPart.getEnvelope();
SOAPHeader soapHeader = soapEnvelope.getHeader();
Name headerElementName = soapEnvelope.createName(
LOCAL_NAME,
PREFIX,
NAMESPACE
);
SOAPHeaderElement soapHeaderElement = soapHeader.addHeaderElement(headerElementName);
elements.forEach((key, value) -> {
try {
SOAPElement element = soapHeaderElement.addChildElement(key, PREFIX);
element.addTextNode(value);
} catch (SOAPException e) {
// error handling
}
});
soapMessage.saveChanges();
} catch (SOAPException e) {
// error handling
}
}
}
});
The above steps result in:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Header>
<credentials xmlns="http://example.com/auth">
<password>password</password>
<username>username</username>
</credentials>
</env:Header>
<env:Body>
<!-- your payload -->
</env:Body>
</env:Envelope>
Response response = (Response)getWebServiceTemplate() .marshalSendAndReceive(request, new HeaderModifier());
Create class HeaderModifier and override doWithMessage
public class HeaderModifier implements WebServiceMessageCallback {
private static PrintStream out = System.out;
@Override
public void doWithMessage(WebServiceMessage message) throws IOException {
SaajSoapMessage soapMessage = (SaajSoapMessage) message;
SoapEnvelope soapEnvelope = soapMessage.getEnvelope();
SoapHeader soapHeader = soapEnvelope.getHeader();
//Initialize QName for Action and To
QName action = new QName("{uri}","Action","{actionname}");
QName to = new QName("{uri}","To","{actionname}");
soapHeader.addNamespaceDeclaration("{actionname}", "{uri}");
SoapHeaderElement soapHeaderElementAction = soapHeader.addHeaderElement(action);
SoapHeaderElement soapHeaderElementTo = soapHeader.addHeaderElement(to);
soapHeaderElementAction.setText("{text inside the tags}");
soapHeaderElementTo.setText("{text inside the tags}");
soapMessage.setSoapAction("{add soap action uri}");
soapMessage.writeTo(out);
}
}
精彩评论