现在一般很少会用到Webservice了,但有时候和第三方传统机构对接,他们用的可能是WebService。这里写下CXF 拦截器的使用。
拦截器分为服务端拦截器和客户端拦截器,又分为入拦截器(in)和出拦截器(out)
先讲述一个Webservice请求过程如下。
1、首先是客户端发起请求,在请求到达服务端之前,我们可以用客户端出拦截器(client out interceptor)进行拦截,比如可以修改下请求报文。
2、客户端发出请求后,接下来应该是服务端接收请求了。服务端接收请求之前可以通过服务端入拦截器(server in interceptor)先进行报文的拦截。
3、服务端接收到请求之后,自身需要处理,处理完请求后,就会进行响应了。在响应抵达客户端之前,我们可以通过服务端出拦截器(server out interceptor)进行相应报文的拦截。
4、接下来是客户端接收响应消息了,在客户端接收响应消息之前,我们可以通过客户端入拦截器(client in interceptor)进行拦截。
借助拦截器我们通常可以用来对报文XML消息体进行修改,比如我们可以根据实际需要修改其命名空间或者甚至XML消息内容。
一般我们要么是在消息发出之前(分为客户端消息发给服务端之前(client out interceptor),或者服务端发消息给客户端响应之前(server out interceptor)进行修改(此时是出拦截器,对应的生命周期阶段是Phase.PRE_STREAM);
或者是消息接收之前(分为服务端接收客户端的消息(server in interceptor),或者是客户端接收服务端响应消息之前(client in interceptor)进行修改(此时是入拦截器,对应生命周期阶段是Phase.RECEIVE))。
上面提到的生命周期阶段要注意,因为消息在不同时间点,所存在的形式是不一样的。我上面提到的生命周期是基于大部分拦截器仅仅是需要对XML报文进行一定的修改。如果需要对消息进行其他处理,请选择合适的阶段。
可以根据实际需要,选择对应的入拦截器或者出拦截器。
首先加入Apache Cxf 相关依赖包,我这里使用的是cxf 3.1.10版本
<!-- cxf Web Service -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.1.10</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.1.10</version>
</dependency>
下面首先提供入拦截器(in interceptor)例子
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* WebService入拦截器
* @author lichuang
*
*/
public class CxfInInterceptor extends AbstractPhaseInterceptor<SoapMessage>{
private static final Logger logger = LoggerFactory.getLogger(CxfInInterceptor.class);
public CxfInInterceptor() {
super(Phase.RECEIVE);
}
@Override
public void handleMessage(SoapMessage message) {
InputStream is = message.getContent(InputStream.class);
if (is != null) {
try {
String str = IOUtils.toString(is);
str=str.replace("str1", "str2");
InputStream ism = new ByteArrayInputStream(str.getBytes());
message.setContent(InputStream.class, ism);
}
catch(IOException e){
logger.error("WebService消息拦截器处理异常!",e);
}
}
}
}
再提供一个出拦截器(out interceptor)的例子
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.helpers.IOUtils;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CxfOutInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private static final Logger logger = LoggerFactory.getLogger(CxfOutInterceptor.class);
public CxfOutInterceptor() {
super(Phase.PRE_STREAM);
}
@Override
public void handleMessage(SoapMessage message) {
OutputStream os = message.getContent(OutputStream.class);
if (os != null) {
try {
/*
* 网上提到当消息体很大时,拦截器获取得到的xml输出报文可能是空的,
* 可以试着将下面的CachedStream换成字节数组流ByteArrayOutputStream
*/
CachedStream cs = new CachedStream();
message.setContent(OutputStream.class, cs);
message.getInterceptorChain().doIntercept(message);
CachedOutputStream csnew = (CachedOutputStream) message.getContent(OutputStream.class);
InputStream in = csnew.getInputStream();
String xml = IOUtils.toString(in);
xml=xml.replace("str1", "str2");
// 这里对xml做处理,处理完后同理,写回流中
IOUtils.copy(new ByteArrayInputStream(xml.getBytes()), os);
cs.close();
os.flush();
message.setContent(OutputStream.class, os);
} catch (IOException e) {
logger.error("WebService消息命名空间拦截器处理异常!", e);
}
}
}
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 {
}
}
}