【Struts2】Struts2学习(7) 拦截器

来源:互联网 发布:mac 右键 编辑:程序博客网 时间:2024/05/29 13:24

Struts2拦截器

Struts2大多数核心功能是通过拦截器实现的,每个拦截器完成某项功能。如params拦截器负责解析HTTP请求的参数,并设置Action属性。servlet-config拦截器将HTTP请求中的HttpServeltRequest实例和HttpServeletResponse实例传递给Action;fileUpload拦截器负责解析请求中参数的文件域,并将一个文件域设置成Action的三个属性。

 

Struts2拦截器是插拔式设计,如果我们需要使用某个拦截器,只需要在配置文件中应用该拦截器。Struts2默认启用了大量通用功能的拦截器,只要我们配置Action的package继承struts-default包,这些拦截器就会起作用。

 

struts2内建拦截器以name-class对的形式配置在 struts-default.xml文件中,其中name是拦截器的名字,这是使用拦截器的唯一标识,calss指定了该拦截器的实现类。

Struts2内建拦截器

alias:实现在不同请求中相似参数别名的转换。

autowiring: 自动装配拦截器,用于当Struts2和Spring整合时,Struts2可以使用自动装配的方式来访问Spring容器中的Bean。

chain : 构建一个Action链,使当前Action可以访问前一个Action的属性,一般和<result type=”chain” …/>一起使用。

conversionError: 这是一个负责处理类型转换错误的拦截器,它负责将类型转换错误从ActionContext中取出,并转换成Action的FieldError错误。

createSession : 该拦截器负责创建一个HttpSession对象,主要用于哪些需要用HttpSession对象才能正常工作的拦截器中。

debugging: 当使用Struts2的开发模式时,这个拦截器会提供更多的调试信息。

execAndWait: 后台执行Action,负责将等待画面发送给用户。

exception: 负责处理异常,它将异常映射为结果。

fileUpload: 用于上传文件,负责解析表单中文件域的内容。

i18n: 用于支持国际化的拦截器,负责把所选语言、区域放入用户Session中。

logger: 日志记录拦截器,主要是输出Action的名字。

model-driven : 模型驱动拦截器,当某个Action类实现了ModelDriven接口时,它负责把getModel()方法的结果堆入ValueStack中。

scoped-model-driven: 如果一个Action实现了一个ScopeModelDriven接口,该拦截器负责从指定生存范围中找出指定的Model,并将通过setModel方法将Model传给Action实例。

params : 最基本的一个拦截器,它负责解析HTTP请求中的参数,并将参数值设置成Action对应的属性值。

prepare: 如果action实现了Preparable接口,将会调用该拦截器的prepare()方法。

static-params: 这个拦截器将负责将xml中<action>标签下<param>标签中的参数传入action。

scope: 范围转换拦截器,它可以将Action状态信息保存到HttpSession范围,或者保存到ServletContext范围内。

servlet-config: 如果某个Action需要直接访问ServletAPI ,就是通过这个拦截器实现。(应尽量避免在Action中直接访问ServletAPI,这样会导致Action与Servlet的高耦合)

roles: 这是一个JAAS(Java authentication and authorization service ,Java 授权和认证服务)拦截器,只有当浏览者取得合适的授权后,才可以调用被该拦截器拦截的Action。

timer: 这个拦截器负责输出Action的执行时间,这个拦截器在分析Action的性能瓶颈时比较有用。

token:这个拦截器用于组织重复提交,它检查传到Action中的token,从而防止多次提交。

token-session: 这个拦截器与前一个基本类似,只是它吧token保存在HttpSession中。

validation: 通过执行在 xxxAction-validation.xml中定义的校验器,从而完成数据校验。

workflow: 这个拦截器负责调用Action类中的validate方法,如果校验失败,则返回input逻辑视图。

 

配置拦截器

<interceptor name=”拦截器名” class=”拦截器实现类”/><!—需要传入参数的拦截器--><interceptor name=”拦截器名” class=”拦截器实现类”/>    <param name=”参数名”>参数值</param></interceptor>
配置拦截器栈,如果需要在Action执行前同时做登录检查、安全检查和日志记录,可以把这三个拦截器定义成一个拦截器栈。
<interceptor-stack name=”拦截器栈名”>  <interceptor-ref name=”拦截器1”>  <interceptor-ref name=”拦截器2”>  <interceptor-ref name=”拦截器3”>  …</interceptor-stack>

拦截器栈里也可以包含拦截器栈。

使用拦截器

通过<interceptor-ref …/>元素可以在Action内使用拦截器。

<action name=”xxx” class=”xxxxx”>  <interceptor-ref name=”defaultStack”/></action>

配置默认拦截器

配置一个包时,可以为其指定默认拦截器,一般为包指定了默认拦截器,则包中的Action没有显式指定拦截器,则默认拦截器就会起作用,如果一般我们为Action显式指定了某个拦截器,则默认的拦截器不会起作用。每个包只能指定一个默认拦截器。
<package name=”包名”>  <!—所有拦截器和拦截器栈都配置在该元素下--><interceptors>   <interceptor …/>  …<interceptors><!—配置该包下的默认拦截器 既可以是拦截器,也可以是拦截器栈--><default-interceptor-ref name=”拦截器名或者拦截器栈”/><action…/></package>

