你的位置:首页 > Java教程

[Java教程]Struts 2 拦截器


什么是Struts 2 拦截器

 拦截器就是当用户请求后台Action类时在Action的Excute()方法执行前和Result返回魔板试图之后(将页面(数据)发送给浏览器渲染之前)所需要的一些通用操作存放在拦截器中对数据进行拦截!

简单来说就是对请求和响应信息进行过滤,可以看做是Java EE中的过滤器,但是需要注意的是拦截器只能对Action类的请求进行拦截若直接请求jsp文件、Css样式等静态文件拦截器是无法进行过滤的!

为什么要使用拦截器

任何优秀的MVC框架都会提供一些通用的操作,如请求数据的封装、类型转换、数据校验、解析上传的表单、防止表单的多次提交等。而早期的MVC框架中,这些通用的操作都写死在核心控制器中,然而并不是所用的请求都需要这些操作的实现,于是就导致了框架的灵活性差、可扩展性低等问题。

Struts2将它的核心功能放到拦截器而不是集中在核心控制器中实现,把大部分控制器需要完成的工作按功能分开定义,每个拦截器只完成一个功能,而完成这些功能的拦截器可以自由选择,灵活组合,需要哪些功能只需要在配置文件中进行添加即可,从而提高了框架的灵活性。

拦截器的工作原理

Struts2拦截器围绕Action和Result的执行而执行。其实现原理和Servlet Filter差不多,以链式执行,对真正要执行的方法(execute())进行拦截。首先执行Action配置的拦截器,在Action和Result执行之后,拦截器在一次执行(与先前的执行顺序相反),在此以链式的执行过程中,任何一个拦截器都可以直接返回,从而终止余下的拦截器、Action及Result的执行。

当ActionInvocation的invoke()方法被调用时,开始执行Action配置的第一个拦截器,拦截器作出相应的处理后会在此调用ActionInvocation的invoke()方法,ActionInvocation对象负责跟踪执行过程的状态,并且把控制权交给合适的拦截器。ActionInvocation通过调用拦截器的intercept()方法将控制转交给拦截器。因此,拦截器的执行过程可以看做是一个递归的过程,后续拦截器继续执行,直到最后一个拦截器,invoke()方法会执行Action的execut()方法。

先面以一张图来描述拦截器的执行过程

image

Struts2的内值拦截器

Struts2提供了一些默认的内值拦截器。如下所示:

<!--拦截器栈(可以存放一堆拦截器,在调用时只需调用defaultStack就可以调用其中的所有拦截器)--> <interceptor-stack name="defaultStack">        <interceptor-ref name="exception"/><!--用于捕获异常,并根据类型将异常映射到用户自定义的错误页面-->        <interceptor-ref name="alias"/>        <interceptor-ref name="servletConfig"/><!--将源于Servlet API的各种对象注入 Action当中-->        <interceptor-ref name="i18n"/>        <interceptor-ref name="prepare"/>        <interceptor-ref name="chain"/>        <interceptor-ref name="scopedModelDriven"/>        <interceptor-ref name="modelDriven"/>        <interceptor-ref name="fileUpload"/><!--将文件和元数据从多重请求转换为常规的请求数据,以便能将他们设置在队形的Action属性中-->        <interceptor-ref name="checkbox"/>        <interceptor-ref name="datetime"/>        <interceptor-ref name="multiselect"/>        <interceptor-ref name="staticParams"/><!--将在配置文件中通过action的子元素param设置的参数设置到对应的Action属性中-->        <interceptor-ref name="actionMappingParams"/>        <interceptor-ref name="params"/><!--将请求中的数据设置到Action中的属性上-->        <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-ref name="deprecation"/>      </interceptor-stack>

自定义拦截器

介绍了那么多的原理,现在我们来自己编写一个拦截器来体验一下吧。下面来说一下我们这个例子的功能。首先当用户访问我们的网站时使用拦截器判断其是否已经登录,如果没有登录则跳转到登录页面进行登录如图所示:

image

如果是已经登录的用户则直接跳转到欢迎界面,如图所示:

image

关于页面的html和登录的验证代码这里就不在进行展示了,我们主要看一下关于拦截器的代码,首先我们要定义一个拦截器类(该类实现com.opensymphony.xwork2.interceptor.Interceptor 接口)。其代码如下:

package cn.wz.logindemo;

import java.util.Map;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class Myinterceptor implements Interceptor {
    /**
     *
     */
    private static final long serialVersionUID = 1L;
    /**
     * 实现Interceptor接口的intercept()方法,该方法进行拦截操作,
     */
    public String intercept(ActionInvocation invoc) throws Exception {
        ActionContext context = invoc.getInvocationContext();//获取Action上下文对象
        Map<String, Object> map = context.getSession();//通过Action上下文获取Session对象的集合(Session实质上就是封装了一个map集合,通过getSession()方法来以解耦的方式获取Session)
        boolean falg = map.containsKey("userName");//判断用户是否已经登录
        if (falg) {
            //如果已经登录则将控制权转交给其它的拦截器或Action
                 return     invoc.invoke();
       
        }
        //如果没有登录则返回“input”不再执行其他拦截器或Action直接跳转到登录页面
    return "input";
    }
    /**
     * 实现Interceptor接口的destory()方法,该方法只在该拦截器销毁时调用一次
     */
    public void destroy() {
       
    }
    /**
     * 实现Interceptor接口的init方法,该方法只在该拦截器初始化时调用一次
     */
    public void init() {
       
    }


}

然后在Struts.

image