Struts 2 之拦截器

拦截器概述

Struts2拦截器是在访问某个Action或Action的某个方法,字段之前或之后实施拦截,并且Struts2拦截器是可插拔的,拦截器是AOP(Aspect Oriented Programming,面向切面编程)的一种实现

拦截器栈(InterceptorStack)。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

Struts2规定用户自定义拦截器必须实现com.opensymphony.xwork2.interceptor.Interceptor接口,该接口声明了3个方法

void init();

void destroy();

Stringintercept(ActionInvocation invocation) throws Exception;

其中,init和destroy方法会在程序开始和结束时各执行一遍,不管使用了该拦截器与否,只要在struts.xml中声明了该Struts2拦截器就会被执行。

intercept方法就是拦截的主体了,每次拦截器生效时都会执行其中的逻辑

不过,struts中又提供了几个抽象类来简化这一步骤

public abstractclass AbstractInterceptor implementsInterceptor;

public abstractclass MethodFilterInterceptorextends AbstractInterceptor;

都是模板方法实现的。

其中AbstractInterceptor提供了init()和destroy()的空实现,使用时只需要覆盖intercept()方法;

而MethodFilterInterceptor则提供了includeMethods和excludeMethods两个属性,用来过滤执行该过滤器的action的方法。可以通过param来加入或者排除需要过滤的方法。

实例

直接实现Interceptor接口

public class MyInterceptor implements Interceptor {public void destroy() {// TODO Auto-generated method stub}public void init() {// TODO Auto-generated method stub}public String intercept(ActionInvocationinvocation) throws Exception {System.out.println("Action执行前插入 代码");//执行目标方法 (调用下一个拦截器, 或执行Action)final String res =invocation.invoke();System.out.println("Action执行后插入 代码");return res;}}

配置

<package name="default" extends="struts-default"><interceptors><interceptor name="MyInterceptor" class="interceptor.MyInterceptor"></interceptor><interceptor-stack name="myInterceptorStack"><interceptor-ref name="MyInterceptor"/><interceptor-ref name="defaultStack"/></interceptor-stack></interceptors><action name="loginAction" class="loginAction"><result name="fail">/index.jsp</result><result name="success">/success.jsp</result><interceptor-ref name="myInterceptorStack"></interceptor-ref></action></package>

特别注意,在使用拦截器的时候,最后一定要引用struts2自带的拦截器缺省堆栈defaultStack,否则出错

继承AbstractInterceptor抽象类

我们尝试编写一个Session过滤用的拦截器,该拦截器查看用户Session中是否存在特定的属性(LOGIN属性)如果不存在,中止后续操作定位到LOGIN,否则执行原定操作,代码为:

public class CheckLoginInterceptor extends AbstractInterceptor {public static final String LOGIN_KEY = "LOGIN";public static final String LOGIN_PAGE = "global.login";public String intercept(ActionInvocationactionInvocation) throws Exception {System.out.println("begin checklogin interceptor!");// 对LoginAction不做该项拦截Object action = actionInvocation.getAction();if (action instanceof LoginAction) {System.out.println("exit checklogin, because this is login action.");return actionInvocation.invoke();}// 确认Session中是否存在LOGINMap session = actionInvocation.getInvocationContext().getSession();String login = (String)session.get(LOGIN_KEY);if (login != null &&login.length() > 0) {// 存在的情况下进行后续操作。System.out.println("alreadylogin!");return actionInvocation.invoke();} else {// 否则终止后续操作,返回LOGINSystem.out.println("no login,forward login page!");return LOGIN_PAGE;}}}

注册拦截器

<interceptors><interceptor name="login" class="com.clf.CheckLoginInterceptor"/><interceptor-stack name="teamwareStack"><interceptor-ref name="login"/><interceptor-ref name="defaultStack"/></interceptor-stack></interceptors>

将上述拦截器设定为默认拦截器:

<default-interceptor-ref name="teamwareStack"/>这样在后续同一个package内部的所有Action执行之前都会被login拦截。

继承MethodFilterInterceptor抽象类

MethodFilterInterceptor类重写了AbstractInterceptor类的intercept(ActionInvocationinvocation)方法,但提供了一个doIntercept(ActionInvocation invocation)抽象方法。从这种设计方式可以看出,MethodFilterInterceptor类的intercept已经实现了对Action的拦截行为(只是实现了方法过滤的逻辑),但真正的拦截逻辑还需要开发者提供,也就是通过回调doIntercept方法实现。可见,如果用户需要实现自己的拦截逻辑,则应该重写doIntercept(ActionInvocation invocation)方法。

下面是一个简单的方法过滤的示例应用,方法过滤的拦截器代码如下。

//拦截方法的拦截器,应该继承MethodFilterInterceptor抽象类public class MyFilterInterceptor extends 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;}}

从上面的代码中可以看出,上面拦截器的拦截逻辑与前面简单拦截器的拦截逻辑相似,只是之前是需要重写intercept方法,现在是重写doIntercept方法。

实际上,实现方法过滤的拦截器与实现普通拦截器并没有太大的区别,只需要注意两个地方:实现方法过滤的拦截器需要继承MethodFilterInterceptor抽象类,并且重写doIntercept方法定义对Action的拦截逻辑。

在MethodFilterInterceptor方法中,额外增加了如下两个方法:

public void setExcludeMethods(String excludeMethods):排除需要过滤的方法——设置方法“黑名单”,所有在excludeMethods字符串中列出的方法都不会被拦截。

public void setIncludeMethods(String includeMethods):设置需要过滤的方法——设置方法“白名单”,所有在includeMethods字符串中列出的方法都会被拦截。

注意:如果一个方法同时在excludeMethods和includeMethods中列出,则该方法会被拦截。

因为MethodFilterInterceptor类包含了如上的两个方法,则该拦截器的子类也会获得这两个方法。可以在配置文件中指定需要被拦截,或者不需要被拦截的方法。

方法过滤示例应用的配置片段如下:

在那里,有我们特有的记忆,亲情之忆、

Struts 2 之拦截器

相关文章:

你感兴趣的文章:

标签云: