Web Service学习之七:CXF拦截器
一、用途
CXF拦截器类似Struts2的拦截器,后者是拦截和处理请求,前者是对发送和接收的sope消息进行处理,一般用于WS请求响应中的权限验证、日志记录,Soap消息处理,消息的压缩处理等;
这个拦截器可以直接访问和修改sope消息。
拿权限验证举例:
二、服务端添加拦截器
三种方式:JaxWsServerFactoryBean、Endpoint都可以通过getInInterceptors方法,向WebService服务添加拦截器,还可以自定义拦截器
1、Endpoint方式
package ws; import javax.xml.ws.Endpoint;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.EndpointImpl; import ws.impl.HelloWordImpl; public class ServerMain
{
public static void main(String[] args)
{
HelloWordI hw = new HelloWordImpl();
EndpointImpl ep = (EndpointImpl)Endpoint.publish("http://192.168.0.105/test", hw);
//添加In拦截器
ep.getInInterceptors().add(new LoggingInInterceptor());
//添加Out拦截器
ep.getOutInterceptors().add(new LoggingOutInterceptor());
System.out.println("WebService 暴露成功!");
} }
2、JaxWsServerFactoryBean方式
package ws; import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean; import ws.impl.HelloWordImpl; public class ServerMain
{
public static void main(String[] args)
{
HelloWordImpl hw = new HelloWordImpl();
//EndpointImpl ep = (EndpointImpl)Endpoint.publish("http://192.168.0.105/test", hw);
//添加In拦截器
//ep.getInInterceptors().add(new LoggingInInterceptor());
//添加Out拦截器
//ep.getOutInterceptors().add(new LoggingOutInterceptor()); JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
factory.setAddress("http://192.168.0.105/test");
factory.setServiceClass(HelloWordI.class);
factory.setServiceBean(hw);
factory.getInInterceptors().add(new LoggingInInterceptor());
factory.getOutInterceptors().add(new LoggingOutInterceptor());
factory.create();
System.out.println("WebService 暴露成功!");
} }
以上两种方式 实现了接口InterceptorProvider:拦截器链InterceptorChain由许多Interceptor组成,Cxf中定义了一个接口InterceptorProvider,通过该接口可以获取到与当前对象绑定的拦截器链里面的所有拦截器,当我们需要往某对象现有的拦截器链里面添加拦截器的时候我们就可以往通过InterceptorProvider获取到的对应拦截器列表中添加相应的拦截器来实现。InterceptorProvider的定义如下。
public interface InterceptorProvider {
List<Interceptor<?extends Message>>getInInterceptors();
List<Interceptor<?extends Message>>getOutInterceptors();
List<Interceptor<?extends Message>>getInFaultInterceptors();
List<Interceptor<?extends Message>>getOutFaultInterceptors();
}
3、创建自定义拦截器
CXF已经实现了很多种拦截器,很多已经在发布、访问Web 服务时已经默认添加到拦截器链。一般情况下, 我们自己的拦截器只要继承AbstractPhaseInterceptor<T extends org.apache.cxf.message.Message>类即可(也可以实现PhaseInterceptor<T>接口),这个类可以指定继承它的拦截器在什么阶段被启用,阶段属性可以通过org.apache.cxf.phase.Phase 中的常量指定值。
package ws.interceptor; import java.util.List; 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;
import org.w3c.dom.NodeList; /**
* 类说明
* @author wangjunyu
* @createDate 2016-10-20 下午8:34:24
* @version V1.0
*/
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage>
{
//构造方法指定拦截器在什么地方生效
//Phase中常量指定生效位置 如PRE_INVOKE表示调用之前拦截
//RECEIVE 接收消息阶段有效 即使配置在OutInterceptor 的集合中也无效
public AuthInterceptor()
{
super(Phase.PRE_INVOKE);
} /**
* 自定义拦截器需要实现handleMessage方法,该方法抛出Fault异常,可以自定义异常继承自Fault,
* 也可以new Fault(new Throwable())
*/
public void handleMessage(SoapMessage sope) throws Fault
{
System.out.println("开始验证用户信息!");
List<Header> headers = sope.getHeaders();
if (headers == null || headers.size() < 1)
{
throw new Fault(new IllegalArgumentException("找不到Header,无法验证用户信息"));
} Header header = headers.get(0);
Element el = (Element)header.getObject();
NodeList users = el.getElementsByTagName("username");
NodeList passwords = el.getElementsByTagName("password");
if (users.getLength() < 1)
{
throw new IllegalArgumentException("找不到用户信息");
}
String username = users.item(0).getTextContent().trim(); if (passwords.getLength() < 1)
{
throw new IllegalArgumentException("找不到用户密码");
} String password = passwords.item(0).getTextContent().trim(); //检查用户名和密码是否正确
if(!"admin".equals(username) || !"admin".equals(password))
{
throw new Fault(new IllegalArgumentException("用户名或密码不正确"));
}
else
{
System.out.println("用户名密码正确允许访问");
}
} }
三、客户端添加拦截器
package ws.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 wangjunyu
* @createDate 2016-10-20 下午8:53:16
* @version V1.0
*/
public class ClientLoginInterceptor extends AbstractPhaseInterceptor<SoapMessage>
{ public ClientLoginInterceptor(String username, String password)
{
super(Phase.PREPARE_SEND);
this.username = username;
this.password = password;
} private String username;
private String password; public String getUsername() {
return username;
} public void setUsername(String username) {
this.username = username;
} public String getPassword() {
return password;
} public void setPassword(String password) {
this.password = password;
} public void handleMessage(SoapMessage soap) throws Fault
{
List<Header> headers = soap.getHeaders();
Document doc = DOMUtils.createDocument();
Element auth = doc.createElement("authrity");
Element username = doc.createElement("username");
Element password = doc.createElement("password"); username.setTextContent(this.username);
password.setTextContent(this.password); auth.appendChild(username);
auth.appendChild(password); headers.add(0, new Header(new QName("tiamaes"),auth));
} }
package ws; import org.apache.cxf.endpoint.Client;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory; import ws.interceptor.ClientLoginInterceptor; /**
* 类说明
* @author wangjunyu
* @createDate 2016-7-10 上午11:24:09
* @version V1.0
*/
public class ClientMain { /**
* 获取客户端的两种方式*/
public static void main(String[] args)
{
/*
HelloWordImpl hwproxy = new HelloWordImpl();
HelloWordI hw= hwproxy.getHelloWordImplPort();
Client client = ClientProxy.getClient(hw);
client.getInInterceptors().add(new LoggingInInterceptor());
client.getOutInterceptors().add(new LoggingOutInterceptor());
User a = new User();
a.setName("哈哈");
List<User> t = hw.getUsers(a);
//System.out.println(t.get(0).getName());
StringUser u = hw.getSecUsers();
System.out.println(u.getValues().get(0).getValue().getName());
System.out.println(u.getValues().get(1).getValue().getName());
*/ JaxWsDynamicClientFactory dcf = JaxWsDynamicClientFactory.newInstance();
Client client = dcf.createClient("http://192.168.0.104/test?wsdl");
client.getInInterceptors().add(new LoggingInInterceptor());
client.getOutInterceptors().add(new ClientLoginInterceptor("admin","admin"));
try
{
Object[] objs = client.invoke("syaHello", "Tom");
System.out.println(objs[0].toString());
}
catch (Exception e)
{
e.printStackTrace();
}
} }
四、SpringMVC中配置拦截器
1、cxf配置文件方式
1.1 单个拦截器配置
<?xml version="1.0" encoding="UTF-8"?>
<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-servlet.xml" /> <!-- 单个拦截器 -->
<bean id="inMessageInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" />
<bean id="outMessageInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor"/>
<bean id="authorInterceptor" class="com.buss.app.interceptor.AuthInterceptor"/> <!-- 登录验证服务 -->
<jaxws:endpoint id="LoginServiceI" implementor="com.buss.app.login.LoginServiceImpl" address="/LoginService">
<!-- 输入日志拦截器 -->
<jaxws:inInterceptors>
<ref bean="inMessageInterceptor"/>
<ref bean="authorInterceptor"/>
</jaxws:inInterceptors>
<!-- 输出日志拦截器 -->
<jaxws:outInterceptors>
<ref bean="outMessageInterceptor"/>
</jaxws:outInterceptors> </jaxws:endpoint>
<!-- APP首页服务 -->
<jaxws:endpoint id="HomeServiceI" implementor="com.buss.app.home.HomeServiceImpl" address="/HomeService" /> </beans>
1.2 捆绑拦截器打包配置
由于不光CXF内置有拦截器,而且还可以自定义拦截器。这样WebServcie的SEI可能配置多个、一大堆拦截器,这样很不方便。在Struts2中可以自定义拦截器,他还提供了自定义拦截器堆栈的功能,将多个拦截器捆绑在一起使用。这样不必要一个一个的去注册拦截器。在CXF中也有类似功能,可以将拦截器捆绑在一起,你就可以将它注册到你要使用的地方,而不必一个一个拦截器的注册使用。 实现拦截器的捆绑过程非常的简单,继承AbstractFeature 类来实现一个新的特征, 只需要覆盖initializeProvider 方法即可。其实Feature 就是将一组拦截器放在其中,然后一并注册使用。
具体如下:
首先定义一个捆绑拦截器类
package com.buss.app.interceptor; import org.apache.cxf.Bus;
import org.apache.cxf.feature.AbstractFeature;
import org.apache.cxf.interceptor.InterceptorProvider;
import org.apache.cxf.interceptor.LoggingInInterceptor;
import org.apache.cxf.interceptor.LoggingOutInterceptor; public class PackageInterceptorFeature extends AbstractFeature
{ protected void initializeProvider(InterceptorProvider provider, Bus bus)
{
provider.getInInterceptors().add(new LoggingInInterceptor());
provider.getInInterceptors().add(new AuthInterceptor());
provider.getOutInterceptors().add(new LoggingOutInterceptor());
} }
然后再在配置文件使用<jaxws:features>一起配置
<?xml version="1.0" encoding="UTF-8"?>
<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-servlet.xml" /> <!-- 登录验证服务 -->
<jaxws:endpoint id="LoginServiceI" implementor="com.buss.app.login.LoginServiceImpl" address="/LoginService">
<!-- 捆绑拦截器 -->
<jaxws:features>
<bean class="com.buss.app.interceptor.PackageInterceptorFeature"></bean>
</jaxws:features>
</jaxws:endpoint>
<!-- APP首页服务 -->
<jaxws:endpoint id="HomeServiceI" implementor="com.buss.app.home.HomeServiceImpl" address="/HomeService" /> </beans>
2、注解配置拦截器
Cxf为四种类型的拦截器都提供了对应的注解,以方便用户直接在SEI上进行配置,对应的注解如下。
- org.apache.cxf.interceptor.InInterceptors
- org.apache.cxf.interceptor.InFaultInterceptors
- org.apache.cxf.interceptor.OutInterceptors
- org.apache.cxf.interceptor.OutFaultInterceptors
每个注解都对应有两个属性,String[]类型的interceptors和Class<? extends Interceptor<? extendsMessage>>[]类型的classes,其中interceptors用来指定需要配置的拦截器的全名称,而classes则用来指定需要配置的拦截器的类。以下是一个在SEI上通过@InInterceptor配置了入拦截器LogInterceptor的示例。
@InInterceptors(classes={LogInterceptor.class})
@WebService
public interface HelloWorld {
public String sayHi(String who);
}
如果在配置的时候既使用了classes属性配置,又使用了interceptors属性配置,那么两个配置都会生效。如下代码就相当于我们配置了两个自定义的拦截器LogInterceptor到HelloWorld服务的入拦截器链中。
@InInterceptors(classes={LogInterceptor.class}, interceptors={"com.tiantian.cxftest.interceptor.LogInterceptor"})
@WebService
public interface HelloWorld {
public String sayHi(String who);
}
使用注解的方式配置其它拦截器的方式是类似的。使用注解在服务端的SEI上配置的拦截器会作用在服务端,如果客户端与服务端不在一起,需要单独在客户端上配置拦截器,也可以直接在客户端对应的SEI上通过上述四个注解进行配置,方法是一样的。
五、常用内置拦截器
日志拦截器:LoggingInInterceptor 入拦截器日志 LoggingOutInterceptor 出拦截器日志
参考:
CXF-API http://cxf.apache.org/javadoc/latest/
http://elim.iteye.com/blog/2248620#_Toc431737706
http://yufenfei.iteye.com/blog/1688133
http://blog.csdn.net/jaune161/article/details/25602655
Web Service学习之七:CXF拦截器的更多相关文章
- Web Service学习-CXF开发Web Service实例demo(一)
Web Service是什么? Web Service不是框架.更甚至不是一种技术. 而是一种跨平台,跨语言的规范 Web Service解决什么问题: 为了解决不同平台,不同语言所编写的应用之间怎样 ...
- CXF拦截器(Interceptor)LoggingInInterceptor
Interceptor是CXF架构中一个重要的功能.你可以在不对核心模块进行修改的情况下,动态添加很多功能(你可以想象Struts2拦截器的优点).这对于CXF这个以处理消息为中心的服务框架来说是非常 ...
- springMVC学习(12)-使用拦截器
一.拦截器配置和测试: 1)定义两个拦截器,(要实现HandlerInterceptor接口) HandlerInterceptor1: package com.cy.interceptor; imp ...
- CXF 入门:创建一个基于SOAPHeader的安全验证(CXF拦截器使用)
CXF拦截器使用,创建一个使用SOAPHeader的安全验证xml格式: <soap:Header> <auth:authentication xmlns:auth="ht ...
- Web Service学习笔记:动态调用WebService
原文:Web Service学习笔记:动态调用WebService 多数时候我们通过 "添加 Web 引用..." 创建客户端代理类的方式调用WebService,但在某些情况下我 ...
- SpringMVC学习08(拦截器)
8.拦截器 概述 SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理.开发者可以自己定义一些拦截器来实现特定的功能. 过滤器与拦截器的区别: ...
- Web Service学习-CXF开发Web Service的权限控制(二)
Web Service怎样进行权限控制? 解决思路:server端要求input消息总是携带实username.password信息,假设没实username和password信息.直接拒绝调用 解决 ...
- Web Service学习之六:CXF解决无法处理的数据类型
CXF不能够处理像Map复杂的数据类型,需要单独转换处理. 总体思路:创建一个转换器和一个对应的可以处理的数据结构类型,将不能处理的类型转换成可以处理的类型: 步骤: 一.创建一个可以处理的类型 举例 ...
- CXF - 拦截器获取调用方法
没想到要弄这么一个东西. 起初只是想用interceptor记录一下webservice调用日志,后来却被要求在页面展示. 展示容易,但只是展示webservice的地址无法让用户从中明白什么. 那么 ...
随机推荐
- Support Library官方教程(2)各支援包的特性详介(含表)*
快速阅读 包名 作用 位置 是否有资源 v4 提供了最多的api <sdk>/extras/android/support/v4/ y Multidex 把DEX文件生成apk < ...
- Miller-Rabin素数测试学习小计
1.Miller-Rabin是干啥的?它是用来检测一个数字(一般是很大的数字)是不是素数: 2.Miller-Rabin算法基于的两个定理: (1)费尔马小定理:如果p是一个素数,且0<a< ...
- Java 包装类 自动装箱和拆箱
包装类(Wrapper Class) 包装类是针对于原生数据类型的包装. 因为有8个原生数据类型,所以对应有8个包装类. 所有的包装类(8个)都位于java.lang下. Java中的8个包装类分别是 ...
- [POJ2377]Bad Cowtractors(最大生成树,Kruskal)
题目链接:http://poj.org/problem?id=2377 于是就找了一道最大生成树的AC了一下,注意不连通的情况啊,WA了一次. /* ━━━━━┒ギリギリ♂ eye! ┓┏┓┏┓┃キリ ...
- 8天学通MongoDB——第八天 驱动实践
作为系列的最后一篇,得要说说C#驱动对mongodb的操作,目前驱动有两种:官方驱动和samus驱动,不过我个人还是喜欢后者, 因为提供了丰富的linq操作,相当方便. 官方驱动:https://gi ...
- Codeforces Round #254 (Div. 2) B. DZY Loves Chemistry (并查集)
题目链接 昨天晚上没有做出来,刚看题目的时候还把题意理解错了,当时想着以什么样的顺序倒,想着就饶进去了, 也被题目下面的示例分析给误导了. 题意: 有1-n种化学药剂 总共有m对试剂能反应,按不同的 ...
- HDU 4948
题目大义: 给一张图,任意两点间有单向边,找出一种方案,使得每个新入队的点与队中的点距离<=2. 题解: 贪心,从最后入队点开始反向插入,每次找出最大入度的点入队. 只需证明最大入度点A与所有未 ...
- bzoj2823
最小圆覆盖 有个东西叫作随机增量法,具体可以baidu 这里来说说怎么求三点共圆 这其实就是求两条线段的交点 在编程中,我们解方程是比较麻烦的一个比较好的方法是利用相似三角形 设线段AB,CD交P,则 ...
- iOS开发:UINavigationController常用操作
NavigationController常用操作: 更改bar的背景颜色:self.navigationController?.navigationBar.barTintColor =UIColor. ...
- mysql的MMM高可用方案
1 MMM高可用mysql方案 1.1 方案简介 MMM即Master-Master Replication Manager for MySQL(mysql主主复制管理器)关于mysql主主复 ...