Struts2拦截器的运用

一、什么是拦截器?

提到拦截器,使我不得不 想起武侠剧中劫匪们常说的一句话:“此山是我开,此树是我栽,要打此路过,留下买路财!”。难不成程序中也有“打劫”的,说的没错,拦截器就是个打劫的。 在现实生活中,劫匪劫的大都是钱财,当然也有别的什么,那么程序中的“劫匪”劫的又是什么呢?或者说程序中为什么需要它?在我们的日常编程中少不了写一些 重复的代码,例如在一个地方中写了一段代码,后来发现这段代码在其它地方中同样需要,在传统的编程中我们一定会采取复制、粘贴的办法。如果这段代码只在这 一两个处需要,我们采取这种办法,还说的过去,但是如果系统对这段代码过于依赖,也就是这段代码在系统中出现的过多,如果那一天我们发现这段代码中在某些 地方还需要完善,我们是不是要着个修改它们呢?我估计没有人会这么做,它严重违反了软件开发中一条非常重要的DRY规则,不写重复代码。说了这么多你一定知道我们为什么需要在程序中弄一个“劫匪”了吧。这个“劫匪”就是并不是劫取什么东西,只是为了在某个程序执行前后,动态的增加一些功能(以前所写通用代码块)或进行一些检查工作。那么这个拦截器到底是怎么实现的呢?实际上它是用Java中的动态代理来实现的。

二、拦截器在Struts2中的应用

对于Struts2框架而言,正是大量的内置拦截器完成了大部分操作。像params拦截器将http请求中参数解析出来赋值给Action中对应的属性。Servlet-config拦截器负责把请求中HttpServletRequest实例和HttpServletResponse实例传递给Action……struts2内置的拦截器有很多,在此我就不一一列举了

那么怎么在struts2中定义自己的拦截器呢?

    很简单Struts2为我们提供了一个Interceptor接口,该接口源代码如下:

publicinterfaceInterceptorextends Serializable {

    void destroy();

    void init();

    String intercept(ActionInvocation invocation)throws Exception;

}

1)   init():在拦截器执行之前调用,主要用于初始化系统资源。

2)   destroty():与init()对应,用于拦截器执行之后销毁资源。

3)   intercept():拦截器的核心方法,实现具体的拦截操作。与action一样,该方法也返回一个字符串作为逻辑视图。如果拦截器成功调用了action,则返回一个真正的,也就是该action中execute()方法返回的逻辑视图,反之,则返回一个自定义的逻辑视图。

通常我们使用拦截器并不需要申请资源,为此Struts2还为我们提供了一个AbstractInterceptor类,该类的init()和destroy()都是空实现。我们开发自己的拦截器只需要继承这个类就行了。

    下面创建一个判断用户是否登录的拦截器。代码如下:

@SuppressWarnings("serial")
public class AuthInterceptor extends AbstractInterceptor {
        public String intercept(ActionInvocation actionInvocation) throws Exception {
                 System.out.println("-------AuthInterceptor-------");
               //检查Session中是否存在user
               Map map = actionInvocation.getInvocationContext().getSession();
              if(map.get("user")==null){
              // 否则终止后续操作,返回LOGIN
                        return Action.INPUT;
               }else{
              //存在的情况下进行后续操作
                       return actionInvocation.invoke();
           }
      }
}

 

    创建好拦截器后,还不能使用,还需要我们在struts.xml中配置一下。

  下面看一下怎么配置拦截器。

<interceptors>

           <interceptor name="auth" class="com.cyd.interceptor.AuthInterceptor"></interceptor>

</interceptors>

   这个定义好的拦截器在Action中怎么使用呢?使用方法很简单,如下:

<action name="userManager" class="com.cyd.action.UserManagerAction" method="del">

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

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

 </action> 

  一旦我们为某个action引用了自定义的拦截器,struts2默认的拦截器就不会再起作用,因此还需要引用默认拦截器。

