JavaEE学习笔记之SSH—Struts2(4)

这篇文章讲讲 Struts2 的核心所在——拦截器

一、strut2框架中的拦截器(interceptor)

1.什么是拦截器(interceptor)

  拦截器是strut2框架中提供的一种java类。

  作用:

   1.可以拦截访问action的请求

   2.给这个action加入新的丰富功能(上传、参数自动接收、类型自动转换等等)需要配置之后,指明哪一个拦截器去拦截哪一个action或者哪一些action,这样这个拦截器才会去拦截我们的这个action,每一个拦截器就可以给我们的action加入一个新的功能.

2.拦截器(interceptor)如何工作的

  a.有一个拦截器的类(struts2框架自带的或者我们自己定义的一个类)

  b.在配置文件中把这个拦截器类配置出来.

  c.指明这个拦截器要拦截哪一个或者哪一些action.

  d.客户端发送一个请求访问一个被拦截器拦截的action

  e.这个请求会先被struts2的filter所拦截,filter会先检查这个请求是不是请求的action,如果是action的话,那么会再检查这个action有没有被定义的拦截器所拦截,有如果那么就把这个请求交给拦截器去处理.

3.如何自定义一个拦截器

  struts2框架已经写好了很多个拦截器(在struts2的核心jar包),同时也把这些拦截器配置在配置文件里面(在struts-default.xml中).

  除此以外,我们还能写自己的的拦截器。

  要写一个拦截器,首先要实现一个接口:com.opensymphony.xwork2.interceptor.Interceptor

  例如:
public class MyInterceptor implements Interceptor{
            public void destroy() {

                System.out.println("in destory() of MyInterceptor");

            }

            public void init() {
                System.out.println("in init() of MyInterceptor");

            }

            //拦截到访问action的情况的时候调用这个方法
            public String intercept(ActionInvocation ai) throws Exception {

                System.out.println("before...");
                //ai.invoke()其实就是帮我们去调用action中将要执行的方法,比如execute方法
                //ai.invoke()的返回值其实就是action中方法执行完返回的字符串
                String s = ai.invoke();
                System.out.println("after...");
                return s;
            }
         }

Init()方法:在服务器起动的时候加载一次,并且只加载一次;

Destroy()方法:当拦截器销毁时执行的方法;

Interceptor()方法:其中里边有一个参数invocation

Invocation.invoke()是如果只有一个拦截器执行完这个方法后,会返回给视图,如果有多个拦截器,它顺序的执行完所有的拦截器,才返回给视图.

        然后在struts.xml文件中配置出这个拦截器类:
        <interceptors>
            <interceptor name="myInterceptor" class="com.briup.web.interceptor.MyInterceptor"></interceptor>
        </interceptors>
    最后指明这个拦截器在哪一个action中起作用:
<action name="MyTest">
            <result>/index.jsp</result>
            <interceptor-ref name="myInterceptor"></interceptor-ref>
        </action>

4.拦截器栈

  当前一个action需要被多个拦截器拦截的时候,正常情况下,我们需要在这个action中去引用要使用到的多个拦截器,但是我们可以使用一个拦截器栈去包含那几个拦截器,然后在action中直接引用这个拦截器栈就可以了.

  1.一个拦截器栈可以包含多个拦截器

  2.一个拦截器栈还可以包含其他拦截器栈

  3.定义拦截器或者拦截器栈都要在<interceptors>标签中
  例如:
      <interceptors>
        <interceptor name="myInterceptor" class="com.briup.web.interceptor.MyInterceptor"></interceptor>
        <interceptor-stack name="myStack">
            <!-- 这是我们自己定义的一个拦截器 -->
            <interceptor-ref name="myInterceptor"></interceptor-ref>
            <!-- 这是struts-default.xml文件中定义的一个拦截器 -->
            <interceptor-ref name="params"></interceptor-ref>
            <!-- 这是struts-default.xml文件中定义的一个拦截器栈 -->
            <interceptor-ref name="basicStack"></interceptor-ref>
        </interceptor-stack>
      </interceptors>

5.默认拦截器/拦截器栈

   在一个package中,我们可以把一个拦截器或者拦截器栈声明为一个默认的拦截器/拦截器栈

   作用:将来这个package中所有的action都会被这个默认的拦截器/拦截器栈所拦截。

   例如:
     myStack是一个拦截器或者拦截器栈
       <default-interceptor-ref name="myStack"></default-interceptor-ref>
   注意:
   一般情况下,我们所写的任何action都会被一个叫做defaultStack的拦截器栈所拦截,这个拦截器栈中包含了十几个拦截器,这些拦截器给我们的action提供了很多丰富的功能.因为我们写所有的package都是直接或间接的继承了struts-default.xml文件中的一个名字叫struts-default的package,struts-default包中又把名字叫defaultStack的拦截器栈配置成了一个默认的拦截器栈,那么我们的package就把这个配置继承了过来,所有我们的action正常情况下都会被defaultStack所拦截

   但是如果我们一旦指明了某一个action被我们所写的一个拦截器/拦截器栈所拦截,那么这个action就不会被defaultStack拦截了.所以我们可以在action中主动的再声明 这个action被defaultStack所拦截,或者把defaultStack加入到我们自定义的拦截器栈里面(拦截器栈可以包含拦截器栈)

6.package之间的继承

    我们可以专门再定义一个package,在这个package里面我们只做拦截器/拦截器栈的定义:
<!-- 在这个package中,我们只定义拦截器/拦截器栈 -->
        <package name="MyInter" extends="struts-default" namespace="/">

        <interceptors>
            <interceptor name="myInterceptor" class="com.briup.web.interceptor.MyInterceptor"></interceptor>
            <interceptor-stack name="myStack">
                <interceptor-ref name="myInterceptor"></interceptor-ref>
                <!-- 这是struts-default.xml文件中定义的一个拦截器栈 -->
                <interceptor-ref name="defaultStack"></interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <!-- 声明默认拦截器/拦截器栈 -->
        <!-- 当前包中所有的action都会被这个myStack所拦截器 -->
        <!-- 继承了当前包的其他包里面的所有action也会被这个myStack所拦截器 -->
        <default-interceptor-ref name="myStack"></default-interceptor-ref>

        </package>
    然后我们可以让其他的package去继承我们这个MyInter包,这样一来,其他包中的action都会被我们这个MyInter包中的默认拦截器栈myStack所拦截了。 
    注意:一定要保证action至少是被defaultStack这个拦截器栈所拦截的.

7.注意:在struts.xml中只定义出来一个拦截器,这个拦截器是不会被初始化和销毁的,在action中引用过以后才能让struts2框架帮我们去初始化这个拦截器,但是还是不能销毁,如果还想销毁的话,那么就要在一个拦截器栈中去引用一下这个拦截器才可以.

二、拦截器(interceptor)和过滤器(filter)的比较

 相同点:
   1.都是一种java类

   2.都能拦截客户端发给服务器端的请求

   3.拦截到请求之后都可以做一些相应的处理,最后还可以把这个请求放行.

   4.都需要实现各自相应的接口以及在相应的配置文件中配置.

 不同点:

   1.拦截器(interceptor)是struts2框架中的定义的,过滤器(filter)是web里面的对象,是J2EE标准里面定义的.

   2.拦截器(interceptor)只会拦截器访问action的请求,过滤器(filter)能够拦截所有请求.

   3.拦截器(interceptor)定义在struts.xml文件中,过滤器(filter)定义在web.xml文件中.

   4.拦截器(interceptor)对象的创建、调用、销毁是struts2框架负责的,过滤器(filter)对象的创建、调用、销毁服务器负责的.

我们自己定义的filter能不能拦截Struts2框架中的action

  1.可以拦截

  2.需要在web.xml文件中把我们自己的filter配置在struts2的filter的上面才可以.

  因为web.xml文件中filter配置的先后顺序控制filter起作用的顺序,同时如果struts的filter先拦截到访问action的请求后,不会把这个请求交给下面的filter,而是交给了他它内部的拦截器(interceptor)了,但是如果我们自己filter拦截到请求之后,还是依然会交给下一个filter,也就是交给struts2的filter.

几个简单的拦截器:

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 注解方式(Annotation)(补充)

1.引入 支持Struts2框架注解开发的jar包 struts2-convention-plugin-2.3.4.1
在struts-2.3.24.1-all\struts-2.3.24.1\lib下找

2.struts.xml
    <constant name="struts.convention.action.suffix" value="Action"/>

3.Struts2使用注解开发需要遵循一些规范:

    1)Action要必须继承ActionSupport父类;

    2)Action所在的包名必须以  .action 结尾

    3)类名必须以Action结尾

4.package-info.java 
    @Namespace("/")
    @ParentPackage("struts-default")
    package com.briup.action.manager;
    import org.apache.struts2.convention.annotation.Namespace;
    import org.apache.struts2.convention.annotation.ParentPackage;


5.action中常用的注解:
    Namespace Annotation
    1.通过在ActionClass上定义 @Namespace("/custom")
    2.通过 package-info.java 定义
        @org.apache.struts2.convention.annotation.Namespace("/custom")
        package com.example.actions;

    Action Annotation
    1. @Action(interceptorRefs={ 
            @InterceptorRef("validation"),
            @InterceptorRef("defaultStack")
        })
    2. chain
        @Action("foo")
        public String foo() {
            return "bar";
        }

        @Action("foo-bar")
        public String bar() {
            return SUCCESS;
        }

    Result Annotation
    1.全局,整个类可以访问
    2.局部,某个方法可以访问
    @Results({
        @Result(name="failure", location="fail.jsp")
    })
    public class HelloWorld extends ActionSupport {
        @Action(value="/different/url",results={@Result(name="success", location="http://struts.apache.org", type="redirect")}        )
        public String execute() {
            return SUCCESS;
        }
    }
    可以传递参数:
        results={ @Result(name="success", 
            type="httpheader", 
            params={"status", "500", "errorMessage", "Internal Error"})}

补充:

          1,@ParentPackage:对应xml配置文件中的package的父包,一般需要继承struts-default。

          2,@Namespace:对应配置文件中的nameSpace,命名空间。

          3,写在方法前边的注解:

                @Action,这个注解对应<action>节点

                value(),表示action的请求名称,也就是<action>节点中的name属性;

                results(),表示action的多个result;这个属性是一个数组属性,因此可以定义多个Result;

                interceptorRefs(),表示action的多个拦截器。这个属性也是一个数组属性,因此可以定义多个拦截器; 

                exceptionMappings(),这是异常属性,它是一个ExceptionMapping的数组属性,表示action的异常,在使用时必须引用相应的拦截器

          4,看一下action中最常用的results中单个result注解的配置吧:
                @Result,这个注解对应了<result>节点。这个注解只能应用于action类上。这个注解中也有几个属性:

                name(),表示action方法的返回值,也就是<result>节点的name属性,默认情况下是【success】;

                location(),表示view层文件的位置,可以是相对路径,也可以是绝对路径;

                type(),是action的类型,比如redirect,不指定情况下,框架默认的是dispatcher

     这些注解基本上就可以完成我们的功能了,通过这样注解开发,可以代替配置xml的编写。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值