我通过Spring
和CXF
创建并配置了网络服务。见下面的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>
您可以看到我在我的网络服务中添加了架构验证。但是当请求与架构不对应时,CXF
会抛出SoapFault
。
我想发送给客户SoapMessage
而不是SoapFault
,这就是我添加outFaultInterceptors
的原因。
我的问题是如何将SoapFaul
t转换为SoapMessage
?我做了几次尝试,但我不知道如何实现outFaultInterceptor
。
答案 0 :(得分:16)
可能你忘了设置拦截器阶段及其在拦截器链中的顺序。
尝试这样的事情:
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;
}
}
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;
}
}
<?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();
}
}
答案 1 :(得分:2)
你的拦截器应该实现
org.apache.cxf.interceptor.Interceptor
将调用handleMessage方法的handleFault。参数是两种情况都是
的实例org.apache.cxf.message.Message
你可以打电话
removeContent()
或
setContent()
替换消息。