zoukankan      html  css  js  c++  java
  • Struts2 中的拦截器扫盲篇

    Struts2 中的拦截器和 servelt 中的过滤器是非常的相似的。如果学过过滤器的话,肯定能够感觉的到,尽管有些微的不同。可是struts2的拦截器到底如何使用呢,为什么会有这些配置呢? 接下来一一来看。

    过滤器和拦截器是非常相似的,过滤器 public interface Filter 接口里面有三个方法:

    • init(FilterConfig      filterConfig),
    • destroy(),
    • doFilter(ServletRequest      request, ServletResponse response, FilterChain chain),

    这里面的 doFilter() 方法是最重要的,在 struts2 中  String intercept(ActionInvocation invocation)就相当于此方法。

    如何完成一个拦截器呢?在 struts2 中要实现一个接口 这个接口是什么呢?在哪呢?,是否在哪听说过?是 webwork 是我们以前听的最多的关于拦截器的框架, struts2 用了其中一个核心的东西,这个东西在是什么呢?是 xwork 。恩,有了它才可以拦截,好了我们在哪找呢?在 com.opensymphony.xwork2.interceptor 中找,里面有个 Interceptor 这是个接口,里面也有三个方法,有 init, destroy 和 intercept 三个方法,而在 struts2 里面的所有的拦截器都继承这个接口!

    实现如下

    1. Java代码package com.interceptor;   
    2. import com.opensymphony.xwork2.ActionInvocation;        
    3. import com.opensymphony.xwork2.interceptor.Interceptor;        
    4.   
    5. public class MyInterceptor implements Interceptor{        
    6.     private String hello;//一定要写,后面会用上   
    7.     get和set方法   
    8.             
    9.     public void init() {        
    10.        System.out.println("init");        
    11.     }        
    12.             
    13.     public String intercept(ActionInvocation invoker) throws Exception {        
    14.        System.out.println("intercept");        
    15.   
    16.        String result=invoker.invoke();        
    17.   
    18.        return result;        
    19.     }        
    20.             
    21.     public void destroy() {        
    22.        System.out.println("destory");        
    23.     }        
    24. }  

     

    为了看这些是怎么实现的,加入了一些打印!

    intercept 方法返回一个字符串,这个里面最重要的是 ActionInvocation 也是个抽象的接口,里面有个 invoke() 方法
              作用:Invokes the next step in processing this ActionInvocation. 即调用下一个拦截器,如果有的话!
    拦截器进行了实现,但是如何让struts2知道我们写了个拦截器呢,此时必须在struts.xml中配置一下。如下所示

    Xml代码

    1. <struts>  
    2.    <package name="struts2" extends="struts-default">  
    3.       <interceptors>  
    4.          <interceptor name="myinterceptor" class="com.interceptor.MyInterceptor">  
    5.               <param name="hello">world</param>  
    6.          </interceptor>  
    7.       </interceptors>  
    8.    </package>  
    9. <struts>  

    <struts>

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

          <interceptors>

             <interceptor name="myinterceptor" class="com.interceptor.MyInterceptor">

                  <param name="hello">world</param>

             </interceptor>

          </interceptors>

       </package>

    <struts>



    这里为了测试,用了一个虚拟的注册页面register.jsp 和 RegisterAction

    Xml代码                        

    1. <action name="register" class="com.test.action.RegisterAction" >  
    2.       <result name="input">/register.jsp</result>  
    3.       <result name="success">/success.jsp</result>  
    4. </action>  

    <action name="register" class="com.test.action.RegisterAction" >

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

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

    </action>


    好了到了这里 拦截器也配置好了,但是拦截器是拦截 action 的,怎么才能让 action 被拦截呢?
    一般的情况下,放在 result 后面,具体如下:

    Xml代码

    1. <interceptor-ref name="myinterceptor"></interceptor-ref>  

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


    将上面的配置整合起来就是:

    Xml代码

    1. <struts>  
    2.    <package name="struts2" extends="struts-default">  
    3.       <interceptors>  
    4.          <interceptor name="myinterceptor" class="com.interceptor.MyInterceptor">  
    5.               <param name="hello">world</param>  
    6.          </interceptor>  
    7.       </interceptors>  
    8.   
    9.       <action name="register" class="com.test.action.RegisterAction" >  
    10.          <result name="input">/register.jsp</result>  
    11.          <result name="success">/success.jsp</result>  
    12.          <interceptor-ref name="myinterceptor"></interceptor-ref>  
    13.       </action>  
    14.    </package>  
    15. <struts>  

    这样就可以让 Aciton 被拦截了,到此,好了,可以运行程序了:
    输出结果是:启动服务器 init 被打出
    运行后提交 action 输出 intercept

    这个就是初步的一个拦截器。


    =======
    在此可能出现一个问题,是什么呢?如果就我们做的注册程序而言,可以想一下,有数据转换,有数据校验,以前当转换和校验不符合的时候,点击提交,会提示相关错误信息,然而,此时当转换和校验依然不符合要求时,点击提交,却不会提示错误信息,为什么呢?
    ====
    当然你答对了,这些功能都包含在struts2的默认拦截器中,这里没执行是被添加的拦截器myinterceptor取代了。

    为了查明原因可以查看一下struts2-core-2.xx.jar中的struts-default.xml 这个文件
    这里定义的很多的东西,和我们的程序相关的非常紧密
    首先这里有个
    <package name="struts-default" abstract="true">...</package> 和 struts.xml 里面的
    <package name="struts2" extends="struts-default">...</package>有什么关系呢?很明显可以猜到 struts.xml 继承的就是 struts-default.xml中的包 struts-default。

    这个里面还看到<interceptors></interceptors>标签,这个是定义拦截器栈的,仔细看可以发现里面有个validation 如此可以猜想,validation 也是定义的一个拦截器,猜想当注册信息出错后没有提示信息呢?肯定是相关的验证功能没有执行,以前的执行了,现在没执行,这样说明了,是现有的拦截器取代了原有的拦截器,这个是我仅能想到的!那么我们手工把原来的默认拦截器加入,这样可以吗?
    答案是可以的!添加如下!

    接着上面result后面添加一个把!

    Xml代码

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

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


    这也说明一个问题:如果我们没有添加拦截器的话,struts2会给我们添加默认拦截器为什么加这句话呢?是因为在package 中定义了<default-interceptor-ref name="defaultStack"/> 这句话的意思是将defaultStack定义为默认的拦截器

    最后配置如下:

    Xml代码

    1. <action name="register" class="com.test.action.RegisterAction" >  
    2.      <result name="input">/register.jsp</result>  
    3.      <result name="success">/success.jsp</result>  
    4.      <interceptor-ref name="myinterceptor"></interceptor-ref>  
    5.      <interceptor-ref name="defaultStack"></interceptor-ref>  
    6. </action>  

    <action name="register" class="com.test.action.RegisterAction" >

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

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

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

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

    </action>



    为拦截器添加参数
    好了,到了这里,让我们来处理上面为myinterceptor拦截器添加的参数问题吧

    Xml代码

    1. <param name="hello">world</param>  

    <param name="hello">world</param>


    这里我们可以通过配置文件,给拦截器添加一个参数,那这个在拦截器中怎么取得的呢?
    了解过滤器的朋友都知道,里面有个init(FilterConfig filterConfig)方法在这里可以取值,而在struts2中没有这么麻烦,做法吗,上面其实已经给出来了!
    private String hello;    get和set方法
    写个变量,然后加上get和set方法,当然变量的名字必须和设定的参数是相同的,这个是赋值成功的前提条件

    此时,运行,在整个拦截器中任何方法中运行 System.out.println(hello);成功输出: world  
    这里的参数使用是在定义拦截器的时候,还有一种是在使用拦截器的时候添加参数。如下:
    1. 定义拦截器的时候添加参数:

    Xml代码

    1. <interceptor name="myinterceptor" class="com.interceptor.MyInterceptor">  
    2.     <param name="hello">world</param>  
    3. </interceptor>  

    <interceptor name="myinterceptor" class="com.interceptor.MyInterceptor">

        <param name="hello">world</param>

    </interceptor>


    2. 使用拦截器的时候添加参数:

    Xml代码

    1. <interceptor-ref name="myinterceptor">  
    2.      <param name="hello">zhuxinyu</param>  
    3. </interceptor-ref>  

    <interceptor-ref name="myinterceptor">

         <param name="hello">zhuxinyu</param>

    </interceptor-ref>


    这下知道了吗,可是还有个问题,在定义的时候添加了参数hello,使用时同样添加了参数param,当运行MyInterceptor类时会输出哪个呢? world 还是 zhuxinyu。
    结果是:zhuxinyu  很明显,覆盖了第一个,这是什么原则:就近原则。形如 OO 中的覆盖,重写。


    好了,把这些零散的东西搞完了,真的开始解决更多的知识!

    拦截器栈,在struts2里面,其实是把拦截器和拦截器栈一样的对待。可以把拦截器栈当作一个拦截器看待,同样的引用。
    现在定义一个拦截器栈把!

    同样在<interceptors> </interceptors>里面定义

    Xml代码

    1. <interceptor-stack name="mystack">  
    2.      <interceptor-ref name="myinterceptor"></interceptor-ref>  
    3.      <interceptor-ref name="defaultStack"></interceptor-ref>  
    4. </interceptor-stack>  

    <interceptor-stack name="mystack">

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

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

    </interceptor-stack>


    看见了没,一个引用第一次定义的myinterceptor拦截器,一个引用默认的拦截器,怎么引用呢,和开始的一个样,呵呵!

    Xml代码

    1. <interceptor-ref name=" mystack "></interceptor-ref>  

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


    呵呵 ,这样看是不是比刚才简单呢?把两次引用换成一次!运行结果呢?和上次一样,而且都成功!

    当然我们也可以自己定义一个默认的拦截器,这样在程序中怎么做呢?呵呵,定义如下

    Xml代码

    1. <default-interceptor-ref name="mystack"></default-interceptor-ref>  

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


    这里引用的就是上面的mystack拦截器,这样在程序中如果不在action中加入拦截器,它同样可以执行相应的工作,
    前面已经说过了,如果不加入任何拦截器的引用,它将把默认的拦截器加入。


    拦截器栈
    过滤器可以组成过滤器链,就是可以有多个过滤器来去过滤一个组件,拦截器也是,只不过是叫拦截器栈(相当于拦截器链)。
    拦截器栈先把拦截器逐个执行,接着执行action方法,之后又按照相反的顺序回到最后的一个拦截器,再回到视图。

    拦截器栈是怎么构成的呢?继续看struts-default.xml这个文件!里面有这些东西:

    Xml代码

    1.  <interceptor-stack name="defaultStack">  
    2.        <interceptor-ref name="static-params"/>  
    3.        <interceptor-ref name="params"/>  
    4.        <interceptor-ref name="conversionError"/>  
    5. </interceptor-stack>  
    6.   
    7. <interceptor-stack name="validationWorkflowStack">  
    8.         <interceptor-ref name="defaultStack"/>  
    9.         <interceptor-ref name="validation"/>  
    10.         <interceptor-ref name="workflow"/>  
    11. </interceptor-stack>  

     <interceptor-stack name="defaultStack">

           <interceptor-ref name="static-params"/>

           <interceptor-ref name="params"/>

           <interceptor-ref name="conversionError"/>

    </interceptor-stack>

     

    <interceptor-stack name="validationWorkflowStack">

            <interceptor-ref name="defaultStack"/>

            <interceptor-ref name="validation"/>

            <interceptor-ref name="workflow"/>

    </interceptor-stack>


    这里面看见了 栈是什么样的结构,是由很多个预先定义好的拦截器构成,而且也可以再加上拦截器栈组成,就如此就组成了!


    AbstractInterceptor 拦截器
    我们在做拦截器的时候,刚才实现了Interceptor接口,里面有三个方法,但是一般的情况下init() 和 destroy() 方法我们用不上,最关心的就是intercept(ActionInvocation invoker){}方法,所以怎么办呢?其实,struts2给我们提供了一个简化的拦截器类:AbstractInterceptor

    AbstractInterceptor 这是一个抽象的类,里面实现了 init() 和 destroy() 方法,所以只要我们继承这个类,就不用再多写这两个方法!

    具体实现如下:

    Java代码

    1. public class MyInterceptor2 extends AbstractInterceptor{         
    2.   protected String doIntercept(ActionInvocation invocation) throws Exception {        
    3.   
    4.        System.out.println("my interceptor2");        
    5.   
    6.        String result=invocation.invoke();        
    7.   
    8.        return result;        
    9.     }        
    10. }  

    public class MyInterceptor2 extends AbstractInterceptor{

      protected String doIntercept(ActionInvocation invocation) throws Exception {

     

           System.out.println("my interceptor2");

     

           String result=invocation.invoke();

     

           return result;

        }

    }


    如此一来写的更加少了,其它的配置方法不变。

    当然在这里还需要指出一点,你安放的拦截器的顺序,其实也就是拦截器执行的顺序!但是拦截器,不只是在执行execute()方法之前要执行,而且在execute()方法之后也要执行。给出如下两个拦截器说明:
    1

    Java代码

    1. public String intercept(ActionInvocation invoker) throws Exception {        
    2.        System.out.println("intercept1");        
    3.        String result = invoker.invoke();        
    4.        System.out.println("finish1");        
    5.        return result;        
    6. }  

    public String intercept(ActionInvocation invoker) throws Exception {

           System.out.println("intercept1");

           String result = invoker.invoke();

           System.out.println("finish1");

           return result;

    }


    2

    Java代码

    1. public String intercept(ActionInvocation invoker) throws Exception {        
    2.        System.out.println("intercept2");        
    3.        String result = invoker.invoke();        
    4.        System.out.println("finish2");        
    5.        return result;        
    6. }  

    public String intercept(ActionInvocation invoker) throws Exception {

           System.out.println("intercept2");

           String result = invoker.invoke();

           System.out.println("finish2");

           return result;

    }


    在配置顺序也是一二,结果会输出什么呢?

    intercept1  intercept2 finish2  finish1  这里执行拦截器的过程是正着来的,回来的时候是反着的。就像你要进一个很多门的房间一样。进去一个,开一个门,为了让自己能回来的方便一些,这个打开的门就不要关着了,当你把所有的门进去了后,然后回来,再逐个关门。这样的过程就像是这个拦截器执行的过程。

    最后讲一个方法过滤拦截器,顾名思义,过滤的是方法。其实在struts2中可以在一个action类中写很多个与aciton的execute方法类似的方法。
    只要在struts.xml中的action添加一个属性就可以了这个属性是method比如:

    Xml代码

    1. <action name="register"class="com.test.action.RegisterAction" method="test">  

    <action name="register"class="com.test.action.RegisterAction" method="test">

    当然在action类中也有个 test() 方法

    这个拦截器可以细化到拦截到具体的哪一个方法。如果不是方法过滤拦截器 哪么它可能将与execute()方法类似的方法都执行。
    比如说上面的test()方法。如此这样照成很多的不必要。于是这种拦截器就显的格外的重要。在这个类继承后实现的不是inteceptor()方法而是doIntercept(),可是做好这个类后如何配置继承MethodFilterInterceptor这个类呢?
    如下(为了实现过滤方法加入了几个参数,其他的都相同):

    Xml代码

    1. <interceptor-ref name="myinterceptor2">  
    2.               <param name="includeMethods">execute,test</param>  
    3. </interceptor-ref>  

    <interceptor-ref name="myinterceptor2">

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

    </interceptor-ref>


    includeMethods  包含execute,test这两个方法,结果执行了这个拦截器,如果改成excludeMethods ,就不会执行了,也可以再加下面的一个参数
    <param name="excludeMethods">execute,test</param>
    不排除execute,test这两个方法 可是又加入又排除到底执行吗?答案是执行的,必定结果是最能说明问题的!呵呵!

    转载:http://wenku.baidu.com/view/8726c90979563c1ec5da71a5.html###

  • 相关阅读:
    计算在线人数
    微软MSMQ消息件研究(一)
    jQuery循序渐进2
    单点登陆的ASP.NET应用程序设计[zt]
    利用SQL2005的缓存依赖
    .Net 操作MSMQ
    GridView中数据格式化
    TcpListener/TcpClient/UdpClient 的区别及联系
    微软消息件MSMQ研究DEMO(二)
    Nhibernate(1)
  • 原文地址:https://www.cnblogs.com/xhqgogogo/p/3037811.html
Copyright © 2011-2022 走看看