java Spring Soap 拦截器如何修改消息的内容?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3207163/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:49:05  来源:igfitidea点击:

How can a Spring Soap interceptor modify the contents of a message?

javaweb-servicessoapspring-ws

提问by Dave

I'm trying to write an interceptor for a web service that will modify the contents of the Soap message before is sent on to the endpoint. If a client sent a message where the value of some element is 1, I want to be able to alter that element to a 2 so that, when the message arrives at the endpoint, it looks as if the client submitted a 2 instead of a 1. I'm not sure if this is a difficult task which is elluding me, or an easy task which I am making harder than it needs to be.

我正在尝试为 Web 服务编写一个拦截器,该服务将在发送到端点之前修改 Soap 消息的内容。如果客户端发送了一条消息,其中某个元素的值为 1,我希望能够将该元素更改为 2,这样当消息到达端点时,客户端看起来好像提交了 2 而不是1. 我不确定这是一项让我感到困惑的困难任务,还是一项我做得比它需要的更难的简单任务。

I have stepped through some of the Spring interceptors; but the validation and logging interceptors don't every alter the message that is in transit. The Wss4jSecurityInterceptor does add some properties to the MessageContext; but I haven't been able to leverage anything that it is doing. I have a shell of an interceptor; but nothing that is doing anything of any value.

我已经通过了一些 Spring 拦截器;但是验证和日志拦截器不会改变传输中的消息。Wss4jSecurityInterceptor 确实向 MessageContext 添加了一些属性;但我一直无法利用它正在做的任何事情。我有一个拦截器的外壳;但没有任何东西有任何价值。

public boolean handleRequest(MessageContext messageContext, Object endpoint)
        throws Exception {

    SaajSoapMessage saajSoapMessage = (SaajSoapMessage) messageContext
            .getRequest();
    SOAPMessage soapMessage = saajSoapMessage.getSaajMessage();
    SOAPBody soapBody = soapMessage.getSOAPBody();

    return true;
}

I was hoping there was a chance that soembody else had already solved this particular problem. Any insight would be appreciated. Thanks.

我希望有其他人已经解决了这个特定问题的机会。任何见解将不胜感激。谢谢。

回答by skaffman

Modifying the payload is a little bit tricky. The only way I've found to make this work is to use the getPayloadSource()and getPayloadResult()methods on SoapBody, which expose javax.xml.transform-friendly objects for manipulating the data.

修改有效载荷有点棘手。我发现使这项工作有效的唯一方法是使用getPayloadSource()getPayloadResult()方法SoapBody,它公开了javax.xml.transform用于操作数据的友好对象。

It's annoyingly heavyweight, but you can do something like this:

这是令人讨厌的重量级,但你可以做这样的事情:

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());

I'd love to see a better way of doing this.

我很想看到一种更好的方式来做到这一点。

回答by Dave

I realized that it was easer to alter the request at a later point. I did not need to modify the original SOAP message, so long as I was able to modify the data before it reached my endpoint.

我意识到稍后更改请求会更容易。我不需要修改原始 SOAP 消息,只要我能够在数据到达我的端点之前修改它。

The endpoints I am working with all extend AbstractDom4jPayloadEndpoint - so I wrapped these endpoints in a proxy that allowed me to modify the request element before proceeding to my endpoint. i.e.:

我使用的端点都扩展了 AbstractDom4jPayloadEndpoint - 所以我将这些端点封装在一个代理中,允许我在继续到我的端点之前修改请求元素。IE:

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 );
    }

回答by K St. Clair

I modified the code in this answer to insert an <authentication/>element into all SOAP body requests:

我修改了这个答案中的代码,将一个<authentication/>元素插入到所有 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;
}

This solution was used because the WebServiceMessageCallback would require me to change the Document, and the SaajSoapMessageFactory is activated before the soap body has been inserted by the configured Jaxb2Marshaller.

使用此解决方案是因为 WebServiceMessageCallback 需要我更改文档,并且在配置的 Jaxb2Marshaller 插入肥皂正文之前激活 SaajSoapMessageFactory。