<action name="userManager" class="com.cyd.action.UserManagerAction" method="del">

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

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

                <interceptor-ref name="defaultStack" />

</action>

   但是我们这么做似乎也不太方便,因为如果拦截器auth需要被多个action引用的话,每一个都要配置一遍太麻烦了。我们可以把它定义成默认的拦截器。

 <interceptors>
            <!-- 定义拦截器 -->
           <interceptor name="auth" class="com.cyd.interceptor.AuthInterceptor"></interceptor>

            <!-- 定义一个拦截器栈,包含多个拦截器 -->
          <interceptor-stack name="myDefault"> 
                 <interceptor-ref name="auth"></interceptor-ref>
                <interceptor-ref name="defaultStack"></interceptor-ref>
         </interceptor-stack>

 </interceptors>

<default-interceptor-refname="mydefault"/>

   另外,struts2还为我们提供了一个方法过滤的拦截器MethodFilterInterceptor类,该类继承AbstractInterceptor类,重写了intercept(ActionInvocation invocation)并提供了一个新的方法doInterceptor(ActionInvocation invocation)抽象方法。该类的使用方法很简单,就不举例了。这个拦截器与以往的拦截器配置有所不同。那就是可以指定哪些方法需要被拦截,那些不需要。通常在引用该拦截器时指定。

<interceptor-refname="  ">

       <paramname="exculdeMethods"></param>

       <paramname="includeMethods"></param>    

</interceptor-ref>

   exculdeMethods:是不被拦截的方法,如果有多个以逗号分隔。

   includeMethods:需要被拦截的方法,如果有多个以逗号分隔。

 

     下面我来实验下。我们写个拦截器栈
    <struts>
    <package name="default" extends="struts-default">
    
        <interceptors>
            <!-- 定义拦截器 -->
      <interceptor name="auth" class="com.cyd.interceptor.AuthInterceptor"></interceptor>
      <interceptor-stack name="myDefault"> 
    <interceptor-ref name="auth"></interceptor-ref>
          <interceptor-ref name="defaultStack"></interceptor-ref>
   </interceptor-stack>
  </interceptors>
  
  <default-interceptor-ref name="myDefault"></default-interceptor-ref>
  <!-- 拦截器必须要定义在action的上面 -->
  
        <action name="login" class="com.cyd.action.LoginAction" method="login">
            <result name="success">/view/menu/index.jsp</result>
            <result name="input">/index.jsp</result>
            <interceptor-ref name="defaultStack"></interceptor-ref>
        </action>
       
        <action name="userManager" class="com.cyd.action.UserManagerAction" method="del">
        </action>
       
   </package>
   
</struts>
  

上面的配置只有当用户登录的时候,不用拦截,除了登录以外的所有的action都需要拦截。(因为登录的时候session一定是没有user的,所以就没有必要拦截,

如果拦截的话,永远也不会登录成功)

 

拦截器几乎完成了Struts2框架70%的工作,包括解析请求参数、将请求参数赋值给Action属性、执行数据校验、文件上传……,Struts2设计的灵巧性,更大程度地得益于拦截器设计,当需要扩展Struts2功能时,只需要提供对应拦截器,并将它配置在Struts2容器中即可;如果不需要该功能时,也只需要取消该拦截器的配置即可。这种可插拔式的设计,正是软件设计领域一直孜孜以求的目标。

实际上,Struts2的精髓就在于拦截器,掌握了Struts2的拦截器机制,你就可以说精通了Struts2。
从某个角度来看,我们可以把Struts2框架理解成一个空壳,而这些拦截器像一个一个抽屉,随时可以
插进入,也可以拔出来——这是软件产品一直追求的目标。
如果你喜欢,你可以把Struts2的全部插件拔出,那么Struts2就成了一个空容器——
而这种空,正是 Struts2的魅力,你可以把任何自己想要的东西填入进去,甚至包括自己完全实现这个框架。