自定义拦截器

如果用户要开发自己的拦截器类,应该实现com.opensymphony.xwork2.interceptor.Interceptor接口。

public interface Interceptor extends Serializable{  //销毁该拦截器之前的回调方法  void destroy();  //初始化该拦截器的回调方法  void init();  //拦截器实现拦截的逻辑方法  String intercept(ActionInvocation invocation) throws Exception;}

该接口包含了如下三个方法:

init();在拦截器被实例化之后,在该拦截器执行拦截之前,系统将回调该方法。对于每个拦截器而言,其init()方法只执行一次。因此该方法的方法体主要用于初始化性资源,如数据库连接。

destroy:该方法和init()方法对应。在拦截器实例被销毁之前,系统将回调该拦截器的destroy方法,该方法用于销毁在init()方法里打开的资源。

intercept(ActionInvocation invocation); 该方法是用户需要实现的拦截动作。就像Action的execute方法一样,intercept方法会返回一个字符串作为逻辑视图。如果该方法直接返回了一个字符串,系统将会跳转到该逻辑视图对应的实际视图资源,不会调用被拦截的Action。该方法的 ActionInvocation 参数包含了被拦截的Action的引用,可以通过调用该参数的invoke方法,将控制权转给下一个拦截器,或者转给Action的execute方法。

除了Interceptor接口,Struts2还提供了一个AbstracInterceptor类,该类提供一个init和destroy方法的空实现,如果我们实现的拦截器不需要打开资源,则可以无须实现这两个方法。

 

自定义一个简单的拦截器

public class SimpleInterceptor extends AbstractInterceptor{//简单拦截器的名字private String name;//为该简单拦截器设置名字的setter方法public void setName(String name){this.name = name;}public String intercept(ActionInvocation invocation)throws Exception{//取得被拦截的Action实例LoginAction action = (LoginAction)invocation.getAction();//打印执行开始的实现System.out.println(name + " 拦截器的动作---------" + "开始执行登录Action的时间为:" + new Date());//取得开始执行Action的时间long start = System.currentTimeMillis();//执行该拦截器的后一个拦截器//如果该拦截器后没有其他拦截器,则直接执行Action的execute方法String result = invocation.invoke();//打印执行结束的时间System.out.println(name + " 拦截器的动作---------" + "执行完登录Action的时间为:" + new Date());long end = System.currentTimeMillis();System.out.println(name + " 拦截器的动作---------" + "执行完该Action的事件为" + (end - start) + "毫秒");return result;}}
在struts中注册并引用这个拦截器
<package name="lee" extends="struts-default"><!-- 应用所需使用的拦截器都在该元素下配置 --><interceptors><!-- 配置mysimple拦截器 --><interceptor name="mysimple"class="org.crazyit.app.interceptor.SimpleInterceptor"><!-- 为拦截器指定参数值 --><param name="name">简单拦截器</param></interceptor></interceptors><action name="loginPro" class="org.crazyit.app.action.LoginAction"><result name="error">/WEB-INF/content/error.jsp</result><result name="success">/WEB-INF/content/welcome.jsp</result> <!-- 配置系统的默认拦截器 --><interceptor-ref name="defaultStack"/><!-- 应用自定义的mysimple拦截器 --><interceptor-ref name="mysimple"><param name="name">改名后的拦截器</param></interceptor-ref></action><action name="*"><result>/WEB-INF/content/{1}.jsp</result></action></package>

执行结果



从执行结果可以看出,name属性值被<interceptor-ref…/>中的属性值覆盖。拦截器得到了执行,并且打印出了Action的执行时间。Struts2的拦截器的功能非常强大,它既可以在Action的execute方法之前插入执行代码,也可以在execute方法之后插入执行代码,这种方式实质就是AOP(面向切面编程)的思想。

 

拦截方法的拦截器

如果为某个Action定义了拦截器,则这个拦截器会拦截该Action内的所有方法。但在某些情况下,我们不想拦截所有的方法,只需要拦截指定方法,此时就需要使用Struts2拦截器的方法过滤特性,Struts2提供了一个MethodFilterInterceptor类,该类是AbstractInterceptor类的子类。该类重写了AbstractInterceptor类的intercept 方法,但提供了一个doIntercept(ActionInvocationinvocation)抽象方法。

定义一个方法拦截器

public class MyFilterInterceptorextends MethodFilterInterceptor{//简单拦截器的名字private String name;//为该简单拦截器设置名字的setter方法public void setName(String name){this.name = name;}//重写doIntercept方法,实现对Action的拦截逻辑public String doIntercept(ActionInvocation invocation)throws Exception{//取得被拦截的Action实例LoginAction action = (LoginAction)invocation.getAction();//打印执行开始的时间System.out.println(name + " 拦截器的动作---------"+ "开始执行登录Action的时间为:" + new Date());//取得开始执行Action的时间long start = System.currentTimeMillis();//执行该拦截器的后一个拦截器,或者直接指定Action的execute方法String result = invocation.invoke();//打印执行结束的时间System.out.println(name + " 拦截器的动作---------" + "执行完登录Action的时间为:" + new Date());long end = System.currentTimeMillis();//打印执行该Action所花费的时间System.out.println(name + " 拦截器的动作---------"+ "执行完该Action的事件为" + (end - start) + "毫秒");return result;}}
配置Struts.xml
<package name="lee" extends="struts-default"><!-- 应用所需使用的拦截器都在该元素下配置 --><interceptors><interceptor name="myfilter"class="org.crazyit.app.interceptor.MyFilterInterceptor"><!-- 为拦截器指定参数值 --><param name="name">拦截方法的拦截器</param></interceptor></interceptors><action name="loginPro" class="org.crazyit.app.action.LoginAction"><result name="error">/WEB-INF/content/error.jsp</result><result name="success">/WEB-INF/content/welcome.jsp</result> <!-- 配置系统的默认拦截器 --><interceptor-ref name="defaultStack"/><!-- 应用自定义的拦截器 --><interceptor-ref name="myfilter"><!-- 重新指定name属性的属性值 --><param name="name">改名后的拦截方法过滤拦截器</param><!-- 指定execute方法不需要被拦截 --><param name="excludeMethods">execute</param></interceptor-ref></action><action name="*"><result>/WEB-INF/content/{1}.jsp</result></action></package>

执行结果

通过配置excludeMethods 属性指定了execute方法无须被拦截,多个方法需要拦截,用英文逗号隔开。includeMethods属性指定需要被拦截的方法。

在MethodFilterInterceptor类中,有如下两个方法。

public void setExcludeMethods(String excludeMethods): 排除需要过滤的方法,设置黑名单

public void setIncludeMethods(String includeMethods): 设置需要过滤的方法,设置白名单

 

拦截器的执行顺序:在Action的控制方法执行之前,位于拦截器前面的拦截器将先发生作用,在Action的控制方法执行之后,位于拦截器前面的拦截器将后发生作用。

 

拦截结果的监听器

为了精确定义在execute方法执行结束后,在处理物理资源转向之前的动作,Struts2提供了用于拦截结果的监听器,这个监听器是手动注册在拦截器内部的。

这里把PreResultListener监听器注册在拦截器中,只要该拦截器起作用的地方,这个监听器都会被触发。

监听器代码

public class MyPreResultListener  implements PreResultListener{//定义在处理Result之前的行为public void beforeResult(ActionInvocation invocation,String resultCode){//打印出执行结果System.out.println("返回的逻辑视图为:" + resultCode);}}
将监听器注册给拦截器

public class BeforeResultInterceptor extends AbstractInterceptor{public String intercept(ActionInvocation invocation) throws Exception{//将一个拦截结果的监听器注册给该拦截器invocation.addPreResultListener(new MyPreResultListener()); System.out.println("execute方法执行之前的拦截...");//调用下一个拦截器,或者Action的执行方法String result = invocation.invoke();System.out.println("execute方法执行之后的拦截...");return result;}}

执行结果:


覆盖拦截器栈里特定拦截器的参数

如果我们需要覆盖拦截器栈里某个特定拦截器的参数,则需要使用<拦截器名>.<参数名>这种形式。

 

使用拦截器完成权限控制

当浏览者请求执行某个操作时,需要先检查浏览者是否登录以及是否有权限执行该操作,一种做法是可以在每个Action执行实际处理逻辑之前,先执行权限检查逻辑,这种不利于复用,所以可以将这些操作放在拦截器里实现。

创建一个权限检查拦截器类

public class AuthorityInterceptor extends AbstractInterceptor{//拦截Action处理的拦截方法public String intercept(ActionInvocation invocation)throws Exception{//取得请求相关的ActionContext实例ActionContext ctx = invocation.getInvocationContext();Map session = ctx.getSession();//取出名为user的Session属性String user = (String)session.get("user");//如果没有登录,或者登录所用的用户名不是scott,都返回重新登录if (user != null && user.equals("limeng") ){return invocation.invoke();}//没有登录,将服务器提示设置成一个HttpServletRequest属性ctx.put("tip" ,"您还没有登录,请输入crazyit.org,leegang登录系统");//直接返回login的逻辑视图return Action.LOGIN;}}
在struts.xml中定义并使用拦截器

<interceptors><interceptor name="authority" class="org.crazyit.app.interceptor.AuthorityInterceptor"/></interceptors><!-- 定义全局Result --><global-results><!-- 当返回login视图名时,转入login.jsp页面 --><result name="login">/WEB-INF/content/login.jsp</result></global-results><action name="viewBook"><!-- 返回success视图名时,转入/WEB-INF/content/viewBook.jsp页面 --><result>/WEB-INF/content/viewBook.jsp</result><interceptor-ref name="defaultStack"/><!-- 应用自定义拦截器 --><interceptor-ref name="authority"/></action>

当我们直接访问viewBook这个Action时,会触发权限检查拦截器,会跳转到login界面。






原创粉丝点击