关于拦截器
1.概念:动态拦截Action的对象,提供了一种机制,使得开发者在定义的action执行前后加执行的代码;封装大量的功能的组件;也可以在一个action执行前组织其执行,也就是说它提供了一种可以提取action中的重复代码,统一管理和执行的方式。不同的拦截器完成不同的功能。
2.拦截器链:即拦截器栈(Interceptor chain->Interceptor Stack),将拦截器按一定顺序链接成一条链,当访问到被拦截的方法或字段时,拦截器栈中的拦截器就会按顺序执行其中定义的拦截器。
3.拦截器和过滤器的区别:
3.1:过滤器是servlet中的规范,任何web项目都可以使用
3.2: 拦截器是struts2框架中的模块
3.3:过滤器可以过滤任何内容,拦截器只能拦截目标action
4.通常情况下,struts2中会执行一组默认的拦截器
拦截器底层原理
1.AOP思想(面向切面编程,约定大于配置,spring的重点)
在不修改源码的基础上对已有的方法进行动态增强
在struts2中,拦截器就是对Action进行增强(将复刻代码提出来,放在拦截器中统一管理和执行)
2.责任链模式(动态代理)
在action方法执行之前执行默认拦截器,执行过程使用AOP思想(action没有直接调用拦截器的方法,而是使用配置文件方式进行操作)
在执行多个默认的拦截器的时候,使用责任链模式(拦截器1执行完毕之后->放行->执行拦截器2->拦截器2执行完毕后放行->执行拦截器3->拦截器3执行完毕放行->action)
自定义拦截器
1.目的:通过自定义拦截器,补充系统默认拦截器中不具备的功能
2.常用方法:
2.1:实现Interceptor接口
2.2:继承AbstractInterceptor
3.继承MethodFilterInterceptor
拦截器结构描述
以MethodFilterInterceptor为例
它不仅继承了AbstractInterceptor,还可以指定不拦截的方法
其中的核心为doIntercept(ActionInvocation actionInvocation)
放行即通过actionInvocation对象执行invoke方法(注意,该方法并不是反射)
当不放行而要拦截并引导到方法时(不执行action类),返回一个返回值name即可(拦截器最终会回到action,返回name即在通知action执行方法的哪一个)
拦截器放行之后的情况 --执行拦截器的方法后,执行action中的被拦截的方法,相当于调用action中的被拦截的方法
拦截器返回为null的情况 --不执行action中的方法。
拦截器返回放行的情况 ---执行拦截器的方法后,执行action中的被拦截的方法,相当于调用action中的被拦截的方法,推荐使用
在action中配置拦截器
1.在被拦截的action所在package标签中声明拦截器(interceptors/interceptor标签):注意package中如果与其它标签,interceptors标签必须放在最前面,否则编译无法通过。
2.在action中使用声明的拦截器(interceptor-ref标签)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置字符集-->
<constant name="struts.i18n.encoding" value="utf-8"></constant>
<!--<!–导入其他的配置文件–>-->
<!--设置为开发者模式,可以打印出更详细的错误信息-->
<constant name="struts.devMode" value="true"></constant>
<!--<include file="work.xml"></include>-->
<include file="hello.xml"></include>
<package name="dupei2" extends="struts-default" namespace="/ehome">
<interceptors>
<interceptor name="interceptor" class="com.bj169.interceptor.Interceptor1"></interceptor>
<!--声明拦截器栈-->
<interceptor-stack name="myDefaultStack">
<interceptor-ref name="interceptor">
<!--设置方法是否拦截,excludeMethods代表不拦截-->
<!--<param name="excludeMethods">show</param>-->
</interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="demo1" class="com.bj169.action.Demo1Action" method="show">
<interceptor-ref name="interceptor"></interceptor-ref>
<!--系统默认拦截器-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="success">/debug.jsp</result>
<result name="index">/index.jsp</result>
</action>
</package>
</struts>
package com.bj169.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
/**
* @ClassName Interceptor1
* @Description TODO
* @Author Administrator
* @Date 2018/12/3 0003 10:26
* @Version 1.0
**/
public class Interceptor1 extends MethodFilterInterceptor {
@Override
public String doIntercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("拦截器1开始运行");
return actionInvocation.invoke();
// System.out.println("拦截器2开始运行");
// return "success";
}
}
拦截器的返回值
拦截器返回的是action执行的方法的返回值,那么,如果拦截器同时存在放行和return呢?
package com.bj169.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
/**
* @ClassName Interceptor1
* @Description TODO
* @Author Administrator
* @Date 2018/12/3 0003 10:26
* @Version 1.0
**/
public class Interceptor1 extends MethodFilterInterceptor {
@Override
public String doIntercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("拦截器1开始运行");
actionInvocation.invoke();
System.out.println("拦截器2开始运行");
return "success";
}
}
jsp页面在拦截器执行完毕后才会显示,所以,执行到放行的时候,jsp的内容是暂存在缓冲区的,不管最后return的是什么,都显示的是缓冲区的内容(即放行得到的结果)。意思就是执行放行后action方法中返回的页面,而不是拦截器返回的页面。
添加其他默认拦截器
自定义拦截器会让默认拦截器失效,手动添加一次,引用defaultStack即可),根据实际情况,如果不需要使用默认中的功能,则不需配置
设置拦截器栈 (完整代码)
拦截器会对action中所有方法都进行拦截,需要对指定的方法不进行拦截(在interceptor-ref中进行配置),使用param标签并配置不拦截的方法名称(不是name名称,而是action的method属性,例如execute()),多个不拦截的方法可以用,隔开。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"http://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!--设置字符集-->
<constant name="struts.i18n.encoding" value="utf-8"></constant>
<!--<!–导入其他的配置文件–>-->
<!--设置为开发者模式,可以打印出更详细的错误信息-->
<constant name="struts.devMode" value="true"></constant>
<!--<include file="work.xml"></include>-->
<include file="hello.xml"></include>
<package name="dupei2" extends="struts-default" namespace="/ehome">
<interceptors>
<interceptor name="interceptor" class="com.bj169.interceptor.Interceptor1"></interceptor>
<!--声明拦截器栈-->
<interceptor-stack name="myDefaultStack">
<!--引入系统默认拦截器,不需要的话可以不用-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!--引用自定义拦截器-->
<interceptor-ref name="interceptor">
<!--设置方法是否拦截,excludeMethods代表不拦截-->
<param name="excludeMethods">show</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="demo1" class="com.bj169.action.Demo1Action" method="show">
<!--引用自定义拦截器栈-->
<interceptor-ref name="myDefaultStack"></interceptor-ref>
<result name="success">/debug.jsp</result>
<result name="index">/index.jsp</result>
</action>
</package>
</struts>
package com.bj169.action;
import com.bj169.entity.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
/**
* @ClassName Demo1Action
* @Description TODO
* @Author Administrator
* @Date 2018/11/29 0029 9:35
* @Version 1.0
**/
public class Demo1Action extends ActionSupport {
public String show() {
System.out.println("action中的show方法");
return "index";
}
}
package com.bj169.interceptor;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
/**
* @ClassName Interceptor1
* @Description TODO
* @Author Administrator
* @Date 2018/12/3 0003 10:26
* @Version 1.0
**/
public class Interceptor1 extends MethodFilterInterceptor {
@Override
public String doIntercept(ActionInvocation actionInvocation) throws Exception {
System.out.println("拦截器1开始运行");
return actionInvocation.invoke();
// System.out.println("拦截器2开始运行");
// return "success";
}
}