另一方面,因为Struts2的插件机制,Struts2提供了无限扩展的可能性,你可以把自己想要的任何
东西做成插件,然后填入Struts2——这样的结果是:一个企业,一个团队,可以把自己业务相关的东西
做成插件,随时随地地复用。
也就是说:如果你想要,你可以把Struts2改造成属于自己的框架。

当然,Struts2也内建了大量的拦截器,这些拦截器以name-class对的形式配置在struts-default. xml文件中,其中name是拦截器的名字,就是以后使用该拦截器的唯一标识;class则指定了该拦截器的实现类,如果我们定义的package继承了Struts2的默认struts-default包,则可以自由使用下面定义的拦截器,否则必须自己定义这些拦截器。
下面是Struts2内建拦截器的简要介绍:
alias:实现在不同请求中相似参数别名的转换。
autowiring:这是个自动装配的拦截器,主要用于当Struts2和Spring整合时,Struts2可以使用自动装配的方式来访问Spring容器中的Bean。
chain:构建一个Action链,使当前Action可以访问前一个Action的属性,一般和<result type="chain" .../>一起使用。
conversionError:这是一个负责处理类型转换错误的拦截器,它负责将类型转换错误从ActionContext中取出,并转换成Action的FieldError错误。
createSession:该拦截器负责创建一个HttpSession对象,主要用于那些需要有HttpSession对象才能正常工作的拦截器中。
debugging:当使用Struts2的开发模式时,这个拦截器会提供更多的调试信息。
execAndWait:后台执行Action,负责将等待画面发送给用户。
exception:这个拦截器负责处理异常,它将异常映射为结果。
fileUpload:这个拦截器主要用于文件上传,它负责解析表单中文件域的内容。 
i18n:这是支持国际化的拦截器,它负责把所选的语言、区域放入用户Session中。
logger:这是一个负责日志记录的拦截器,主要是输出Action的名字。
model-driven:这是一个用于模型驱动的拦截器,当某个Action类实现了ModelDriven接口时,它负责把getModel()方法的结果堆入ValueStack中。
scoped-model-driven:如果一个Action实现了一个ScopedModelDriven接口,该拦截器负责从指定生存范围中找出指定的Modol,并将通过setModel方法将该Model传给Action实例。
params:这是最基本的一个拦截器,它负责解析HTTP请求中的参数,并将参数值设置成Action对应的属性值。
prepare:如果action实现了Preparable接口,将会调用该拦截器的prepare()方法。
static-params:这个拦截器负责将xml中<action>标签下<param>标签中的参数传入action。
scope:这是范围转换拦截器,它可以将Action状态信息保存到HttpSession范围,或者保存到ServletContext范围内。
servlet-config:如果某个Action需要直接访问Servlet API,就是通过这个拦截器实现的。
注意:尽量避免在Action中直接访问Servlet API,这样会导致Action与Servlet的高耦合。
roles:这是一个JAAS(Java Authentication and Authorization Service,Java授权和认证服务)拦截器,只有当浏览者取得合适的授权后,才可以调用被该拦截器拦截的Action。
timer:这个拦截器负责输出Action的执行时间,这个拦截器在分析该Action的性能瓶颈时比较有用。
token:这个拦截器主要用于阻止重复提交,它检查传到Action中的token,从而防止多次提交。
token-session:这个拦截器的作用与前一个基本类似,只是它把token保存在HttpSession中。
validation:通过执行在xxxAction-validation.xml中定义的校验器,从而完成数据校验。
workflow:这个拦截器负责调用Action类中的validate方法,如果校验失败,则返回input的逻辑视图。
大部分时候,开发者无需手动控制这些拦截器,因为struts-default.xml文件中已经配置了这些拦截器,只要我们定义的包继承了系统的struts-default包,就可以直接使用这些拦截器。

当然,Struts2的拦截器机制并不是来自于Struts1,而是来自于WebWork。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值