CXF拦截器介绍

  CXF拦截器是功能的主要实现单元,也是主要的扩展点,可以在不对核心模块进行修改的情况下,动态添加功能。当服务被调用时,会经过多个拦截器链(Interceptor Chain)处理,拦截器链在服务输入(IN)或输出(OUT)阶段实现附加功能,拦截器可以在客户端加入,也可以在服务端加入。

  工作示意图如下:
    

  

  拦截器的拦截阶段:
    拦截器有多个阶段,每个阶段都有多个拦截器。拦截器在哪个阶段起作用,可以在拦截器的构造函数中声明。

输入拦截器有如下几个阶段,这些阶段按照在拦截器中的先后顺序排列。
阶段名称 阶段功能描述
RECEIVE Transport level processing(接收阶段,传输层处理)
(PRE/USER/POST)_STREAM Stream level processing/transformations(流处理/转换阶段)
READ This is where header reading typically occurs(SOAPHeader读取)
(PRE/USER/POST)_PROTOCOL Protocol processing, such as JAX-WS SOAP handlers(协议处理阶段,例如JAX-WS的Handler处理)
UNMARSHAL Unmarshalling of the request(SOAP请求解码阶段)
(PRE/USER/POST)_LOGICAL Processing of the umarshalled request(SOAP请求解码处理阶段)
PRE_INVOKE Pre invocation actions(调用业务处理之前进入该阶段)
INVOKE Invocation of the service(调用业务阶段)
POST_INVOKE Invocation of the outgoing chain if there is one(提交业务处理结果,并触发输入连接器)

    

输出拦截器有如下几个阶段,这些阶段按照在拦截器中的先后顺序排列。
阶段名称 阶段功能描述
SETUP Any set up for the following phases(设置阶段)
(PRE/USER/POST)_LOGICAL Processing of objects about to marshalled
PREPARE_SEND Opening of the connection(消息发送准备阶段,在该阶段创建Connection)
PRE_STREAM 流准备阶段
PRE_PROTOCOL Misc protocol actions(协议准备阶段)
WRITE Writing of the protocol message, such as the SOAP Envelope.(写消息阶段)
MARSHAL Marshalling of the objects
(USER/POST)_PROTOCOL Processing of the protocol message
(USER/POST)_STREAM Processing of the byte level message(字节处理阶段,在该阶段把消息转为字节)
SEND 消息发送

  

  


在CXF中,所有对消息的处理都是通过各种拦截器实现。CXF已经实现了多种拦截器,如操纵消息头、执行认证检查、验证消息数据、日志记录、消息压缩等,有些拦截器在发布服务、访问服务时已经默认添加到拦截器。

日志拦截器

  首先使用CXF搭建好WebService的客户端以及服务端。参照(【WebService】使用CXF开发WebService(四)),下例中使用的是上一篇的工程。

  1、服务器端的日志拦截器:主要是在发布的时候,添加输入和输出日志拦截器。代码如下:

 package com.test.ws.server;

 import java.util.List;

 import javax.xml.ws.Endpoint;

 import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws22.EndpointImpl;
import org.apache.cxf.message.Message; import com.test.ws.HelloWSImpl; /**
* 发布Web Service
* @author H__D
* @date 2017年7月28日 上午11:40:48
*
*/
public class ServerTest { public static void main(String[] args) { //定义WebService的发布地址,这个地址就是提供给外界访问Webervice的URL地址,URL地址格式为:http://ip:端口号/xxxx
String address = "http://127.0.0.1:8989/test-webservice/hellows";
//使用Endpoint类提供的publish方法发布WebService,发布时要保证使用的端口号没有被其他应用程序占用
Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl()); //打印endpoint,可以看到endpoint实际上是一个 org.apache.cxf.jaxws22.EndpointImpl 对象
System.out.println("endpoint -->" + endpoint); //强转为EndpointImpl对象
EndpointImpl endpointImpl = (EndpointImpl) endpoint; //服务端的日志入拦截器
List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
inInterceptors.add(new LoggingInInterceptor()); //服务器端的日志出拦截器
List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors();
outInterceptors.add(new LoggingOutInterceptor()); System.out.println("发布webservice成功!"); }
}

  

  2、客服端的日志拦截器:主要是在调整WebService的时候,添加输入和输出日志拦截器。(注:由于使用的是CXF拦截器,所以客户端也需要添加CXF相应的jar包)
    客户端添加CXF的jar包:
      
    调用代码如下:

 package com.test.ws.client;

 import java.util.List;

 import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.message.Message; import com.test.ws.HelloWS;
