• struts2拦截器


    1.  struts2拦截器简单介绍

    1.1.  拦截器的概念

    拦截器(Interceptor)是Struts2的核心组成部分。非常多功能都是构建在拦截器基础之上的。比如文件的上传和下载、国际化、转换器和数据校验等。Struts2利用内建的拦截器。完毕了框架内的大部分操作。

    在Struts2文档中对拦截器的解释为--拦截器是动态拦截Action调用的对象。

    它提供了一种机制,使开发人员能够定义一个特定的功能模块,这个模块能够在Action运行之前或者之后运行,也能够在一个Action运行之前阻止Action运行。同一时候也提供了一种能够提取Action中可重用的部分的方式。

    拦截器是Struts2 更高层次的解耦,无须侵入框架本身便能够加入新的功能。

    拦截器是AOP(Aspect-Oriented Programming)的一种实现,底层通过动态代理模式完毕。

    1.2.  拦截器的工作原理

    Struts 2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并依据其配置实例化相对的拦截器对象。然后串成一个列表(list)。最后一个一个地调用列表中的拦截器。

    其实,我们之所以可以如此灵活地使用拦截器,全然归功于“动态代理”的使用。

    动态代理是代理对象依据客户的需求做出不同的处理。对于客户来说,仅仅要知道一个代理对象即可了。那Struts2中。拦截器是怎样通过动态代理被调用的呢?当Action请求到来的时候。会由系统的代理生成一个Action的代理对象。由这个代理对象调用Action的execute()或指定的方法,并在struts.xml中查找与该Action相应的拦截器。假设有相应的拦截器,就在Action的方法运行前(后)调用这些拦截器;假设没有相应的拦截器则运行Action的方法。当中系统对于拦截器的调用,是通过ActionInvocation来实现的。

    1.3.  拦截器与过滤器的差别

    Ø  拦截器是基于java的反射机制的,而过滤器是基于函数回调。

    Ø  拦截器不依赖与servlet容器,而过滤器依赖与servlet容器。

    Ø  拦截器仅仅能对action请求起作用,而过滤器则能够对差点儿全部的请求起作用。

    Ø  拦截器能够訪问action上下文、值栈里的对象。而过滤器不能。

    Ø  在action的生命周期中,拦截器能够多次被调用。而过滤器仅仅能在容器初始化时被调用一次

    1.4.  struts2内置拦截器

    拦截器

    名字

    说明

    Alias Interceptor

    alias

    在不同请求之间将请求參数在不同名字件转换,请求内容不变

    Chaining Interceptor

    chain

    让前一个Action的属性能够被后一个Action訪问。如今和chain类型的result()结合使用。

    Checkbox Interceptor

    checkbox

    加入了checkbox自己主动处理代码。将没有选中的checkbox的内容设定为false。而html默认情况下不提交没有选中的checkbox。

    Cookies Interceptor

    cookies

    使用配置的name,value来是指cookies

    Conversion Error Interceptor

    conversionError

    将错误从ActionContext中加入到Action的属性字段中。

    Create Session Interceptor

    createSession

    自己主动的创建HttpSession,用来为须要使用到HttpSession的拦截器服务。

    Debugging Interceptor

    debugging

    提供不同的调试用的页面来展现内部的数据状况。

    Execute and Wait Interceptor

    execAndWait

    在后台运行Action。同一时候将用户带到一个中间的等待页面。

    Exception Interceptor

    exception

    将异常定位到一个画面

    File Upload Interceptor

    fileUpload

    提供文件上传功能

    I18n Interceptor

    i18n

    记录用户选择的locale

    Logger Interceptor

    logger

    输出Action的名字

    Message Store Interceptor

    store

    存储或者訪问实现ValidationAware接口的Action类出现的消息,错误,字段错误等。

    Model Driven Interceptor

    model-driven

    假设一个类实现了ModelDriven。将getModel得到的结果放在Value Stack中。

    Scoped Model Driven

    scoped-model-driven

    假设一个Action实现了ScopedModelDriven,则这个拦截器会从对应的Scope中取出model调用Action的setModel方法将其放入Action内部。

    Parameters Interceptor

    params

    将请求中的參数设置到Action中去。

    Prepare Interceptor

    prepare

    假设Acton实现了Preparable,则该拦截器调用Action类的prepare方法。

    Scope Interceptor

    scope

    将Action状态存入session和application的简单方法。

    Servlet Config Interceptor

    servletConfig

    提供訪问HttpServletRequest和HttpServletResponse的方法,以Map的方式訪问。

    Static Parameters Interceptor

    staticParams

    从struts.xml文件里将中的中的内容设置到相应的Action中。

    Roles Interceptor

    roles

    确定用户是否具有JAAS指定的Role,否则不予运行。

    Timer Interceptor

    timer

    输出Action运行的时间

    Token Interceptor

    token

    通过Token来避免双击

    Token Session Interceptor

    tokenSession

    和Token Interceptor一样,只是双击的时候把请求的数据存储在Session中

    Validation Interceptor

    validation

    使用action-validation.xml文件里定义的内容校验提交的数据。

    Workflow Interceptor

    workflow

    调用Action的validate方法。一旦有错误返回。又一次定位到INPUT画面

    Parameter Filter Interceptor

    N/A

    从參数列表中删除不必要的參数

    Profiling Interceptor

    profiling

    通过參数激活profile

    2.  拦截器的配置

    2.1.  配置拦截器

    struts.xml

    <package name="default" extends="struts-default">

       <interceptors>

           <interceptorname="timer" class=".."/>

           <interceptorname="logger" class=".."/>

       </interceptors>

       <action name="login"

          class="tutorial.Login">

            <interceptor-refname="timer"/>

            <interceptor-refname="logger"/>

             <result name="input">login.jsp</result>

             <result name="success"

                type="redirectAction">/secure/home</result>

       </action>

    </package>

    有的时候,假设须要在配置拦截器时就为其传入拦截器參数,其格式例如以下:

    <interceptor  name="拦截器名" class="拦截器实现类 ">

    <param name="參数名">參数值</param>

    ...//假设须要传入多个參数,能够一并设置

    </interceptor>

             覆盖拦截器參数有三种方法:

    1)        第一种方法,须要复制全部的默认的拦截器,然后在传递參数,比較少用。

    <action name="myAction" class="myActionClass">

        <interceptor-ref name="exception"/>

        <interceptor-ref name="alias"/>

        <interceptor-ref name="params"/>

        <interceptor-ref name="servletConfig"/>

        <interceptor-ref name="prepare"/>

        <interceptor-ref name="i18n"/>

        <interceptor-ref name="chain"/>

        <interceptor-ref name="modelDriven"/>

        <interceptor-ref name="fileUpload"/>

        <interceptor-ref name="staticParams"/>

        <interceptor-ref name="params"/>

        <interceptor-ref name="conversionError"/>

        <interceptor-ref name="validation">

            <paramname="excludeMethods">myValidationExcudeMethod</param>

        </interceptor-ref>

        <interceptor-ref name="workflow">

            <paramname="excludeMethods">myWorkflowExcludeMethod</param>

        </interceptor-ref>

    </action>

    2)        另外一种方法,採用引用拦截器栈传參数

    <action name="myAction" class="myActionClass">

        <interceptor-refname="defaultStack">

            <paramname="validation.excludeMethods">myValidationExcludeMethod</param>

            <paramname="workflow.excludeMethods">myWorkflowExcludeMethod</param>

        </interceptor-ref>

    </action>

    3)        第三种方法,採用引用拦截器传參数

    <interceptors>

        <interceptor-stack name="parentStack">

            <interceptor-refname="defaultStack">

                <paramname="params.excludeParams">token</param>

            </interceptor-ref>

        </interceptor-stack>

    </interceptors>

    <default-interceptor-ref name="parentStack"/>

    2.2.  拦截器栈

    在非常多时候,有些指定的拦截器须要被多个Action所使用,这个时候,假设我们为每个Action都分别配置拦截器的话,不仅麻烦,并且不利后期的维护,此时就须要用到拦截器栈。

    所谓拦截器栈就是将一些拦截器组合起来进行统一管理。

    <package name="default" extends="struts-default">

       <interceptors>

            <interceptor name="timer" class=".."/>

            <interceptor name="logger" class=".."/>

            <interceptor-stack name="myStack">

               <interceptor-ref name="timer"/>

               <interceptor-ref name="logger"/>

            </interceptor-stack>

        </interceptors>

    <action name="login"

         class="tutuorial.Login">

             <interceptor-ref name="myStack"/>

             <result name="input">login.jsp</result>

             <result name="success"

                 type="redirectAction">/secure/home</result>

    </action>

    </package>

    2.3.  默认拦截器

    拦截器栈配置完毕后就能够在<action>中使用<interceptor-refname="myStack"/>对其引用了。

    一旦继承了struts-default包(package),全部Action都会默认调用拦截器栈---defaultStack。可是当在Action配置中增加“<interceptor-ref name=”..“ />”则会覆盖defaultStack,所以在action中写拦截器引用时,须要显示引用defaultStack(并且最好在第一句)。

    <default-interceptor-ref name=“…”>

    假设为Action指定了拦截器,则默认拦截器不再起作用,必须显式指定默认截拦器。

    3.  自己定义拦截器

    自己定义拦截器有下面三种实现方法:

    1)        实现Interceptor接口

    2)        继承AbstractInterceptor类

    3)        继承MethodFilterInterceptor类

    3.1.  实现Interceptor接口

    com.opensymphony.xwork2.interceptor.Interceptor接口的代码例如以下:

    public interface Interceptor extends Serializable {

        void destroy();

        void init();

        String intercept(ActionInvocation invocation) throws Exception;

    }

             该接口中有例如以下三种方法:

    1)        init():该方法在拦截器被实例化之后、拦截器运行之前调用。该方法仅仅被运行一次,主要用于初始化资源。

    2)        intercept(ActionInvocationinvocation):该方法用于实现拦截的动作。

    该方法有个參数,用该參数调用invoke()方法,将控制权交给下一个拦截器,或者交给Action类的方法。

    3)        destroy():该方法与init()方法相应,拦截器实例被销毁之前调用。用于销毁在init()方法中打开的资源。

    3.2.  继承AbstractInterceptor类

    com.opensymphony.xwork2.interceptor.AbstractInterceptor抽象类代码例如以下:

    public abstract class AbstractInterceptor implements Interceptor {

        public void init() {}

        public void destroy() { }

        public abstract String intercept(ActionInvocation invocation) throws Exception;

    }

             该抽象类实现了Interceptor接口,并提供了init()方法和destroy()方法的空实现。

    在一般的拦截器实现中,都会继承该类。由于一般实现的拦截器是不须要打开资源的,故无须实现这两种方法。继承该类会更简洁。

    3.3.  使用自己定义拦截器解决中文乱码

    1)        自己定义拦截器类的关键实现

    public class EncodingInterceptor extends AbstractInterceptor {

             public String intercept(ActionInvocation invocation) throws Exception {

                       HttpServletRequest request = (HttpServletRequest) invocation

                                         .getInvocationContext().get(ServletActionContext.HTTP_REQUEST);

                       Map<String, String[]> paramMap = request.getParameterMap();

                       Iterator<String[]> iterable = paramMap.values().iterator();

                       while (iterable.hasNext()) {

                                String[] values = iterable.next();

                                for (int i = 0; i < values.length; i++) {

                                         values[i] = new String(values[i].getBytes("iso-8859-1"),

                                                            "utf-8");

                                }

                       }

                                return invocation.invoke();

             }

    }

    2)        自己定义拦截器的配置。struts.xml

    <package name="user" extends="struts-default" namespace="/">

                       <interceptors>

                                <interceptor name="encodingInteceptor"

                                         class="com.morris.interceptor.EncodingInterceptor">

                                </interceptor>

                                <interceptor-stack name="userStack">

                                         <interceptor-ref name="encodingInteceptor"></interceptor-ref>

                                         <interceptor-ref name="defaultStack"></interceptor-ref>

                                </interceptor-stack>

                       </interceptors>

                       <default-interceptor-ref name="userStack"></default-interceptor-ref>

                       <action name="…." class="…."">

                       ………………

                       </action>

             </package>

    3.4.  继承MethodFilterInterceptor类

    Struts 2框架还提供了com.opensymphony.xwork2.interceptor.MethodFilterInterceptor抽象类,该类继承了AbstractInterceptor类。这个拦截器能够指定要拦截或排除的方法列表。通常情况下。拦截器将拦截Action的全部方法调用,但在某些应用场景中,对某些方法的拦截将会出现一些问题。

    比如:对表单字段进行验证的拦截器。当我们通过doDefault()方法输出表单时,该方法不应该被拦截,因此此时表单字段都没有数据。该类部分代码例如以下:

    public abstract class MethodFilterInterceptor extends AbstractInterceptor{

    protected Set<String> excludeMethods = Collections.emptySet();

        protected Set<String> includeMethods = Collections.emptySet();

    。。。

    protected abstract String doIntercept(ActionInvocation invocation) throws Exception;

    。。。。

    }

    在使用的时候我们仅仅须要继承MethodFilterInterceptor类:重写doIntercept方法就可以。

             拦截器的配置例如以下:

    <interceptor name=”” class=””>

             <!– m1, m3, m4须要拦截 -->

             <param name=”includeMethods”>m1, m3, m4</param>

    <!-- m2不须要拦截 -->

             <param name=”excludeMethods”>m2</param>

    </interceptor>

    在struts2中,从MethodFilterInterceptor继承的拦截器类有:

    Ø  TokenInterceptor

    Ø  TokenSessionStoreInterceptor

    Ø  DefaultWorkflowInterceptor

    Ø  ExecuteAndWaitInterceptor

    Ø  ValidationInterceptor

    Ø  ParametersInterceptor

    Ø  PrepareInterceptor

    MethodFilterInterceptor通过指定included/excluded方法列表来选择拦截器或排除的方法,能够设置的參数例如以下:

       excludeMethods-------要排除的方法。

       includeMethods--------要拦截的方法。

    比如:有例如以下的拦截器配置:

    <interceptor-ref name="validation">

             <param name="excludeMethods">input,back,cancel</param>

             <param name="includeMethods">execute</param>

    </interceptor-ref>

    当运行Action的input、back和cancel方法时,验证拦截器将不运行对输入数据的验证。当运行Action的execute方法时,验证拦截器将运行对输入数据的验证。

    在设置拦截器或排除的方法时,假设有多个方法,那么以逗号(,)分隔。如上所看到的。假设一个方法的名字同一时候出如今execludeMethods和includeMethods參数中,那么它会被当作要拦截的方法。也就是说, includeMethods优先于execludeMethods。

    在编写拦截器类的时候要注意,拦截器必须是无状态的。换句话说,在拦截器类中不应该有实例变量。这是由于struts2对每个Action的请求使用的是同一个拦截器实例来拦截调用。假设拦截器有状态,在多个线程(client的每个请求将由server端的一个线程来服务)同一时候訪问一个拦截器实例的情况下。拦截器的状态将不可预測。

    word版本号下载   源码下载

  • 相关阅读:
    这些年学过的FPGA
    基于SoCkit的opencl实验1-基础例程
    基于8051内核的实验—流水灯
    8051内核的使用
    基于FPGA的电压表与串口通信(下)
    基于FPGA的电压表与串口通信(上)
    基于FPGA的通信信号源的设计
    基于DDS的任意波形发生器
    基于FPGA的通信系统实验
    进程间通信三(共享内存)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5179779.html
Copyright © 2020-2023  润新知