interceptor

来源:互联网 发布:淘宝网 网银支付 编辑:程序博客网 时间:2024/05/29 08:32

一、什么是拦截器?

     

拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。

在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。

谈到拦截器,还有一个词大家应该知道——拦截器链(Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

实现原理

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

图1 拦截器调用序列图
图1 拦截器调用序列图

二、拦截器在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,则返回一个真正的,也就是该actionexecute()方法返回的逻辑视图,反之,则返回一个自定义的逻辑视图。

通常我们使用拦截器并不需要申请资源,为此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。



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 华为手机老卡怎么办 小米手机慢卡怎么办 华为指纹识别不灵敏了怎么办 金立手机信号不好怎么办 手机边框坏了怎么办 手机保护膜划了怎么办 车膜贴的有气泡怎么办 手机膜进气泡怎么办 贴的手机膜翘角怎么办 全屏膜出现气泡怎么办 手机膜的气泡怎么办 透明手机壳气泡怎么办 钢化膜边缘有气泡怎么办 贴钢化膜边缘有气泡怎么办 钢化膜边上有泡泡怎么办 贴钢化膜周边有气泡怎么办 钢化膜里面有气泡怎么办 手机保护膜破了怎么办 手机触摸屏没反应怎么办 苹果手机触屏坏了怎么办 手机边缘有气泡怎么办 手机膜有空气怎么办 电脑膜有气泡怎么办 汽车贴膜起泡怎么办 汽车玻璃膜用久了起泡怎么办 车窗玻璃膜起泡怎么办 新车贴膜气泡怎么办 贴手机钢化膜有灰尘怎么办 戒指砖石掉了怎么办 寄手机没有包装怎么办 手机背面有划痕怎么办 oopo手机声音小怎么办 手机屏幕被划了怎么办 oppo手机组装屏卡顿怎么办 金立手机卡顿怎么办 vivo手机有点卡怎么办 oppo手机有点卡怎么办 mx6指纹不匹配怎么办 小米手机cpu太高好烫怎么办 魅族mx6卡顿怎么办 魅族mx5反应慢怎么办