拦截器简介
在开发中,我们经常需要多次解决一个相同的问题,从而造成代码重复,臃肿,可读性不高等问题.也可以使用拦截器做登陆校验,由此可见,拦截器的常用之处,那么问题来了,怎么在struts2框架里面自定义拦截器呢?
1.拦截器跟过滤器的相同点,不同点
需要注意的是:过滤器只能过滤servlet,jsp 等 而拦截器只能拦截 action,它们之间是有区别的
以上是过滤器跟拦截器的不同之处,那么我们就来讲讲相同之处.
过滤器的执行流程是请求到来的时候过滤一遍,响应数据的时候再过滤一遍,拦截器也是如此,它们都需要经过俩次过滤器
2.struts2过滤器的执行流程
客户端发送请求到action,执行前端控制器,创建一个动态代理action类来执行excute方法,在excute方法里执行ActionInvocation的invoke方法,在actionInvacation方法invoke内部有一个判断,判断当前拦截器后面是否还有拦截器,如果有拦截器,就再调用ActionInvacation的invoke方法,(此处形成了递归),如果当前拦截器是最后一个拦截器,那么就执行目标action,当action执行结束后,那么就会根据result执行响应操作.最后由response进行响应
流程图如下
流程时序图如下
如果还没有理解的话就自己翻翻源码,嗯多看源码有益身体健康
自定义拦截器
(拦截器 说白了,就是一个类,只是继承类(包含抽象类)或实现接口的类而已),这是我的个人理解,个人观点有可能是错误的,,,建议百度
下面介绍实现拦截器的三种方法
- 继承抽象类 AbstractInterceptor
- 实现Interceptor接口
- 继承Interceptor接口的实现类MethodFilterInterceptor
我们先演示第一种代码 继承抽象类
首先我们实现抽象接口,会重写父类的方法,然后我们会发现方法提供了一个ActionInvacation的参数,看到这个参数,有没有一种似曾相识的感觉?没错,我们之前讲拦截器的时候有提到过它,它的invoke()方法,当我们已经执行完相关的操作时,我们可以调用invoke方法,让拦截器进入下一个拦截器或者是执行指定action.所以invoke()方法是关键
public class Interceptor_01 extends AbstractInterceptor{
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//这里进行功能操作
System.out.println("执行了拦截器");
if(1 == 2){ //为了方便看测试数据,我们使用false条件
//放行
invocation.invoke();
return null;
} else {
//如果没有达成放行要求
// 拒绝放行 不调用invoke() 就不会放行
}
return null;
}
}
创建被拦截的类
public class demo1 {
public void fun_01(){
System.out.println("执行了demo1");
}
}
配置struts.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="demo" extends="struts-default" namespace="/">
<interceptors> <!-- 定义一个拦截方法 name:属性自定义,不重复就行 class 是拦截器的类路径-->
<interceptor name="fun_01" class="cn.itcast.interceptor.Interceptor_01"></interceptor>
</interceptors>
<!-- 被拦截的类 -->
<action name="interceptor_*" method="{1}" class="cn.itcast.interceptor.demo1">
<!-- 引入拦截器 name 属性需要与拦截器定义的name 一致-->
<interceptor-ref name="fun_01"></interceptor-ref>
</action>
</package>
</struts>
我们来运行一下,访问interceptor_fun_01
控制台输出结果 : “执行了拦截器”
由此可见,由于我们拦截器判断是 1 == 2 永假条件,所以消息被拦截了,
我们把拦截器判断条件改为 1 == 1 时,
控制台输出 : “执行了拦截器” “执行了demo1”
第二种拦截器定义方式 : 实现Interceptor接口
//创建一个被拦截的类
public class demo3 {
public void fun01(){
System.out.println("执行了demo3");
}
}
创建一个拦截器
//实现Interceptor接口
public class Interceptor_03 implements Interceptor {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init() {
// TODO Auto-generated method stub
}
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//执行功能操作
System.out.println("执行了拦截器");
if(1 == 2 ){
// 如果此条件成立就放行.
invocation.invoke();
return null;
}
return null;
}
}
编写配置文件 struts.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="demo" extends="struts-default" namespace="/">
<interceptors> <!-- 定义一个拦截方法 name:属性自定义,不重复就行 class 是拦截器的类路径-->
<interceptor name="fun_03" class="cn.itcast.interceptor.Interceptor_03"></interceptor>
</interceptors>
<action name="interceptor03_*" method="{1}" class="cn.itcast.interceptor.demo3" >
<!-- 引入第二种写法的拦截器 -->
<interceptor-ref name="fun_03"></interceptor-ref>
</action>
</package>
</struts>
然后我们访问interceptor03_fun01
输出结果如下 :
执行了拦截器
然后我们修改拦截器的条件为 1 == 1
输出结果如下 :
执行了拦截器 : 执行了demo3
我们来介绍第三种拦截器 (开发中常用的) 继承Intercptor的实现类MethodFilterInterceptor
//创建一个实现类
public class Interceptor_04 extends MethodFilterInterceptor{
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
system.out.print("执行了拦截器")
if(1 == 2){ //条件不成立
// 条件成立,就放行
invocation.invoke();
return null;
}
return null;
}
}
创建一个被拦截类
public class demo4 {
//为了体现该方法的特别,暴露出俩个方法
public void fun01(){
System.out.println("执行了被拦截类 的fun01方法");
}
public void fun02(){
System.out.println("执行了被拦截类 的fun02方法");
}
}
编写xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<package name="demo" extends="struts-default" namespace="/">
<interceptors> <!-- 定义一个拦截方法 name:属性自定义,不重复就行 class 是拦截器的类路径-->
<interceptor name="fun_04" class="cn.itcast.interceptor.Interceptor_04"></interceptor>
</interceptors>
<action name="interceptor04_*" method="{1}" class="cn.itcast.interceptor.demo4" >
<!-- 引入第二种写法的拦截器 -->
<interceptor-ref name="fun_04"></interceptor-ref>
</action>
</package>
</struts>
进行代码测试
分别测试 fun01 fun02俩个方法
输出结果分别是 :
- 执行了拦截器
- 执行了拦截器
然后我们在拦截器配置里增加
<interceptors> <!-- 定义一个拦截方法 name:属性自定义,不重复就行 class 是拦截器的类路径-->
<action name="interceptor04_*" method="{1}" class="cn.itcast.interceptor.demo4" >
<!-- 引入第二种写法的拦截器 -->
<interceptor-ref name="fun_04">
<param name="excludeMethods">fun01</param> <!-- fun01是方法名称,意思是不拦截次方法 -->
</interceptor-ref>
</action>
然后我们再运行代码进行测试
分别访问 fun01 和 fun02方法
输出结果如下
- 执行了被拦截类 的fun01方法 执行fun01没有经过拦截器
- 执行了被拦截类 的fun01方法 执行了拦截器 执行fun02经过了拦截器,由次可知,
<param name="excludeMethods">fun01</param> 该代码的作用是声明方法,该声明的方法不会被拦截器拦截
param name的另外一个属性includeMethods
作用是拦截被该param声明的方法,由于时间问题,就不测试了
本人也是菜鸟一枚,如果有什么地方讲的不好,或者不对,欢迎指出.鞋靴