Struts2的拦截器

    技术2022-05-19  18

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

    拦截器动态拦截Action调用的对象,它提供了一种机制,使开发者可以定义一个特定的功能模块,这个模块可以在Action执行之前或者执行之后运行,也可以在一个Action执行之前阻止Action执行。同时也提供了一种可以提取Action中可重用的部分的方式。

    Struts2架构中,可以使用配置文件,灵活配置定义拦截器。当需要一个拦截器的时候,只要在配置文件中设置即可;如果不需要时,可以取消该拦截器,这样就可以实现拦截器同Action类的松耦合,提高系统扩展性。

     

     

    一、 Struts2拦截器原理

     

     

     

     

     Struts2架构的Action被一个或者多个拦截器(拦截器栈)所包围,所有的用户请求都会被拦截器所拦截,然后交给Action处理,处理结果以逻辑视图方式返回给用户。 这个调用执行流程是由Struts2的配置文件来实现的。 当用户请求到达Struts2ServletDispatcher时,Struts2会查找配置文件,并根据其配置实例化相对的拦截对象,然后串成一个列表(List),最后一个一个地调用列表中的拦截器。

     

    二、 定义拦截器

     

         Struts2框架的拦截器处理机制采用了AOP(面向方面编程)设计思想。使得拦截器(拦截器组)可以类似“热插拔”的方式来组合,配合业务控制器Action来完成用户请求的处理。 这种“热插拔”实际上是通过Struts2框架的配置文件来实现的,配置文件中可以定义拦截器和拦截器栈,并可以在Action中定义所使用的拦截器或者拦截器栈。开发者如果要改变拦截器的执行顺序或者数量,只需要修改配置文件即可。

         struts.xml配置文件中,配置拦截器如下:

     

    <interceptors>

       <!—定义拦截器-->

              <interceptor  class="intercept.FilterInterceptor"  

                      name="filterIntercept"></interceptor>

              <interceptor class="interceptOrder.InterceptorOrder"

                       name="InterceptorOrder">

               <!—定义拦截器参数-->

               <param name="">value</param>

               <param name="">value</param>

    </interceptor>

              <interceptor name="checkIntercept" 

                    class="authorityIntercept.CheckInterceptor">

    </interceptor>

     <!—定义拦截器栈-->

              <interceptor-stack name="myDefaultStack">

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

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

              </interceptor-stack>

           </interceptors>

     

    三、 使用拦截器

     

         1、在Struts2框架中定义了拦截器或者拦截器栈,就可以在配置文件中使用该拦截器或者拦截器栈来拦截Action。指定拦截器或者拦截器栈,会在Actionexecute()方法执行之前被执行。 Action中配置拦截器如下:

      <action name="FilterAction" class="intercept.FilterAction">

                         <result name="success">/intercept/MethodFilter.jsp</result>

                            <!—显式引用默认拦截器-->

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

                            <!—自定义拦截器栈-->

                         <interceptor-ref name="myDefaultStack">

                         </interceptorref>           

                         <interceptor-ref name="filterIntercept">

                            <!—在使用拦截器时指定拦截器参数-->

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

                                <param name="excludeMethods">method2</param>

                                <param name="name">方法过滤拦截器</param>

                         </interceptor-ref>         

                  </action>

     

               注意:Struts2框架的默认拦截器defaultStack包含了很多重要的功能,在Action

                 义自己的拦截器的同时,一定要注意需要同时显式的引用系统默认拦截器

                        defaultStack

     

         2 配置默认拦截器

     

             为了避免每个Action配置相同的拦截器,使用默认拦截器,则包内所有Action都会自动使用默认拦截器,避免了配置代码的重复使用。

             配置默认拦截器使用<default-interceptor-ref…/>元素,该元素为包<package…/>的一个子元素,如果在包配置中定义了一个默认拦截器,那么该拦截器对包内所有的Action都是有效的,Action中显式定义拦截器情况下除外。

    <default-interceptor-ref…/>元素需要指定一个name属性,该属性指定默认拦截器的名称。该属性必须是一个已经存在的拦截器名称,即前面已经定义好了的。

    <interceptors>

             <interceptor name="checkInterceptor" class="bbs.checkInterceptor">

             </interceptor>

             <interceptor-stack name="bbsStack">

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

                <interceptor-ref name="checkInterceptor" />

                <interceptor-ref name="jsfStack" />

             </interceptor-stack>

    </interceptors>

    <!—指定包内默认拦截器-->

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

     

    注意:在指定包内默认拦截器时,只能使用一个<default-interceptor-ref…/>元素,即

          每个包内只能定义一个默认的拦截器。 如果需要将多个拦截器都设置为一个包的默

          认拦截器,最好的方式是将这些拦截器组成一个拦截器栈,再将拦截器栈设置为包

          的默认拦截器。

     

      3 自定义拦截器实现类

     

          1 Struts2框架为开发者自定义拦截器实现类提供了一个Interceptor接口,用户可

            以实现该接口来开发自定义拦截器实现类。Interceptor接口中定义了三个方法:

                init()destroy()String interceptor(ActionInvocation invocation)

     

          2 Struts2框架除了提供Interceptor接口用于开发自定义拦截器实现类外,还提供

            了一个com.opensymphony.xwork.interceptor.AbstractInterceptor 类,

            开发者只要继承该类,就可以用简单的方式来实现自己的拦截器实现类。该类实

            现了Interceptor接口。 该类同样定义了上面的三个方法,如果在用户自定义的

            拦截器实现类的初始化时,不需要加载一些特殊的系统资源,可以不用实现init()

            和destroy()方法。只需要重写interceptor(ActionInvocation invocation)

            法即可。

     

     

    四、 拦截器深度剖析

     

         1 拦截器的方法过滤

     

             业务控制器Action中可以使用动态方法来处理用户请求,这样Struts2框架的Action更 

          加灵活。 Action中使用拦截器,默认情况下会拦截Action实现类中的所有方法。但

          是某些情况下,开发者可能只需要拦截Action中的一个或者多个方法,有时候也希望拦

          截器不拦截某些Action方法。 这时,让拦截器有选择的拦截Action中的某个方法,就

          需要使用拦截器的方法过滤。

     

      Struts2框架提供了一个MethodFilterInterceptor类,开发者自定义的拦截器只要继承

     该类,就可以使用拦截器的方法过滤功能,来拦截Action中特定的方法。

    MethodFilterInterceptor类为

    com.opensymphony.xwork.interceptor.AbstractInterceptor拦截器类的子类,实现

    InterceptorSerializable接口。该类有两个重要的参数:

    excludeMethods:该参数指定拦截器拒绝拦截的方法列表。多个方法值中间用逗号分开。

    includeMethods: 该参数指定拦截器需要拦截的方法列表。多个方法值中间用逗号分开。

     

    下面给出该类的主要方法:

      protected abstract String doInterceptor(ActionInvocation invocation) :继承该类的子类必须重写该方法,并实现拦截器逻辑。

      String interceptor(ActionInvocation invocation):继承自AbstractInterceptor类,该方法不需要强制重写。

      void setExcludeMethods(String excludeMethods):设置黑名单,该方法参数为一个字符

    串,即对应的Action方法名称。

          void setIncludeMethods(String includeMethods):设置拦截器的白名单。

          Set getExcludeMethodsSet():获得拦截器的黑名单。

          Set getIncludeMethodsSet(): 获得拦截器的白名单。

       注意: 开发者使用MethodFilterInterceptor类的子类来实现拦截器的方法过滤,只需要

             重写doInterceptor(ActionInvocation invocation)方法即可。

      下面为实现方法过滤拦截的配置文件: filterInterceptor过滤器继承了MethodFilterInterceptor类。

        <interceptor-ref name="filterIntercept">

                    <!—使用方法过滤,设置白名单或黑名单-->

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

                   <param name="excludeMethods">method2</param>

                   <param name="name">方法过滤拦截器</param>

           </interceptor-ref>  

     

    2 拦截器的执行顺序

         配置在前面的拦截器,会在被拦截方法执行之前执行拦截动作,拦截器的拦截动作是按照配置文件拦截器的引用顺序来执行的。

    3 拦截结果监听器

        开发者如果需要在Action执行之后,拦截器的interceptor(ActionInvocation arg0)返回result之前进行一些业务处理操作。例如Action执行execute()后,返回一个“success”字符串,拦截器对该返回结果进行处理,修改某些业务数据后,再返回“success”逻辑视图。

    1、    实现上面的要求,可以在拦截器的invoke()方法之后加入处理代码。例如:

        public String intercept(ActionInvocation arg0) throws Exception {

                  //注册一个监听器

                arg0.addPreResultListener(new MyListener());

                System.out.println(name+"拦截器信息:启动拦截器,拦截Action

                                间:"+new Date());

                String result=arg0.invoke();

            //根据处理结果处理其他业务

            if(result.equals("success")){

                 dosomething();

    }

             System.out.println(name+"拦截器信息:Action执行完毕时间:"+new

    Date());

                  return result;

           }

     

    2、    上面代码会导致拦截器中加入了大量的业务逻辑判断和处理代码,从而降低了系统代码的复用性。 为了处理Action执行处理方法之后和拦截器返回result之间节点的业务,Struts2框架提供了一个PreResultListener接口。实现该接口就可以监听Action特定方法执行之后的结果,并做进一步的预后处理。

     

    PreResultListener接口中只有一个方法,如下所示。该方法中有两个参数,其中resultcode就是Action执行之后返回的结果。

     void beforeResult(ActionInvocation invocation, String resultcode)

     

    1. 开发者可以开发自己的监听器类,该类必须实现PreResultListener接口,并重写void beforeResult(ActionInvocation invocation, String resultcode)方法。例如下面的代码:

       public class MyListener implements PreResultListener {

             public void beforeResult(ActionInvocation arg0, String arg1) {

                  // TODO Auto-generated method stub

                  System.out.println("监听器监听执行结果..."+arg1);

            }

    }

     

    2. 为了使用监听器,需要在拦截器中注册监听器。下面的示例中在拦截器中加入了监听器:

       public String intercept(ActionInvocation arg0) throws Exception {

            //注册一个监听器

            arg0.addPreResultListener(new MyListener());

    System.out.println(name+"拦截器信息:启动拦截器,拦截Action时间:"+new Date());

    String result=arg0.invoke();

    System.out.println(name+"拦截器信息:Action执行完毕时间:"+new Date());

    return result;

    }


    最新回复(0)