【问题标题】:How to transform SoapFault to SoapMessage via Interceptor in CXF?如何通过 CXF 中的拦截器将 SoapFault 转换为 SoapMessage?
【发布时间】:2011-12-25 08:57:05
【问题描述】:

我通过SpringCXF 创建和配置了网络服务。请参阅下面的 bean:

<?xml version="1.0" encoding="UTF-8"?>
<beans <!-- ommited -->>
    <import resource="classpath:META-INF/cxf/cxf.xml" />
    <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml" />

    <bean id="internalActService" class="package.InternalActServiceImpl" />

    <jaxws:endpoint implementor="#internalActService" address="/InternalActService">
        <jaxws:properties>
            <entry key="schema-validation-enabled" value="true" />
        </jaxws:properties>

        <jaxws:outFaultInterceptors>
            <bean class="package.InternalActServiceFaultOutInterceptor" />
        </jaxws:outFaultInterceptors>
    </jaxws:endpoint>
</beans>

如您所见,我向我的 Web 服务添加了模式验证。但是当请求与架构不对应时,CXF 会抛出 SoapFault。 我想发送给客户SoapMessage 而不是SoapFault,这就是我添加outFaultInterceptors 的原因。

我的问题是如何将SoapFault 转换为SoapMessage?我做了几次尝试,但我不知道如何实现outFaultInterceptor

