如何修改出站CXF请求的原始XML消息?

kiw*_*rog 17 java web-services cxf interceptor

我想修改一个传出的SOAP请求.我想从信封的主体中删除2个xml节点.我设法建立一个Interceptor并将生成的消息集的String值获取到端点.

但是,以下代码似乎不起作用,因为未按预期编辑传出消息.有没有人有关于如何做到这一点的一些代码或想法?

public class MyOutInterceptor extends AbstractSoapInterceptor {

public MyOutInterceptor() {
        super(Phase.SEND); 
}

public void handleMessage(SoapMessage message) throws Fault { 
        // Get message content for dirty editing...
        StringWriter writer = new StringWriter();
        CachedOutputStream cos  = (CachedOutputStream)message.getContent(OutputStream.class); 
        InputStream inputStream = cos.getInputStream();
        IOUtils.copy(inputStream, writer, "UTF-8");
        String content = writer.toString();

        // remove the substrings from envelope...
        content = content.replace("<idJustification>0</idJustification>", "");
        content = content.replace("<indicRdv>false</indicRdv>", "");
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        outputStream.write(content.getBytes(Charset.forName("UTF-8")));
        message.setContent(OutputStream.class, outputStream);
} 
Run Code Online (Sandbox Code Playgroud)

sno*_*ndy 36

根据第一条评论,我创建了一个抽象类,可以很容易地用来改变整个肥皂信封.

以防万一有人想要一个现成的代码部分.

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.io.IOUtils;
import org.apache.cxf.binding.soap.interceptor.SoapPreProtocolOutInterceptor;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.log4j.Logger;

/**
 * http://www.mastertheboss.com/jboss-web-services/apache-cxf-interceptors
 * http://stackoverflow.com/questions/6915428/how-to-modify-the-raw-xml-message-of-an-outbound-cxf-request
 * 
 */
public abstract class MessageChangeInterceptor extends AbstractPhaseInterceptor<Message> {

    public MessageChangeInterceptor() {
        super(Phase.PRE_STREAM);
        addBefore(SoapPreProtocolOutInterceptor.class.getName());
    }

    protected abstract Logger getLogger();

    protected abstract String changeOutboundMessage(String currentEnvelope);

    protected abstract String changeInboundMessage(String currentEnvelope);

    public void handleMessage(Message message) {
        boolean isOutbound = false;
        isOutbound = message == message.getExchange().getOutMessage()
                || message == message.getExchange().getOutFaultMessage();

        if (isOutbound) {
            OutputStream os = message.getContent(OutputStream.class);

            CachedStream cs = new CachedStream();
            message.setContent(OutputStream.class, cs);

            message.getInterceptorChain().doIntercept(message);

            try {
                cs.flush();
                IOUtils.closeQuietly(cs);
                CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);

                String currentEnvelopeMessage = IOUtils.toString(csnew.getInputStream(), "UTF-8");
                csnew.flush();
                IOUtils.closeQuietly(csnew);

                if (getLogger().isDebugEnabled()) {
                    getLogger().debug("Outbound message: " + currentEnvelopeMessage);
                }

                String res = changeOutboundMessage(currentEnvelopeMessage);
                if (res != null) {
                    if (getLogger().isDebugEnabled()) {
                        getLogger().debug("Outbound message has been changed: " + res);
                    }
                }
                res = res != null ? res : currentEnvelopeMessage;

                InputStream replaceInStream = IOUtils.toInputStream(res, "UTF-8");

                IOUtils.copy(replaceInStream, os);
                replaceInStream.close();
                IOUtils.closeQuietly(replaceInStream);

                os.flush();
                message.setContent(OutputStream.class, os);
                IOUtils.closeQuietly(os);

            } catch (IOException ioe) {
                getLogger().warn("Unable to perform change.", ioe);
                throw new RuntimeException(ioe);
            }
        } else {
            try {
                InputStream is = message.getContent(InputStream.class);
                String currentEnvelopeMessage = IOUtils.toString(is, "UTF-8");
                IOUtils.closeQuietly(is);

                if (getLogger().isDebugEnabled()) {
                    getLogger().debug("Inbound message: " + currentEnvelopeMessage);
                }

                String res = changeInboundMessage(currentEnvelopeMessage);
                if (res != null) {
                    if (getLogger().isDebugEnabled()) {
                        getLogger().debug("Inbound message has been changed: " + res);
                    }
                }
                res = res != null ? res : currentEnvelopeMessage;

                is = IOUtils.toInputStream(res, "UTF-8");
                message.setContent(InputStream.class, is);
                IOUtils.closeQuietly(is);
            } catch (IOException ioe) {
                getLogger().warn("Unable to perform change.", ioe);

                throw new RuntimeException(ioe);
            }
        }
    }

    public void handleFault(Message message) {
    }

    private class CachedStream extends CachedOutputStream {
        public CachedStream() {
            super();
        }

        protected void doFlush() throws IOException {
            currentStream.flush();
        }

        protected void doClose() throws IOException {
        }

        protected void onWrite() throws IOException {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个解决方案非常有效,多亏了一点:-) (2认同)
  • 非常好!谢谢! (2认同)
  • 如果有人对如何将其附加到生成的Apache Cxf客户端感兴趣,应该只使用`Client client = ClientProxy.getClient(someServicePort);。client.getInInterceptors()。add(new MessageChangeInterceptor(){..});`因此可以修改RAW响应 (2认同)
  • 抱歉...这是一个严重损坏的代码。它“可能”有效,但根据 @shx 的经验,这纯粹是运气。输入和输出流无缘无故地被创建,当它们为空时刷新,无缘无故地交换到消息中,当作者没有打开它们时关闭(意味着可能存在流的双重关闭),等等。另外,如果消息写入是通过编写器而不是输出流完成的(例如,带有 messageType = TEXT 的 JMS 上的 SOAP),那么它根本不起作用。基本原理是好的(使用拦截器,访问流......),但实现确实是错误的。 (2认同)

Jpn*_*pnh 19

我今天也遇到了这个问题.经过多次哭泣和咬牙切齿之后,我能够改变CXF源附带的configuration_interceptor演示中的StreamInterceptor类:

OutputStream os = message.getContent(OutputStream.class);
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);

message.getInterceptorChain().doIntercept(message);

try {
    cs.flush();
    CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);

    String soapMessage = IOUtils.toString(csnew.getInputStream());
    ...
Run Code Online (Sandbox Code Playgroud)

soapMessage变量将包含完整的SOAP消息.您应该能够操作soap消息,将其刷新到输出流并进行message.setContent(OutputStream.class...调用以对消息进行修改.这没有保修,因为我自己对CXF很新!

注意:CachedStream是StreamInterceptor类中的私有类.不要忘记将拦截器配置为在PRE_STREAM阶段运行,以便SOAP拦截器有机会编写SOAP消息.