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的地址无法让用户从中明白什么. 那么 ...
随机推荐
- java服务器知识
http://blog.csdn.net/chenyi8888/article/details/4484641 http://blog.csdn.net/chenyi8888/article/deta ...
- Python中模拟enum枚举类型的5种方法分享
这篇文章主要介绍了Python中模拟enum枚举类型的5种方法分享,本文直接给出实现代码,需要的朋友可以参考下 以下几种方法来模拟enum:(感觉方法一简单实用) 复制代码代码如下: # way1 ...
- Building Xcode iOS projects and creating *.ipa file from the command line
For our development process of iOS applications, we are using Jenkins set up on the Mac Mini Server, ...
- UVa 1103 (利用连通块来判断字符) Ancient Messages
本题就是灵活运用DFS来求连通块来求解的. 题意: 给出一幅黑白图像,每行相邻的四个点压缩成一个十六进制的字符.然后还有题中图示的6中古老的字符,按字母表顺序输出这些字符的标号. 分析: 首先图像是被 ...
- [POJ 3498] March of the Penguins
March of the Penguins Time Limit: 8000MS Memory Limit: 65536K Total Submissions: 4378 Accepted: ...
- 转:MVC 下导航超链接本页面高亮的一种解决方案
前言 导航高亮一直是一个让大家头疼的问题. 纯 Javascript 的话可以判断当前页面的地址和链接地址是否有关系. 这样的弊端就是自由度太低,MVC 下会出一定的问题 (MVC 下有默认的 Con ...
- CentOS 5.6 netInstall可以的在线安装方式。
之前百度google了一把, 发现原来的地址都失效了. 只找到一个能用的. 下载9M多的CentOS Net Install ISO文件, 选择安装方式时选HTTP. 然后在后面的 服务器位置处输入 ...
- 使用AngularJS 进行Hybrid App 开发已经有一年多时间了,这里做一个总结
一.AngularJS 初始化加载流程 1.浏览器载入HTML,然后把它解析成DOM.2.浏览器载入angular.js脚本.3.AngularJS等到DOMContentLoaded事件触发.4.A ...
- 02day1
淘汰赛制 递推 [问题描述] 淘汰赛制是一种极其残酷的比赛制度.2^n名选手分别标号1,2,3,…,2^n-1,2^n,他们将要参加n轮的激烈角逐.每一轮中,将所有参加该轮的选手按标号从小到大排序后, ...
- erl0002-erlang ets学习笔记
ets全称“erlang term storage” erlang项式存储. ets打破了erlang“不变数据”的原则,使得进程之间可以共享数据.首先引起的思考是为什么会出现ets?下面是对网络资料 ...