J'essaye d'écrire un intercepteur pour un service Web qui modifiera le contenu du message de savon avant d'être envoyé au point final. Si un client a envoyé un message où la valeur d'un élément est 1, je veux être en mesure de modifier cet élément en 2 afin que, lorsque le message arrive au point de terminaison, il semble que le client a soumis un 2 au lieu d'un 1. Je ne sais pas si c'est une tâche difficile qui me touche, ou une tâche facile que je fais plus que nécessaire. J'ai franchi certains des intercepteurs à ressort; mais les intercepteurs de validation et de journalisation ne modifient pas tous le message en transit. Le Wss4jSecurityInterceptor ajoute des propriétés au MessageContext; mais je n'ai pas été en mesure de tirer parti de tout ce qu'il fait. J'ai une coquille d'intercepteur; mais rien qui fasse quelque chose de n'importe quelle valeur. J'espérais qu'il y avait une chance que Soembody d'autre avait déjà résolu ce problème particulier. Toute idée serait appréciée. Merci.Comment un intercepteur Spring Soap peut-il modifier le contenu d'un message?
Répondre
La modification de la charge utile est un peu compliquée. La seule façon que j'ai trouvé pour faire ce travail est d'utiliser les méthodes getPayloadSource()
et getPayloadResult()
sur SoapBody
, qui exposent javax.xml.transform
objets-friendly pour manipuler les données.
Il est fâcheusement poids lourd, mais vous pouvez faire quelque chose comme ceci:
Transformer identityTransform = TransformerFactory.newInstance().newTransformer();
DOMResult domResult = new DOMResult();
identityTransform.transform(soapBody.getPayloadSource(), domResult);
Node bodyContent = domResult.getNode(); // modify this
identityTransform.transform(new DOMSource(bodyContent), soapBody.getPayloadResult());
J'aimerais voir une meilleure façon de le faire.
J'ai réalisé qu'il était plus facile de modifier la demande à un moment ultérieur. Je n'avais pas besoin de modifier le message SOAP d'origine, tant que j'étais capable de modifier les données avant qu'elles n'atteignent mon point de terminaison. Les points de terminaison avec lesquels je travaille étendent tous AbstractDom4jPayloadEndpoint - donc j'ai enveloppé ces points de terminaison dans un proxy qui m'a permis de modifier l'élément de demande avant de passer à mon point de terminaison. à savoir:
public class MyProxyEndpoint extends AbstractDom4jPayloadEndpoint
@Override
protected Element invokeInternal(
Element requestElement,
Document responseDocument) throws Exception
{
if(requestElement != null)
{
// alter request element
}
return (Element) this.invokeMethod.invoke(
this.target,
requestElement,
responseDocument);
}
J'ai modifié le code dans cette réponse à insérer un élément <authentication/>
dans toutes les demandes du corps SOAP:
@Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
logger.trace("Enter handleMessage");
try {
SaajSoapMessage request = (SaajSoapMessage) messageContext.getRequest();
addAuthn(request);
} catch (Exception e) {
logger.error(e.getMessage(),e);
}
return true;
}
protected void addAuthn(SaajSoapMessage request) throws TransformerException {
Transformer identityTransform = TransformerFactory.newInstance().newTransformer();
DOMResult domResult = new DOMResult();
identityTransform.transform(request.getPayloadSource(), domResult);
Node bodyContent = domResult.getNode();
Document doc = (Document) bodyContent;
doc.getFirstChild().appendChild(authNode(doc));
identityTransform.transform(new DOMSource(bodyContent), request.getPayloadResult());
}
protected Node authNode(Document doc) {
Element authentication = doc.createElementNS(ns, "authentication");
Element username = doc.createElementNS(ns, "username");
username.setTextContent(authn.getUsername());
Element password = doc.createElementNS(ns, "password");
password.setTextContent(authn.getPassword());
authentication.appendChild(username);
authentication.appendChild(password);
return authentication;
}
On utilise cette solution parce que le WebServiceMessageCallback me demander de changer le document, et SaajSoapMessageFactory est activé avant que le corps de savon ait été inséré par le Jaxb2Marshaller configuré.
Merci. Vous avez raison - ce n'est pas aussi simple qu'on pourrait l'espérer. J'ai effectivement résolu mon problème d'une autre manière. Même si cela ne répond pas directement à ma question initiale - cela a résolu mon problème actuel. – Dave