现在的位置: 首页 > 综合 > 正文

Struts2默认拦截器栈分析

2013年12月09日 ⁄ 综合 ⁄ 共 7371字 ⁄ 字号 评论关闭

Struts2默认拦截器栈分析

edited By Bruce Bob

Struts中默认的拦截器栈

打开struts-default.xml文件,在最下面我们可以看到

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

该配置说明Struts默认使用的拦截器栈是defaultStack。我们看一下默认的拦截器栈都有哪些拦截器:

<interceptor-stackname="defaultStack">

                <interceptor-refname="exception"/>

                <interceptor-refname="alias"/>

                <interceptor-refname="servletConfig"/>

                <interceptor-refname="i18n"/>

                <interceptor-refname="prepare"/>

                <interceptor-refname="chain"/>

                <interceptor-refname="debugging"/>

                <interceptor-refname="scopedModelDriven"/>

                <interceptor-refname="modelDriven"/>

                <interceptor-refname="fileUpload"/>

                <interceptor-refname="checkbox"/>

                <interceptor-refname="multiselect"/>

                <interceptor-refname="staticParams"/>

                <interceptor-refname="actionMappingParams"/>

                <interceptor-refname="params">

                 <paramname="excludeParams">dojo\..*,^struts\..*</param>

                </interceptor-ref>

                <interceptor-refname="conversionError"/>

                <interceptor-refname="validation">

                   <paramname="excludeMethods">input,back,cancel,browse</param>

                </interceptor-ref>

                <interceptor-refname="workflow">

                   <paramname="excludeMethods">input,back,cancel,browse</param>

                </interceptor-ref>

           </interceptor-stack>

下面,我们就分别对这些拦截器进行分析,看Struts在处理请求的时候,通过拦截器都做了哪些工作。

1:异常处理拦截器(exception)

<interceptorname="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>

看该类源码中的intercept:

try {

           result = invocation.invoke();

        } catch(Exception e) {

            if(isLogEnabled()) {

               handleLogging(e);

            }

           List<ExceptionMappingConfig> exceptionMappings =invocation.getProxy().getConfig().getExceptionMappings();

           String mappedResult = this.findResultFromExceptions(exceptionMappings,e);

            if (mappedResult!=null) {

               result = mappedResult;

               publishException(invocation, new ExceptionHolder(e));

            } else {

                throw e;

            }

       }

注意,这里是对invocation.invoke(); 中出现的异常进行捕获的。

2:别名拦截器(aliasInterceptor)

该拦截器主要作用是将一个参数别名成为另一个参数,在不同的action之间相似的参数(但是不同名)扮演着胶水的角色。该拦截器在action链中有很大的作用。

这个拦截器在xwork的jar包里,它的作用是给参数起一个别名,可用于在action链中以不同的名字共享同一个参数,也可用于把http请求参数以不同的名字映射到action里。

拦截器有一个参数:aliasesKey,可通过在struts.xml中定义该拦截器时指定其值,默认值是aliases,表示一个别名的map。

下面以实现在action链中以不同的名字共享同一个参数为例:

struts.xml:

<package name="test"namespace="/test">  

<action name="aliasTestFrom"class="test.AliasInterceptorTestFromAction">  

       <result type="chain">aliasTestTo</result>  

    </action>  

    <actionname="aliasTestTo"class="test.AliasInterceptorTestToAction">  

     <paramname="aliases">#{'someList' :'otherList'}</param>  

       <result>/test/alias_result.jsp</result>  

    </action>  

</package>  

param标签的name属性值应该和拦截器参数aliasesKey的值一样,这样拦截器才知道你是否指定了action的别名map。这个map应该象#{原参数名1 : 别名1, 原参数名2 : 别名2}这样的形式,这是一个定义map的OGNL表达式。

该拦截器已经包含在defaultStack中,因此上面没有显示的指定。

相应的,在本例中,test.AliasInterceptorTestFromAction里有一个字段someList:

AliasInterceptorTestFromAction.java
private List someList;   
       
public List getSomeList() {   
    return someList;   
}   
  
public void setSomeList(List someList) {   
    this.someList = someList;   
}  

test.AliasInterceptorTestToAction里有一个字段otherList:

AliasInterceptorTestToAction.java
private List otherList;   
       
public List getOtherList() {   
    return otherList;   
}   
  
public void setOtherList(List otherList) {   

    this.otherList =otherList;   

}  

注 意:AliasInterceptorTestToAction中不能有一个叫someList的字段,如果有的话,otherList最终的值将是AliasInterceptorTestToAction中的someList,而非AliasInterceptorTestFromAction的值。因为该拦截器的实现是在action的值栈里找到原参数名后设置给别名,如果两个action都有someList,而AliasInterceptorTestToAction位于栈顶,它的someList将被赋给otherList,这并不是我们所期望的结果。

someList也可以来自于http请求参数,因为拦截器如果在action的值栈里没有找到someList,还会在http请求参数里找。

3:配置拦截器(servletConfig)