【问题讨论】:

    标签: java web-services jax-ws cxf


    【解决方案1】:

    你的拦截器应该实现

    org.apache.cxf.interceptor.Interceptor

    将调用handleMessage 方法的handleFault。参数是这两种情况都会是

    的实例

    org.apache.cxf.message.Message

    你可以调用那个

    removeContent()
    

    setContent()
    

    替换消息。

    【讨论】:

    • 不幸的是,我正在寻找更具体的答案。我的InternalActServiceFaultOutInterceptor 扩展了AbstractSoapInterceptor。在handleMessage 方法中,我试图通过删除异常来切换响应:soapMessage.removeContent(java.lang.Exception.class) 并通过soapMessage.setContent(RegisterDocumentResponse.class, content); 设置不同的内容。尽管事实上soapMessage.getContentFormats()shows [class package.RegisterDocumentResponse, class java.io.OutputStream, interface javax.xml.stream.XMLStreamWriter] web 服务客户端仍然看到&lt;soap:Fault&gt;
    • 您可能应该仔细检查是否从消息中删除了所有内容,那里可能还有一些东西。如果这不起作用,您总是可以退回到蛮力解决方案并添加一个 servlet 过滤器来完成这项工作,虽然不好,但可以工作......
    • 我不确定它是否一直在工作:stackoverflow.com/questions/37984617/…
    【解决方案2】:

    可能您忘记设置拦截器阶段及其在拦截器链中的顺序。

    试试这样的:

    package org.foo.bar;
    
    import org.apache.cxf.binding.soap.SoapMessage;
    import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
    import org.apache.cxf.interceptor.AttachmentOutInterceptor;
    import org.apache.cxf.interceptor.Fault;
    import org.apache.cxf.interceptor.StaxOutInterceptor;
    import org.apache.cxf.message.Message;
    import org.apache.cxf.message.MessageContentsList;
    import org.apache.cxf.phase.AbstractPhaseInterceptor;
    import org.apache.cxf.phase.Phase;
    
    import java.util.Arrays;
    import java.util.List;
    
    public class InternalActServiceFaultOutInterceptor extends AbstractSoapInterceptor {
    
        public InternalActServiceFaultOutInterceptor() {
            super(Phase.PRE_STREAM);
            addBefore(Arrays.asList(StaxOutInterceptor.class.getName(), AttachmentOutInterceptor.class.getName()));
        }
    
        @Override
        public void handleMessage(SoapMessage message) throws Fault {
            Exception exception = message.getContent(Exception.class);
            if(exception != null) {
                message.getExchange().put(Exception.class, null);
    
                for(Class<?> contentFormat : message.getContentFormats()) {
                    message.setContent(contentFormat, null);
                }
    
                message.setContent(List.class, new MessageContentsList(createSoapMessage(RegisterDocumentResponse.class)));
            }
        }
    
        protected <T> T createSoapMessage(Class<T> messageType) {
            // create your message
            return null;
        }
    
    }
    

    -编辑-

    这是一个适合我的单元测试。能够将 POJO 发送到输出有点棘手。我想如果自己构建 DOM 会简单得多。

    拦截器

    package foo.bar;
    
    import java.util.Arrays;
    import java.util.List;
    
    import org.apache.cxf.binding.soap.SoapMessage;
    import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
    import org.apache.cxf.endpoint.Endpoint;
    import org.apache.cxf.interceptor.Fault;
    import org.apache.cxf.interceptor.Interceptor;
    import org.apache.cxf.interceptor.InterceptorChain;
    import org.apache.cxf.interceptor.OutgoingChainInterceptor;
    import org.apache.cxf.message.Exchange;
    import org.apache.cxf.message.Message;
    import org.apache.cxf.message.MessageContentsList;
    import org.apache.cxf.phase.Phase;
    import org.apache.cxf.service.model.BindingMessageInfo;
    import org.apache.cxf.service.model.BindingOperationInfo;
    import org.apache.cxf.service.model.MessageInfo;
    import org.apache.cxf.service.model.OperationInfo;
    import org.apache.cxf.service.model.ServiceModelUtil;
    import org.apache.cxf.ws.policy.PolicyOutInterceptor;
    
    public class InternalActServiceFaultOutInterceptor extends AbstractSoapInterceptor {
    
        public InternalActServiceFaultOutInterceptor() {
            super(Phase.SETUP);
            addBefore(Arrays.asList(PolicyOutInterceptor.class.getName()));
        }
    
        @Override
        public void handleMessage(SoapMessage message) throws Fault {
            Exchange exchange = message.getExchange();
    
            resetOrigInterceptorChain(message);
            resetFault(exchange);
    
            Message outMessage = createOutMessage(exchange);
    
            InterceptorChain chain = prepareNewInterceptorChain(exchange);
            chain.doIntercept(outMessage);
        }
    
        private InterceptorChain prepareNewInterceptorChain(Exchange exchange) {
            Message message = exchange.getOutMessage();
            bind(message);
    
            InterceptorChain chain = OutgoingChainInterceptor.getOutInterceptorChain(exchange);
            message.setInterceptorChain(chain);
    
            return chain;
        }
    
        private Message createOutMessage(Exchange exchange) {
            Endpoint ep = exchange.get(Endpoint.class);
    
            Message outMessage = ep.getBinding().createMessage();
            outMessage.setExchange(exchange);
            outMessage.setContent(List.class, new MessageContentsList(createSoapMessage()));
    
            exchange.setOutMessage(outMessage);
            return outMessage;
        }
    
        private void resetFault(Exchange exchange) {
            exchange.put(Exception.class, null);
        }
    
        private void resetOrigInterceptorChain(SoapMessage message) {
            InterceptorChain chain = message.getInterceptorChain();
            for(Interceptor<?> interceptor : chain) {
                chain.remove(interceptor);
            }
            chain.reset();
        }
    
        private void bind(Message message) {
            Exchange exchange = message.getExchange();
            BindingOperationInfo bop = unwrap(message.getExchange().getBindingOperationInfo());
    
            message.put(MessageInfo.class, bop.getOperationInfo().getOutput());
            message.put(BindingMessageInfo.class, bop.getOutput());
    
            bop = unwrap(ServiceModelUtil.getOperationForWrapperElement(exchange, bop.getName(), false));
    
            exchange.put(BindingOperationInfo.class, bop);
            if (bop != null) {
                exchange.put(BindingOperationInfo.class, bop);
                exchange.put(OperationInfo.class, bop.getOperationInfo());
            }
        }
    
        private BindingOperationInfo unwrap(BindingOperationInfo bop) {
            while(bop.getUnwrappedOperation() != null) {
                bop = bop.getUnwrappedOperation();
                return bop;
            }
            return bop;
        }
    
        protected Echo createSoapMessage() {
            Echo e = new Echo();
            e.setValue("Bye World!");
            return e;
        }
    
    }
    

    请求/响应 POJO

    package foo.bar;
    
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlType;
    
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "EchoType")
    public class Echo {
        private String value;
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
    }
    

    网络服务

    package foo.bar;
    
    import javax.jws.WebService;
    
    @WebService
    public class InternalActServiceImpl {
        public Echo echo(Echo val) {
            return val;
        }
    }
    

    Spring 上下文:CxfInterceptorTest-context.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:jaxws="http://cxf.apache.org/jaxws"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
    ">
    
        <import resource="classpath:META-INF/cxf/cxf.xml" />
        <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
        <import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />
        <import resource="classpath:META-INF/cxf/cxf-extension-jaxws.xml" />
    
        <bean id="internalActService" class="foo.bar.InternalActServiceImpl" />
    
        <jaxws:endpoint implementor="#internalActService" address="http://localhost:9080/InternalActService">
            <jaxws:properties>
                <entry key="schema-validation-enabled" value="true" />
            </jaxws:properties>
            <jaxws:outFaultInterceptors>
                <bean class="foo.bar.InternalActServiceFaultOutInterceptor" />
            </jaxws:outFaultInterceptors>
        </jaxws:endpoint>
    

    单元测试

    package foo.bar;
    
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    import org.junit.Assert;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration
    public class CxfInterceptorTest {
    
        private static final String REQ =
                "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:bar=\"http://bar.foo/\">\r\n" +
                "   <soapenv:Header/>\r\n" +
                "   <soapenv:Body>\r\n" +
                "      <bar:echo>\r\n" +
                "         <arg0>\r\n" +
                "            <value1>Hello World</value1>\r\n" +
                "         </arg0>\r\n" +
                "      </bar:echo>\r\n" +
                "   </soapenv:Body>\r\n" +
                "</soapenv:Envelope>";
    
        @Test
        public void validate() throws Exception {
            String s = call();
            Assert.assertTrue(s.contains("Bye World!"));
        }
    
        private String call() throws Exception {
            URL url = new URL("http://localhost:9080/InternalActService");
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    
            conn.setDoOutput(true);
            conn.setInstanceFollowRedirects(true);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
            conn.setRequestProperty("SOAPAction", "");
    
            OutputStream os = conn.getOutputStream();
            os.write(REQ.getBytes());
            os.flush();
            os.close();
    
            final int buffSize = 1024;
            byte[] buff = new byte[1024];
            InputStream is = conn.getInputStream();
    
            StringBuilder builder = new StringBuilder(buffSize);
            for(int readBytes = -1; (readBytes = is.read(buff, 0, buffSize)) != -1; ) {
                builder.append(new String(buff, 0, readBytes));
            }
    
            is.close();
    
            return builder.toString();
        }
    
    }
    

    【讨论】:

    • 我的代码有一点小问题,我想要的只是重置错误和一条新的肥皂消息,但我还需要在某个时候添加 ws-addressing ,这不是对我来说,有什么建议吗? p.s.我在 Mule ESB 中做这一切。
    猜你喜欢
    • 1970-01-01
    • 2017-08-02
    • 2023-04-07
    • 2015-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-03
    • 1970-01-01
    相关资源
    最近更新 更多