2013年6月4日星期二

Struts2的拦截器

Struts2的拦截器

265人阅读 评论(0) 收藏 举报
拦截器(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;
}

没有评论:

发表评论