Interceptor是CXF架构中一个很有特色的模式。你可以在不对核心模块进行修改的情况下,动态添加很多功能。这对于CXF这个以处理消息为中心的服务框架来说是非常有用的,CXF通过在Interceptor中对消息进行特殊处理,实现了很多重要功能模块,例如:日志记录,Soap消息处理,消息的压缩处。简单的说,可以在收到请求后,还未进行业务处理前,进行处理。或者在请求包发送前,进行报文的处理。
Interceptor
定义两个方法,一个处理消息 handleMessage, 一个是处理错误 handleFault。
InterceptorChain
单个的Interceptor功能有限,CXF要实现一个SOAP消息处理,需要将许许多多的Interceptor组合在一起使用。因此设计了 InterceptorChain,在我看了InterceptorChain就像是一个Interceptor的小队长。 小队长有调配安置Interceptor的权力(add,remove),也有控制消息处理的权力(doInterceptor,pause,resume,reset,abort),同时也有交付错误处理的权力( {get|set}FaultObserver)。更有意思的是为灵活控制Interceptor的处理消息顺序(doInterceptStartingAt,doInterceptorStartingAfter),这也是InterceptorChain比较难理解的地方。
Fault
定义了CXF中的错误消息。
InterceptorProvider
这里定义了Interceptor的后备保障部队。我们可以在InterceptorProvider中设置In,Out,InFault,OutFault 后备小分队,添加我们所希望添加的Interceptor。而InterceptorChain会根据这些后备小分队,组建自己的小分队实例,完成具体的作战功能任务。
AbstractAttributedInterceptorProvider
InterceptorProvider实现的抽象类,由于这个类来继承了HashMap,我们可以像这个类中存储一些属性信息。
AbrstractBasicInterceptorProvider
与AbstractAttributedInterceptorProvider不同,这个Interceptor只是简单实现了InterceptorProvider的功能,并不提供对其属性存储的扩展。
Message
由于Interceptor是针对Message来进行处理的,当你打开Message这个类文件时,你会发现在Message中定义了很多常量,同时你还可以从Message中获取到很多与Message操作相关的信息。可以获取设置的对象有InterceptorChain Exchange Destination,还有获取设置Content的泛型接口,是不是感觉Message和Bus差不多,都成了大杂货铺,一切与消息处理相关的信息都可以放在Message中。
服务端拦截器
package hs.cxf.soapHeader; import javax.xml.soap.SOAPException; import javax.xml.soap.SOAPHeader; import javax.xml.soap.SOAPMessage; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.saaj.SAAJInInterceptor; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.AbstractPhaseInterceptor; import org.apache.cxf.phase.Phase; import org.w3c.dom.NodeList; /** * * @Title:获取soap头信息 * * @Description: * * @Copyright: * * @author zz * @version 1.00.000 * */ public class ReadSoapHeader extends AbstractPhaseInterceptor<SoapMessage> { private SAAJInInterceptor saa = new SAAJInInterceptor(); public ReadSoapHeader() { super(Phase.PRE_PROTOCOL); getAfter().add(SAAJInInterceptor.class.getName()); } public void handleMessage(SoapMessage message) throws Fault { SOAPMessage mess = message.getContent(SOAPMessage.class); if (mess == null) { saa.handleMessage(message); mess = message.getContent(SOAPMessage.class); } SOAPHeader head = null; try { head = mess.getSOAPHeader(); } catch (SOAPException e) { e.printStackTrace(); } if (head == null) { return; } try { //读取自定义的节点 NodeList nodes = head.getElementsByTagName("tns:spId"); NodeList nodepass = head.getElementsByTagName("tns:spPassword"); //获取节点值,简单认证 if (nodes.item(0).getTextContent().equals("wdw")) { if (nodepass.item(0).getTextContent().equals("wdwsb")) { System.out.println("认证成功"); } } else { SOAPException soapExc = new SOAPException("认证错误"); throw new Fault(soapExc); } } catch (Exception e) { SOAPException soapExc = new SOAPException("认证错误"); throw new Fault(soapExc); } } }
配置文件中新增拦截器配置
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.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-servlet.xml" /> <bean id="jaxWsServiceFactoryBean" class="org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean"> <property name="wrapped" value="true" /> <property name="dataBinding" ref="aegisBean" /> </bean> <bean id="aegisBean" class="org.apache.cxf.aegis.databinding.AegisDatabinding" /> <jaxws:endpoint id="CollectiveServices" implementor="hs.cxf.server.WebServiceSampleImpl" address="/HelloWorld"> <jaxws:inInterceptors> <!-- 日志拦截器 --> <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> <!-- 自定义拦截器 --> <bean class="hs.cxf.soapHeader.ReadSoapHeader"/> </jaxws:inInterceptors> <jaxws:serviceFactory> <ref bean="jaxWsServiceFactoryBean"/> </jaxws:serviceFactory> </jaxws:endpoint> </beans>
客户端拦截器:
package hs.cxf.client.SoapHeader; import java.util.List; import javax.xml.namespace.QName; import org.apache.cxf.binding.soap.SoapHeader; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor; import org.apache.cxf.headers.Header; import org.apache.cxf.helpers.DOMUtils; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.phase.Phase; import org.w3c.dom.Document; import org.w3c.dom.Element; /** * * @Title:在发送消息前,封装Soap Header 信息 * * @Description: * * @Copyright: * * @author zz * @version 1.00.000 * */ public class AddSoapHeader extends AbstractSoapInterceptor { private static String nameURI="http://127.0.0.1:8080/cxfTest/ws/HelloWorld"; public AddSoapHeader(){ super(Phase.WRITE); } public void handleMessage(SoapMessage message) throws Fault { String spPassword="wdwsb"; String spName="wdw"; QName qname=new QName("RequestSOAPHeader"); Document doc=DOMUtils.createDocument(); //自定义节点 Element spId=doc.createElement("tns:spId"); spId.setTextContent(spName); //自定义节点 Element spPass=doc.createElement("tns:spPassword"); spPass.setTextContent(spPassword); Element root=doc.createElementNS(nameURI, "tns:RequestSOAPHeader"); root.appendChild(spId); root.appendChild(spPass); SoapHeader head=new SoapHeader(qname,root); List<Header> headers=message.getHeaders(); headers.add(head); System.out.println(">>>>>添加header<<<<<<<"); } }
客户端调用时:
package hs.cxf.client; import hs.cxf.client.SoapHeader.AddSoapHeader; import java.util.ArrayList; import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; import org.apache.cxf.endpoint.Client; import org.apache.cxf.frontend.ClientProxy; import org.apache.cxf.interceptor.Interceptor; import org.apache.cxf.jaxws.JaxWsProxyFactoryBean; import org.apache.cxf.transport.http.HTTPConduit; import org.apache.cxf.transports.http.configuration.HTTPClientPolicy; /** * @Title: * * @Description: * * @Copyright: * * @author zz * @version 1.00.000 * */ public class TestClient { /** * 测试1 */ @SuppressWarnings("unchecked") public void testSend1() { try { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); ArrayList<Interceptor> list = new ArrayList<Interceptor>(); // 添加soap header list.add(new AddSoapHeader()); // 添加soap消息日志打印 list.add(new org.apache.cxf.interceptor.LoggingOutInterceptor()); factory.setOutInterceptors(list); factory.setServiceClass(WebServiceSample.class); factory.setAddress("http://127.0.0.1:8080/cxfTest/ws/HelloWorld"); Object obj = factory.create(); System.out.println(obj == null ? "NULL" : obj.getClass().getName()); if (obj != null) { WebServiceSample ws = (WebServiceSample) obj; String str = ws.say("test"); System.out.println(str); str = ws.say("1111"); System.out.println(str); User u = new User(); JAXBElement<String> je = new JAXBElement<String>(new QName( "http://bean.cxf.hs", "name"), String.class, "张三"); u.setName(je); str = ws.sayUserName(u); System.out.println(str); // 通过对象来交互 ReqBean req = new ReqBean(); req.setExp(new JAXBElement<String>(new QName( "http://bean.cxf.hs", "exp"), String.class, "<exp>111<exp>")); req.setSeqId(new JAXBElement<String>(new QName( "http://bean.cxf.hs", "seqId"), String.class, "12345678")); RespBean resp = ws.action(req); System.out.println("resp_id:" + resp.getRespId().getValue()); System.out.println("resp_exp:" + resp.getExp().getValue()); } } catch (Exception ex) { ex.printStackTrace(); } } /** * 测试2 */ @SuppressWarnings("unchecked") public void testSend2() { String webServiceUrl = "http://127.0.0.1:8080/cxfTest/ws/HelloWorld"; String webServiceConTimeout = "60000"; String webServiceRevTimeout = "60000"; JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); ArrayList<Interceptor> list = new ArrayList<Interceptor>(); // 添加soap header 信息 list.add(new AddSoapHeader()); // 添加soap消息日志打印 list.add(new org.apache.cxf.interceptor.LoggingOutInterceptor()); factory.setOutInterceptors(list); factory.setServiceClass(WebServiceSample.class); factory.setAddress(webServiceUrl); WebServiceSample service = (WebServiceSample) factory.create(); //超时时间设置 Client clientP = ClientProxy.getClient(service); HTTPConduit http = (HTTPConduit) clientP.getConduit(); HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy(); httpClientPolicy.setConnectionTimeout(Integer .valueOf(webServiceConTimeout)); httpClientPolicy.setReceiveTimeout(Integer .valueOf(webServiceRevTimeout)); httpClientPolicy.setAllowChunking(false); http.setClient(httpClientPolicy); // 通过对象来交互 ReqBean req = new ReqBean(); req.setExp(new JAXBElement<String>(new QName( "http://bean.cxf.hs", "exp"), String.class, "<exp>111<exp>")); req.setSeqId(new JAXBElement<String>(new QName( "http://bean.cxf.hs", "seqId"), String.class, "12345678")); System.out.println(">>>>>>发送消息<<<<<<<<<"); RespBean resp = service.action(req); System.out.println("resp_id:" + resp.getRespId().getValue()); System.out.println("resp_exp:" + resp.getExp().getValue()); } /** * @param args */ public static void main(String[] args) { TestClient tc = new TestClient(); tc.testSend1(); System.out.println(">>>>>>>>>>>>2<<<<<<<<<<<<<"); tc.testSend2(); System.out.println(">>>>>>>>>>>>END<<<<<<<<<<<<<"); } }