struts2之配置拦截器 学习笔记
struts2之配置拦截器
什么是拦截器
java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。
拦截器是可插拔式的,一旦出现了问题,可以不用改变软件的很多代码就可以实现修复,给维护工作带来方便,其实过滤器也是这样的。
Struts2其实就实现了很多的拦截器,可以在struts-default.xml中看到定义很多的拦截器,其中向类型转换,文件上传都是通过拦截器实现的。
Struts2拦截器实现原理与Servlet过滤器实现原理类似,它以链式执行,对真正要执行的方法(execute())进行拦截。首先执行Action配置的拦截器,在Action和Result执行之后,拦截器会再次执行(与先前调用的顺序相反),在此链式执行的过程中,每一个拦截器都可以直接返回,从而终止余下的拦截器、Action及Result的执行。
拦截器的作用
拦截器适合封一些通用处理,便于重复利用,比如日志的记录,访问权限的检查,事务处理等,拦截器通过配置方式调用,因此使用方法比较灵活,便于维护和扩展
内建的拦截器
struts2中提供了许多内建的拦截器,在struts-core.jar中,我们只需要在struts.xml中引用这个内建的拦截器即可
比如我们在实现文件上传的时候,使用的就是内建的拦截器
内建的拦截器使用的很少,通常我们都是使用自定义的拦截器,比如验证访问权限的拦截器
自定义拦截器
实现自定义的拦截器有两种方法,一种是实现接口,一种是继承
需求
我们需要将表单传递过来的数据转换成大写的,再传递给action
实现接口(com.opensymphony.xwork2.interceptor.Interceptor)
接口中的方法
void init()初始化拦截器执行的方法
String intercept(ActionInvocation invocation) throws Exception实现拦截器逻辑的主要方法。
ActionInvocation包含了Action的引用,因此使用这个对象可以对Action进行相应的操作,比如可以获取和设置Action类的成员变量
ActionInvocation包含了Action的引用,可以调用其中的invoke()方法继续调用下一个拦截器,如果后面没有拦截器了,那么就会执行Action中对应的映射方法,如果有,那么就会继续执行下一个拦截器,直到执行完全部的拦截器才会执行对应的映射方法
invoke()方法将拦截器的作用分成了两个部分,在调用invoke()之前的实在Action方法执行之前的逻辑,在之后的代码是在Action执行result,跳转到指定视图之后执行的逻辑
这个方法返回的是一个字符串,对应的也是结果视图,如果在其中没有调用invoke()方法,那么返回的字符串就作为Action跳转的视图,因此在一定要定义这个对应的视图。如果调用了invoke()方法,那么返回的字符串就会失效,就会以Action中方法返回的字符串为主
void destroy() 销毁拦截器开启的资源
实现
拦截器类
这里并没有在init和destroy方法中写什么逻辑,可以根据实际情况来定义其中的逻辑
import com.jsnu.struts2.controller.SimpleAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;
public class TestInterceptor 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 {
Object object=invocation.getAction(); //获取当前调用拦截器的Action类的对象
//如果不为null,就可以获取其中的属性,否则空指针
if (object!=null) {
SimpleAction simpleAction=(SimpleAction)object;
//将User属性全部转换成大写字母
simpleAction.getUser().setName(simpleAction.getUser().getName().toUpperCase());
simpleAction.getUser().setPassword(simpleAction.getUser().getPassword().toUpperCase());
String result=invocation.invoke(); //调用下一个拦截器
System.out.println("成功跳转视图后执行的逻辑");
return result;
}
return null;
}
}
继承AbstractInterceptor(推荐)
继承AbstractInterceptor抽象类,里面只有一个抽象方法String intercept(ActionInvocation invocation),只需要实现这个方法即可,如果你需要初始化和销毁,那么也可以覆盖其中的init()和destroy()方法
继承抽象类的方式比实现接口对一个类的更加简洁,对这个类的污染更加小
其中的方法逻辑还是和上面的一样
还是完成上面的需求,把传递的请求参数转换成大写字母
import com.jsnu.struts2.controller.SimpleAction;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
//继承类AbstractInterceptor
public class AbstractInterceptorTest extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
Object object = invocation.getAction(); // 获取当前调用拦截器的Action类的对象
// 如果不为null,就可以获取其中的属性,否则空指针
if (object != null) {
SimpleAction simpleAction = (SimpleAction) object;
// 将User属性全部转换成大写字母
simpleAction.getUser().setName(
simpleAction.getUser().getName().toUpperCase());
simpleAction.getUser().setPassword(
simpleAction.getUser().getPassword().toUpperCase());
String result = invocation.invoke(); // 调用下一个拦截器
System.out.println("成功跳转视图后执行的逻辑");
return result;
}
return null;
}
}
配置拦截器
因为struts2的很多功能都要依赖内建的拦截器,比如表单传值。这一系列的拦截器都定义在一个拦截器栈中,如果在一个中引用了拦截器,那么这拦截器就会被覆盖,因此一定要在自定义的拦截器之前定义默认的拦截器栈
配置拦截器只需要在下定义拦截器即可,如果哪个action想要引用拦截器,使用引用已经定义好的拦截器即可
一个action中可以引用多个拦截器,在上面配置的拦截器先执行,因此默认的拦截器栈一定要在最上面
在struts.xml中配置上面我们自定义的拦截器
<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</action>
</package>
配置拦截器栈
如果一个action中的需要用到的拦截器很多,或者同时引用几个相同的拦截器的action很多,那么我们此时在action一个一个的引用拦截器效率太低,此时我们就需要将这些拦截器定义在一个拦截器栈中,直接在action中引用了拦截器栈即可。
直接使用标签中使用定义即可
拦截器栈中的拦截器一定要在上面定义过的,否则将会引用出错
拦截器栈中的拦截器引用是有顺序的,在上面的拦截器最先执行
我们把上面自定义的两个拦截器放在拦截器栈中,并在action中引用拦截器栈,注意此时的默认的default-stack还是要放在最上面
<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
<!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
<interceptor-stack name="myStack">
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="myStack"></interceptor-ref>
</action>
</package>
拓展
拦截器中还可以包含其他的拦截器栈,那么此时我们就可以将struts2中内建的拦截器放在自己的拦截器栈顶,那么就不用在每个action中引用了,直接引用这个拦截器栈即可
<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
<!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
<interceptor-stack name="myStack">
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<interceptor-ref name="myStack"></interceptor-ref>
</action>
</package>
自定义默认的拦截器栈
在一个包中定义一个默认的拦截器栈后(使用定义),那么当下没有显式的配置拦截器的时候,那么此时就会默认使用自定义的默认的拦截器或者默认的拦截器栈。
一个包中只能定义一个默认的拦截器,如果想要定义多个拦截器可以使用拦截器栈,定义一个默认的拦截器栈即可解决。
在定义了默认的拦截器之后一定要在每一个action都定义系统默认的拦截器栈defaultStack,前面已经说过如果action定义了拦截器(这里虽然不是显式的定义,但是实际上是定义了),那么就会失去defaultStack的作用,其实我们需要很多defaultStack的功能,因此还是要定义的。
比如登录检查的拦截器,这个是每一个action都需要用到的,那么我们可以设置一个默认的拦截器栈,栈顶引用的是struts2内建的默认的拦截器栈
使用<default-interceptor-ref name=""></default-interceptor-ref> 即可定义
<struts>
<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 实现接口的拦截器 -->
<interceptor name="testInterceptor" class="com.jsnu.struts2.Interceptor.TestInterceptor"></interceptor>
<!-- 继承类的 -->
<interceptor name="abstractInterceptorTest" class="com.jsnu.struts2.Interceptor.AbstractInterceptorTest"></interceptor>
<!-- 自定拦截器栈,其中引用了上面的两个拦截器 -->
<interceptor-stack name="myStack">
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<!-- 引用自定义的拦截器,在上面要定义 -->
<interceptor-ref name="abstractInterceptorTest"></interceptor-ref>
<interceptor-ref name="testInterceptor"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 定义默认的拦截器栈,其中引用了上面定义的拦截器栈 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
</action>
</package>
</struts>
配置拦截方法的拦截器
一般我们的Action类中有很多的方法,但是我们在使用动态调用的时候会调用其中不同的方法,如果不想Action类中的某个方法不被拦截,此时就需要使用拦截方法的拦截器
其中可以设置拦截的方法,也可以设置不拦截的方法
自定义拦截器类
继承MethodFilterInterceptor
其中的方法doIntercept是在执行其中指定方法之前执行,和前面的逻辑一样,也有invoke方法
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
public class SimpleActionInteceptor extends MethodFilterInterceptor{
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
System.out.println("拦截方法的拦截器起了作用");
String result=invocation.invoke();
System.out.println("执行之后");
return result;
}
}
struts中配置
<package name="test" extends="struts-default" namespace="/">
<!-- 定义拦截器 -->
<interceptors>
<!-- 配置拦截方法的拦截器 -->
<interceptor name="simpleMethod" class="com.jsnu.struts2.Interceptor.SimpleActionInteceptor"></interceptor>
</interceptors>
<action name="simple" class="com.jsnu.struts2.controller.SimpleAction" method="regist">
<result name="success">/jsp/success.jsp</result>
<result name="input">/jsp/input.jsp</result>
<!-- 在使用了自定的拦截器之后,那么系统默认的拦截器栈将会失去作用,因此这里需要重新指定拦截器栈-->
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="simpleMethod">
<!-- 定义不拦截login方法 -->
<param name="excludeMethods">login</param>
<!-- 定义需要拦截器的方法 -->
<param name="includeMethods">regist</param>
</interceptor-ref>
</action>
</package>
1:所有拦截器的超级接口Interceptor ,Action去实现这个接口;
Interceptor 它其中有三个方法(init(),destroy() ,interceptor()):
Init()方法:在服务器起动的时候加载一次,并且只加载一次;
Destroy()方法:当拦截器销毁时执行的方法;
Interceptor()方法:其中里边有一个参数invocation
public String intercept(ActionInvocation invocation) throws xception {
System.out.println("interceptor!!");
String result=invocation.invoke();
return result;
}
Invocation.invoke()是如果只有一个拦截器执行完这个方法后,会返回给视图,如果有多个拦截器,它顺序的执行完所有的拦截器,才返回给视图.
2:可以在系统初始化中给拦截器指定默认的参数(也包括了定义拦截器方式)如下:
在拦截器类中把hello当做属性set/get方式注入到拦截器类中;
<interceptors>
<!-- 先定义拦截器 -->
<interceptor name="myInterceptor" class="com.zzz.struts2.interceptor.MyInterceptor">
<!-- 指定系统初始化给拦截器的参数 -->
<param name="hello">张钊钊</param>
</interceptor>
<!-- 加到自己设置的拦截器栈里边去 -->
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor">
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 改变系统默认的拦截器,改成自己的默认拦截器,并且一个系统只能有一个默认的拦截器,这样这个拦截器栈会默认应用到所有的Action上去 -->
<default-interceptor-ref name="myStack">
</default-interceptor-ref>
也可以在使用拦截器的时候给它设置参数:
就是在一个action 的reslut下面配置上如下:
<action name="register"
class="com.zzz.struts2.action.RegisterAction">
<result name="success">/success.jsp</result>
<!-- result 它其中还有一个信息转发类型 type=""记住,如果不转向JSP,转向图表,可以改变type=""值 -->
<result name="input">/register.jsp</result>
<interceptor-ref name="myInterceptor">
<param name="hello">welcome</param>
</interceptor-ref>
<interceptor-ref name="myStack"></interceptor-ref>
</action>
2.拦截器,拦截器栈和默认的拦截器之间的关系
1:拦截器和拦截器栈是一个级别的,也就是说一个拦截器栈中包括许多拦截器, 一个拦截器栈中还可以包括许多拦截器栈,配置如下方式:
<interceptors>
<!-- 先定义拦截器 -->
<interceptor name="myInterceptor" class="com.zzz.struts2.interceptor.MyInterceptor">
<!-- 指定系统初始化给拦截器的参数 -->
<param name="hello">张钊钊</param>
</interceptor>
<!-- 加到自己设置的拦截器栈里边去 -->
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor">
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
拦截器的使用:1.先定义;2.在引用使用;
</interceptor-ref>
2:struts2中有一个系统默认的拦截器栈是 defaultStack,如果你手动引用自己的拦截器,系统默认的拦截器栈将不起作用;这样必需手动引入系统的拦截器栈
</interceptor-ref>
如果想改变系统默认的拦截器栈,可以这样配置:
其中myStack是自己定义的拦截器栈名字;
如果拦截器栈中有多个拦截器,在执行action之前的顺序跟配置拦截器的顺序一致,而在action之后执行的顺序是相反的;
3:抽象的拦截器类AbstractInterceptor
1:Interceptor这个超级拦截器接口,有三方法需要实现,但是如果不想使用init();
和destroy()方法,可以去继承这个抽象拦截器类;
它的使用跟上边的没有什么区别;
4:方法过滤拦截器MethodFilterInterceptor
1:上边的拦截器都要是针对整个action的,如果针对某个方法进行拦截可以去继承这个类;
它的使用跟上边的使用方法差不多,只是需要要配置它对那个方法进行拦截,方法过滤拦截器最好不要配置到自己设置默认的拦截器栈里边,自己手动配置.
interceptor-ref name=“myInterceptor3”>
<param name="includeMethods">execute</param>
<param name="excludeMethods">execute</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
其中includeMethods ,excludeMethods是固定写法: includeMethods 包含拦截那些方法,多个方法需要用”,”隔开; excludeMehtods是排除拦截的那些方法;
5:鉴听器PreResultListener接口
1:它的鉴听点在拦截器执行完某个action方法后,在渲染视图之前做一些事情;让某个类去实现这个接口;
然后向需要它的拦截器中注册进去如下代码:
publicclass MyInterceptor3 extends MethodFilterInterceptor {
privatestaticfinallongserialVersionUID = 3756655410194005443L;
@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
//把鉴听器注册到拦截中去;
invocation.addPreResultListener(new MyListener());
System.out.println("my Interceptor3");
String result=arg0.invoke();
System.out.println("my interceptor3 finshed!");
return result;
}
}
struts2采用convention-plugin实现零配置,Struts2 Convention插件的使用
https://blog.csdn.net/lexang1/article/details/52704164
本文深入解析Struts2框架中的拦截器配置方法,包括拦截器的基本概念、实现方式、自定义拦截器的步骤、配置拦截器栈的技巧以及如何配置默认拦截器。文章还探讨了拦截器在Action执行前后的运作机制,以及如何利用拦截器进行日志记录、权限检查等通用处理。
439

被折叠的 条评论
为什么被折叠?