import com.test.ws.HelloWSImplService; /**
* 调用WebService的客户端
* @author H__D
* @date 2017年7月28日 下午2:39:24
*
*/
public class WSClient { public static void main(String[] args) {
//创建一个用于产生WebServiceImpl实例的工厂,WebServiceImplService类是wsimport工具生成的
HelloWSImplService factory = new HelloWSImplService();
//通过工厂生成一个WebServiceImpl实例,WebServiceImpl是wsimport工具生成的
HelloWS helloWS = factory.getHelloWSImplPort();
System.out.println(helloWS.getClass()); //发送请求的客户端对象
Client client = ClientProxy.getClient(helloWS); //客户端的日志入拦截器
List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();
inInterceptors.add(new LoggingInInterceptor()); //客户端的日志出拦截器
List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
outInterceptors.add(new LoggingOutInterceptor()); //调用WebService的sayHello方法
String result = helloWS.sayHello("Jack");
System.out.println(result);
} }

  3、发布WebService服务端,然后使用客户端进行调用。控制台输出如下:
    服务端控制台输出:
      
    客户端控制台输出:
      

自定义拦截器

  下面使用cxf自定义拦截器,客户端使用自定义拦截器添加用户信息,服务端使用自定义  拦截器获取用户信息并验证

  1、在服务端工程编写自定义拦截器,验证用户信息,代码如下

 package com.test.wx.interceptor;

 import java.util.List;

 import javax.xml.namespace.QName;

 import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element; /**
* 服务端权限拦截器
* @author H__D
* @date 2017年8月2日 下午2:22:02
*
*/
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> { public AuthInterceptor() {
super(Phase.PRE_INVOKE); //拦截器在调用方法之前拦截SOAP消息
} /**
* 拦截器操作
* 信息如下
* <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
* <soap:Header>
* <authHeader>
* <name>hd</name>
* <password>123456</password>
* </authHeader>
* </soap:Header>
* <soap:Body>
* <ns2:sayHello xmlns:ns2="http://ws.test.com/">
* <arg0>Jack</arg0>
* </ns2:sayHello>
* </soap:Body>
* </soap:Envelope>
*/
@Override
public void handleMessage(SoapMessage msg) throws Fault {
System.out.println("com to auth interceptor..."); //获取SOAP信息的所有Header
List<Header> headers = msg.getHeaders(); if(headers == null || headers.size() < 1)
{
throw new Fault(new IllegalArgumentException("没有Header,拦截器实施拦截"));
} boolean isAuth = false;
//获取Header携带的用户名和密码信息
for (Header header : headers) {
//判断认证信息头
if(new QName("authHeader").equals(header.getName()))
{
//提取认证信息
Element element = (Element) header.getObject();
String name = element.getElementsByTagName("name").item(0).getTextContent();
String password = element.getElementsByTagName("password").item(0).getTextContent(); if(name.equals("hd") && password.equals("123456"))
{
isAuth = true;
break;
}
}
} if(isAuth)
{
System.out.println("认证成功!!!");
}else
{
throw new Fault(new IllegalArgumentException("用户名或密码不正确"));
}
} }

    服务端设置好自定义拦截器,并进行发布,代码如下:

 package com.test.ws.server;

 import java.util.List;

 import javax.xml.ws.Endpoint;

 import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws22.EndpointImpl;
