Filter、Interceptor都是AOP思想的体现。
Filter(过滤器)会拦截所有的请求,对html、jsp、Servlet等资源的请求都会被拦截。
Interceptor(拦截器)只拦截对Action的请求,且可以实现细粒化拦截,可以只拦截Action中的部分方法。
Filter、Interceptor的执行顺序都是:去的时候依次执行1,2,3,回来的时候就依次执行3,2,1。
因为是在1里面放行,调用2,在2里面放行,调用3,3里面放行调用Action|Servlet|JSP|html,得到响应对象,
响应对象返还给3,3对响应对象进行处理,返回给2,2对响应对象进行处理,返回给1,1对响应对象进行处理,返回给服务器,服务器返回给浏览器。
相当于递归调用。
注意是先调用JSP,由JSP组成响应,再由拦截器对响应进行进一步处理。
拦截器能拦截请求,也能拦截响应。
拦截器的配置
<struts>
<package name="action" namespace="/action" extends="struts-default">
<interceptors>
<interceptor name="" class=""></interceptor>
<interceptor-stack name="">
<interceptor-ref name=""></interceptor-ref>
<interceptor-ref name=""></interceptor-ref>
<interceptor-ref name=""></interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name=""></default-interceptor-ref>
<action name="" class="">
<interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name=""></interceptor-ref>
<result name=""></result>
<result name=""></result>
</action>
</package>
</struts>
在<interceptors>中注册拦截器、拦截器栈,注册之后就可以通过name来引用拦截器、拦截器栈。可以用拦截器栈来组合一组拦截器。
<default-interceptor-ref name=""></default-interceptor-ref>配置默认引用的拦截器、拦截器栈,此配置会覆盖struts-default.xml中的默认拦截器配置。如果我们配置了拦截器、拦截器栈的引用,就不会再自动调用默认的;如果我们没有配置拦截器、拦截器栈的引用,会自动调用默认的。
<interceptors>、<default-interceptor-ref>均只能作为<package>的子元素来配置。
在<action>中使用<interceptor-ref>来引用拦截器、拦截器栈,可同时引用多个,默认拦截器栈中有很多通用处理,一般都要引用。
<interceptor-ref>只能作为<action>的子元素来配置。
去的时候,按照引用的先后顺序依次调用拦截器,回来的时候,调用顺序相反。
struts-default.xml中的默认拦截器配置:
<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<interceptor-ref name="params"/>
<interceptor-ref name="conversionError"/>
<interceptor-ref name="validation">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
<param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
</interceptor-stack>
<default-interceptor-ref name="defaultStack"/>
servletConfig拦截器用于获取原生的Servlet API。
modelDriven用于模型驱动获取参数。
fileUpload用于文件上传。
params用于封装请求参数。
.........
默认的拦截器(栈)有大量的通用操作,一般都要引用。如果不引用默认的拦截器(栈),struts2的很多功能都用不了。
拦截器是Struts2的核心,完成了Struts2的大部分工作,比如解析请求参数、将请求参数赋给Action的成员变量,数据校验,文件上传等。
Struts2的拦截器是可插拔式设计,要使用某个拦截器,在配置文件中引入即可,不使用时在配置文件中删除即可。
自定义拦截器类
Interceptor本质是一个Java类,新建一个Java类即可。有3种方式:
-
实现Interceptor接口 需实现里面所有的抽象方法
-
实现AbstractInterceptor抽象类 这个类是Interceptor的子类,为其它方法提供了空实现,只有核心方法intercept()是抽象的。实现intercept()方法即可。
-
实现MethodFilterInterceptor抽象类 这个类是AbstractInterceptor的(抽象)子类,可以只拦截Action中的部分方法。需要实现doIntercept()方法。
Interceptor接口:
public interface Interceptor extends Serializable { void destroy(); void init();
String intercept(ActionInvocation var1) throws Exception;
}
在init()中做初始化,在destroy中清理善后,intercept()是核心方法,用于拦截处理。
使用AbstractInterceptor:
public class MyInterceptor extends AbstractInterceptor {
@Override public String intercept(ActionInvocation actionInvocation) throws Exception { //去的时候做一些处理 System.out.println("before"); //放行 String result = actionInvocation.invoke(); //回来的时候做一些处理 System.out.println("after"); return result;
}
}
需要返回String,如果需要在回来的时候做一些处理,要将return放到最后。
返回的String就是action返回的那个String,如果不想进行后续处理,不调用 actionInvocation.invoke() ,直接返回一个String(逻辑视图名)即可。
如果不调用JSP来显示,可以 return null; 。
使用MethodFilterInterceptor拦截action中的部分方法:
public class MyInterceptor extends MethodFilterInterceptor {
@Override protected String doIntercept(ActionInvocation actionInvocation) throws Exception { //去的时候做一些处理 System.out.println("before"); //放行 String result = actionInvocation.invoke(); //回来的时候做一些处理 System.out.println("after"); return result;
}
}
Action中有多个处理业务的方法:
public class MyAction{ public String add(){
System.out.println("add"); return "ok";
} public String update(){
System.out.println("update"); return "ok";
} public String delete(){
System.out.println("delete"); return "ok";
}
}
拦截器配置:
<struts>
<package name="action" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="myInterceptor" class="interceptor.MyInterceptor"> <param name="includeMethods">add,delete</param> </interceptor>
</interceptors> <action name="MyAction_*" class="action.MyAction" method="{1}"> <interceptor-ref name="defaultStack"></interceptor-ref>
<interceptor-ref name="myInterceptor"></interceptor-ref>
<result name="ok">/index.jsp</result> <allowed-methods>add,update,delete</allowed-methods> </action>
</package>
</struts>
MethodFilterInterceptor常与Action动态方法调用搭配使用。
注册拦截器时,需指定要拦截的方法|不拦截的方法:
<interceptor name="myInterceptor" class="interceptor.MyInterceptor">
<param name="includeMethods">add,delete</param>
<param name="excludeMethods">update</param>
</interceptor>
includeMethods指定此拦截器要拦截的方法,excludeMehtods指定不拦截的方法,这2个参数不能一起使用。指定了其中一个,剩下的方法都是另一个的。
要调用的方法是includeMethods中的方法时,才会使用此拦截器进行拦截,否则不使用此拦截器进行拦截。
此例中,访问MyAction_add、MyAcion_delete时,均会调用此拦截器;访问MyAction_update时,不会调用此拦截器。
处理机制:请求传递给此拦截器,此拦截器检查要调用的方法是否是includeMethods中的方法,是就处理,不是就直接放行。
Interceptor的生命周期
Interceptor在部署|启动WebApp时就创建实例,调用init()进行初始化。
从Tomcat中移除当前WebApp时,Interceptor实例随着WebApp的销毁而销毁,会自动调用destroy()。
Interceptor是单例的,一个Interceptor在Tomcat中只有一个实例。
在Interceptor的生命周期中,init()、destroy()均只调用1次。每次拦截请求都会调用核心拦截方法。
Action是多例的,每次处理请求都会创建一个新的Action实例。
处理完业务,调用JSP之后,此Action的生命周期才结束。
注意是执行要调用的JSP之后,Action实例才销毁。就是说在执行JSP时,此Action的ValueStack还在,仍可以从中取出数据。
使用Interceptor实现权限校验
用户登录,登录成功后可执行相关操作,直接执行用户操作,不再检查用户权限、信息,这是不行的。
比如用户可以直接在地址栏输入URL,转到操作页面进行操作,跳过用户登录。
可以使用拦截器拦截用户请求,检查用户权限:
从session中获取用户信息、权限,如果满足条件,就放行,如果未登录、权限不够,就转发到对应的登录页面、提示页面。
在用户登录成功时,将用户信息、权限放到session中。
可使用MethodFilterInterceptor只拦截Action中需要检查权限的某些方法。
如果您觉得本文的内容对您的学习有所帮助:
关键字:
Struts2