该拦截器设置基于action接口实现的action属性。比如说,一个action实现{@link ParameterAware} 接口,那么action上下文的参数map将会被设置到action中。该拦截器设计成如果action需要获取基于servlet的参数,则设置所有的属性到action中,包括servlet context,session等。需要实现的接口如下:

 <li>{@link
ServletContextAware
}
</li>

 

 <li>{@linkServletRequestAware}</li>

 

 <li>{@linkServletResponseAware}</li>

 

 <li>{@linkParameterAware}</li>

 

 <li>{@linkRequestAware}</li>

 

 <li>{@linkSessionAware}</li>

 

 <li>{@linkApplicationAware}</li>

 

 <li>{@linkPrincipalAware}</li>

这里需要注意的是ServletReqeustAware接口和RequestAware接口的区别。前者是获取httpServletRequest原生对象,后者是获取包含了request则很难过所有attribute属性的map类型的参数。

4:国际化拦截器(i18n)

 

5:预处理拦截器(prepare)

在action 方法执行前,调用prepare方法。(只对实现了prepareAble接口的aciton有效)。

该拦截器通常用于执行执行action条件判断,判断是否执行action中所有的条件都已经满足。

6:action链拦截器(chain)

能将所有实例的所有属性都拷贝到当前执行的对象的valueStack中。除非该对象实现了Unchainable接口。该连接器同 action返回类型为chain联合使用。

这里其实并不难理解。request请求在服务器端进入另一个action可以理解成为是服务器端跳转。但是,因为struts2本身的设计思想,所有的action都是prototype的也就是对于每一个请求都单独生成一个action。所有,跳转后的action中没有相应的参数,就需要从前一个action获取参数。该chain就是将前一个action中的参数复制到要跳转的action中。

7:debug拦截器(debugging)

 

8:scopedModelDriven

 

该拦截器只对实现了ScopedModelDriven 接口的action实例起作用。

protected ObjectresolveModel(ObjectFactory factory, ActionContext actionContext, StringmodelClassName, String modelScope, String modelName)throwsException
{

        Objectmodel = null;

       Map<String, Object> scopeMap = actionContext.getContextMap();

        if ("session".equals(modelScope)) {

            scopeMap =actionContext.getSession();

        }

       

        model = scopeMap.get(modelName);

        if (model ==
null
) {

           model = factory.buildBean(modelClassName, null);

            scopeMap.put(modelName,model);

        }

        return model;

}

从该方法中可以看到,默认的都是对context起作用的。除非设置了scopeKey。

9:modelDriven

 

类:com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor

该拦截器同上面原理一样,是只对实现了ModelDriven接口的action起作用

10:文件上传拦截器(fileUpload)

类:org.apache.struts2.interceptor.FileUploadInterceptor

拦截器基于MultiPartRequestWapper,只要是在request中包含一个文件,就会被自动调用。他加入了一下几个参数:File , ContentType,FileName。

该拦截器只对request是MultiPartRequestWrapper 类型的才进行处理。注意,如果是文件上传的请求,在过滤器还是dispatcher中就已经对request进行包装了。

这里先简单介绍下,回头重点分析。

 

11:checkBox处理拦截器(checkbox)

类:org.apache.struts2.interceptor.CheckboxInterceptor

此拦截器是针对checkbox表单控件的。

当提交的表单里有checkbox时,默认情况下,如果没选中,提交的值是null;如果选中,提交的值是"true"。

CheckboxInterceptor的作用是当没选中checkbox时,提交一个指定的值,而不是null。

你需要在页面为每个checkbox指定一个名字为"__checkbox_"+checkbox名的hidden控件,例如,如果表单有一个名为vip的checkbox,就需要一个名为_checkbox_vip的hidden。默认的,这个事情不需要你来做,因为Struts2在checkbox的simple模板中已经为你做了,即下面这条语句:

checkbox.ftl

<input type="hidden" name="_checkbox_${parameters.name?html}" value="${parameters.fieldValue?html}"/>  

CheckboxInterceptor实现原理如下:

当提交表单后,CheckboxInterceptor会在请求参数里查找名字以"_checkbox_"开头的参数,如果找到,继续在请求参数里找对应的checkbox参数,如果没找到(表示没有选中该checkbox),就给checkbox参数一个指定的值,默认的,这个值为"false"。可以在struts.xml定义拦截器时改变这个值,如下,将其值改成"no":

<interceptor-ref name="checkbox">  

    <param name="uncheckedValue">no</param>  

</interceptor-ref>  

默认情况下,请求每个action都会调用CheckboxInterceptor,因为在Struts2定义的默认拦截器defaultStack中包含了它。

12:多选拦截器(multiselect)

类:org.apache.struts2.interceptor.MultiselectInterceptor

同checkbox一样,如果没有选中,则设置默认的值。

13:静态参数拦截器(staticParams)

类:com.opensymphony.xwork2.interceptor.StaticParametersInterceptor

该拦截器将action中配置的静态参数添加到action中。如果action实现了Parameterizable接口,那么,一个map的静态参数也将会设置到action中。

14:actionMappingParams

类:org.apache.struts2.interceptor.ActionMappingParametersInteceptor

该拦截器设置从action映射,当前请求,所有的参数到值栈中。他的操作就像parametersInterceptor一样,只是参数从ActionMapping中来,而不是从actionContext.getParameters()

15:params

 

这里有几个拦截器没有分析,近期手头上的事儿有点杂,最近发的博文也少了,先发上来吧。回头再看看修补一下。

抱歉!评论已关闭.