import org.apache.cxf.message.Message; import com.test.ws.HelloWSImpl;
import com.test.wx.interceptor.AuthInterceptor; /**
* 发布Web Service
* @author H__D
* @date 2017年7月28日 上午11:40:48
*
*/
public class ServerTest { public static void main(String[] args) { //定义WebService的发布地址,这个地址就是提供给外界访问Webervice的URL地址,URL地址格式为:http://ip:端口号/xxxx
String address = "http://127.0.0.1:8989/test-webservice/hellows";
//使用Endpoint类提供的publish方法发布WebService,发布时要保证使用的端口号没有被其他应用程序占用
Endpoint endpoint = Endpoint.publish(address, new HelloWSImpl()); //打印endpoint,可以看到endpoint实际上是一个 org.apache.cxf.jaxws22.EndpointImpl 对象
System.out.println("endpoint -->" + endpoint); //强转为EndpointImpl对象
EndpointImpl endpointImpl = (EndpointImpl) endpoint; //服务端的日志入拦截器
List<Interceptor<? extends Message>> inInterceptors = endpointImpl.getInInterceptors();
inInterceptors.add(new LoggingInInterceptor()); //服务端的自定义拦截器:验证用户名和密码
inInterceptors.add(new AuthInterceptor()); //服务器端的日志出拦截器
List<Interceptor<? extends Message>> outInterceptors = endpointImpl.getOutInterceptors();
outInterceptors.add(new LoggingOutInterceptor()); System.out.println("发布webservice成功!"); }
}

  2、在客户端编写自定义拦截器,添加用户信息,代码如下:

 package com.test.interceptor;

 import java.util.List;

 import javax.xml.namespace.QName;

 import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element; /**
* 客户端添加用户信息拦截器
* @author H__D
* @date 2017年8月2日 下午2:47:08
*
*/
public class AddUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> { private String name;
private String password; public AddUserInterceptor(String name, String password) { super(Phase.PRE_PROTOCOL);//准备协议化时拦截
this.name = name;
this.password = password;
} /**
* <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
* <soap:Header>
* <authHeader>
* <name>hd</name>
* <password>123456</password>
* </authHeader>
* </soap:Header>
* <soap:Body>
* <ns2:sayHello xmlns:ns2="http://ws.test.com/">
* <arg0>Jack</arg0>
* </ns2:sayHello>
* </soap:Body>
* </soap:Envelope>
*/
@Override
public void handleMessage(SoapMessage msg) throws Fault {
//获取消息头
List<Header> headers = msg.getHeaders(); //创建文档
Document document = DOMUtils.createDocument();
//创建根目录
Element rootEle = document.createElement("authHeader"); //配置head信息的用户名和密码
Element nameEle = document.createElement("name");
nameEle.setTextContent(name);
Element passwordEle = document.createElement("password");
passwordEle.setTextContent(password); rootEle.appendChild(nameEle);
rootEle.appendChild(passwordEle);
//将信息添加到头
headers.add(new Header(new QName("authHeader"), rootEle));
} }

    客户端添加自定义拦截器,并调用WebService服务,代码如下:

 package com.test.ws.client;

 import java.util.List;

 import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.message.Message; import com.test.interceptor.AddUserInterceptor;
import com.test.ws.HelloWS;
import com.test.ws.HelloWSImplService; /**
* 调用WebService的客户端
* @author H__D
* @date 2017年7月28日 下午2:39:24
*
*/
public class WSClient { public static void main(String[] args) {
//创建一个用于产生WebServiceImpl实例的工厂,WebServiceImplService类是wsimport工具生成的
HelloWSImplService factory = new HelloWSImplService();
//通过工厂生成一个WebServiceImpl实例,WebServiceImpl是wsimport工具生成的
HelloWS helloWS = factory.getHelloWSImplPort();
System.out.println(helloWS.getClass()); //发送请求的客户端对象
Client client = ClientProxy.getClient(helloWS); //客户端的日志入拦截器
List<Interceptor<? extends Message>> inInterceptors = client.getInInterceptors();
inInterceptors.add(new LoggingInInterceptor()); //客户端的日志出拦截器
List<Interceptor<? extends Message>> outInterceptors = client.getOutInterceptors();
outInterceptors.add(new LoggingOutInterceptor()); //添加自定义输出拦截器
outInterceptors.add(new AddUserInterceptor("hd", "123456")); //调用WebService的sayHello方法
String result = helloWS.sayHello("Jack");
System.out.println(result);
} }

  3、服务端控制台输出如下,可以看到自定义拦截器已经启用,并且获取到了用户名和密码进行验证。
      

  4、客户端控制台输出如下,可以看到自定义拦截器已经启用,并且添加了用户名和密码到消息的头里面。
      

  注:通过控制台可以看出,webservice服务器收到的是一段xml,而返回的也是xml,所有在调用webservcie的时候,可以使用ajax的post请求或者java里面HttpURLConnection来发送请求xml,然后获取响应xml进行处理。

【WebService】WebService之CXF的拦截器(五)的更多相关文章

  1. WebService学习总结(五)--CXF的拦截器

    拦截器是Cxf的基础,Cxf中很多的功能都是由内置的拦截器来实现的,拦截器在Cxf中由Interceptor表示.拦截器的作用类似axis2中handle.Cxf的拦截器包括入拦截器和出拦截器,所有的 ...

  2. CXF实战之自己定义拦截器(五)

    CXF已经内置了一些拦截器,这些拦截器大部分默认加入到拦截器链中,有些拦截器也能够手动加入,如手动加入CXF提供的日志拦截器.也能够自己定义拦截器.CXF中实现自己定义拦截器非常easy.仅仅要继承A ...

  3. CXF之五 拦截器Interceptor

    拦截器(Interceptor)是CXF功能最主要的扩展点,可以在不对核心模块进行修改的情况下,动态添加很多功能.拦截器和JAX-WS Handler.Filter的功能类似,当服务被调用时,就会创建 ...

  4. CXF添加拦截器和自定义拦截器

    前面讲了如何采用CXF开发webservice,现在来讲如何添加拦截器和自定义拦截器. 服务端代码: HelloWorld implementor=new HelloWorldImpl(); Stri ...

  5. Apache CXF自定义拦截器

    为什么设计拦截器?1.为了在webservice请求过程中,能动态操作请求和响应数据,CXF设计了拦截器 拦截器分类: 1.按所处的位置分:服务器端拦截器,客户端拦截器. 2.按消息的方向分:入拦截器 ...

  6. CXF 自定义拦截器

    此例子来自apache cxf sample. /**  * Licensed to the Apache Software Foundation (ASF) under one  * or more ...

  7. (八)CXF添加自定义拦截器

    前面我们说到CXF添加内置的拦截器,今天的话,我们来讲下如何添加自定义拦截器: 我们的实例是客户端访问服务端webservice接口要加权限认证. 我们思路先说下.我们可以通过在SOAP消息的Head ...

  8. (七)CXF添加拦截器

    今天开始讲下拦截器,前面大家学过servlet,struts2 都有拦截器概念,主要作用是做一些权限过滤,编码处理等: webservice也可以加上拦截器,我们可以给webservice请求加权限判 ...

  9. 【CXF】- 拦截器 Interceptor

    CXF拦截器 拦截动态操作请求和响应数据 拦截器分类 位置:服务器端拦截器,客户端拦截器 消息方向:入拦截器 出拦截器 定义者:系统拦截器 自定义拦截器:LoggingInInteceptor ①:创 ...

随机推荐

  1. ss源码学习--从协议建立到完成一次代理请求

    上一次介绍了ss源码中各个事件处理函数完成的工作,这次具体分析一下协议的建立以及请求数据的传输过程. 因为ss的local和server共用一个类以及一系列的事件处理函数,所以看起来稍显复杂.下面来将 ...

  2. 【pycharm】使用过程的相关问题

    背景:安装scrapy后在cmd里可以正常import scrapy模块,但是在pycharm里不可以(python2.7) 问题:cmd中能正常导入模块,在pycharm报错 原因:pycharm里 ...

  3. python 进行机器学习

    summary: 本文总结了几种常见的线性回归的的方式以及各种方式的优缺点. 1,简单现性回归(OSL): OSL:就是一种最为简单的普通最小二乘法的实现,y = a0 + a1*x1 + a2*x2 ...

  4. OpenVPN 2.2.1 之后期维护

    一.Openvpn 用户注销 每个公司都会用员工离职,因此注销vpn用户也就成了运维人员日常工作的一部分. 其实Openvpn在设计的时候也想到了这点,我们可以使用 revoke-full shell ...

  5. 进程实时监控pidstat命令详解

    pidstat主要用于监控全部或指定进程占用系统资源的情况,如CPU,内存.设备IO.任务切换.线程等.pidstat首次运行时显示自系统启动开始的各项统计信息,之后运行pidstat将显示自上次运行 ...

  6. 最小生成树算法(krustra+prime)

    给你一个图,求让图连通的边权和最小值 krustra算法是基于加边法,将所有边权排序,每次加一条边,将两个点放在同一个集合中.如果新加的点不在同一个集合中,就合并(并查集) 涉及到排序,可以用结构体存 ...

  7. P3375 【模板】KMP字符串匹配

    P3375 [模板]KMP字符串匹配 https://www.luogu.org/problemnew/show/P3375 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在 ...

  8. Kylin Cube构建过程优化

    原文地址:https://kylin.apache.org/docs16/howto/howto_optimize_build.html Kylin将一个cube的build过程分解为若干个子步骤,然 ...

  9. HUABASE :基于列存储的关系型数据库系统

    摘要   HUABASE 是基于列存储的关系型数据库系统.列存储技术的特点是数据查询效率高,读磁盘少,存储空间少,是构建数据仓库的理想架构. HUABASE 实现了多种数据压缩机制.查询优化和稀疏索引 ...

  10. stark组件之搜索【模仿Django的admin】

    一.先看下django的admin是如何做搜索功能的 配置一个search_fields的列表就可以实现搜索的功能 class testbook(admin.ModelAdmin): # 第一步,定义 ...