全方位解析:Struts2 配置文件

1.1.1 web.xml配置

任何MVC框架都需要与Web应用整合,就不得不依赖于web.xml文件,只有配置在web.xml文件中的Servlet、Filter才会被应用加载。

1. 核心控制器及参数配置

所有MVC框架都需要Web应用加载一个核心控制器,对于Struts2框架而言,其需要加载FilterDispatcher,只要Web应用负责加载FilterDispatcher,FilterDispatcher将会加载应用的Struts2框架。

FilterDispatcher实质是一个过滤器,它负责初始化整个Struts2框架并且处理所有的请求。这个过滤器可以包括一些初始化参数,有的参数指定了要加载哪些额外的xml配置文件,还有的会影响Struts2框架的行为。除了FilterDispatcher外,Struts2还提供了一个ActionContexCleanUp过滤器,它的主要任务是当有其它一些过滤器要访问一个初始化好了的Struts2框架的时候,负责处理一些特殊的清除任务。ActionContexCleanUp过滤器主要配合其他插件过滤器使用。详细配置,如下图所示:

clip_image002[1]

clip_image004[1]

其中有3个初始化参数有特殊意义:

config:该参数的值是一个以英文逗号(,)隔开的字符串,每个字符串都是一个XML配置文件的位置。Struts 2框架将自动加载该属性指定的系列配置文件。

actionPackages:该参数的值也是一个以英文逗号(,)隔开的字符串,每个字符串都是一个包空间,Struts 2框架将扫描这些包空间下的Action类。

configProviders:如果用户需要实现自己的ConfigurationProvider类,用户可以提供一个或多个实现了ConfigurationProvider接口的类,然后将这些类的类名设置成该属性的值,多个类名之间以英文逗号(,)隔开。

loggerFactory:指定LoggerFactory实现类的类名。

除此之外,还可在此处配置Struts 2常量,每个<init-param>元素配置一个Struts2常量,其中<param-name>子元素指定了常量name,而<param-value>子元素指定了常量value。

至于filter-mapping属性是过滤器(Filter)必须的一个属性,用于过滤请求的路径,此处一般就设为/*形式,对所有请求uri进行拦截(过滤),除非你要做一些特殊的处理。

2. 标签库配置

如果web容器是J2EE1.3(servlet2.3)及以前的规范,由于不会自动加载Struts2的标签库,所以需要在web.xml文件中手动加载Struts2的标签库,将struts-tags.tld文件,一般复制放在WEB-INF下面,可以自己指定,在web.xml中配置的加载标签定义文件如下:

clip_image006[1]

但如果web容器是J2EE1.4(servlet2.4),那么web容器会自动加载标签库,Struts 2的标签库定义文件包含在struts2-core-2.1.6.jar文件里,在struts2-core-2.1.6.jar文件的META-INF路径下,包含了一个struts-tag.tld文件, 这个文件就是Struts 2的标签库定义文件,Servlet 2.4规范会自动加载该标签库文件,避免了在web.xml文件中重新定义Struts2标签库文件的URI。其中struts-tags.tld文件里包含了加载信息的片断,如下:

clip_image008

1.1.2 struts.properties配置

struts.properties文件定义了Struts 2框架的大量属性(也称为Struts2常量),开发者可以通过改变这些属性来满足应用的需求。

struts.properties文件是一个标准的Properties文件,该文件包含了系列的key-value对象,每个key就是一个Struts 2属性,该key对应的value就是一个Struts2属性值。

struts.properties文件通常放在Web应用的WEB-INF/classes路径下。实际上,只

要将该文件放在Web应用的CLASSPATH路径下,Struts 2框架就可以加载该文件。

其实,配置Struts2常量有3个地方:

a) 在struts.properties文件中配置常量;

b) 在web.xml文件中配置FilterDispatcher指定初始化参数来配置常量;

c) 在struts.xml文件中使用<constant …/>元素来配置常量;

下面将该文件必须知道的配置参数详细列举出来,如下图所示:

clip_image010

clip_image012

其他详细配置参数,请参考:struts.properties

1.1.3 struts.xml配置

struts.xml文件主要负责管理应用中的业务控制器Action映射,以及该Action包含的Result定义等。在默认情况下,Struts2框架将自动加载放在WEB-INF/classes路径下的struts.xml文件。

另外,struts-default.xml文件是Struts2框架的默认配置文件,Struts2框架每次都会自动加载该文件。

不仅如此,Struts2框架提供了一种类似Eclipse的扩展方式,允许以一种“可插拔”的方式来安装插件。如:Spring插件、JSF插件等,它们都提供了一个类似的struts2-xxx-plugin.jar的文件,只要将该文件放在WEB-INF/lib路径下,Struts2框架会自动加载该插件。在struts2-xxx-plugin.jar文件中,包含struts-plugin.xml文件,Struts2框架同时也会加载该文件。通过这种方式,Struts2框架允许使用可插拔的方式管理Struts2框架。

上面介绍的struts.xml、struts-default.xml、struts-plugin.xml,所配置的内容没有任何区别,只是加载时顺序有先后(struts-default.xml、struts-plugin.xml、struts.xml),若三个文件中存在相同的配置,后加载的配置会覆盖先加载的配置。

1.struts.xml文件结构

<!-- struts是Struts 2配置文件的根元素 -->

<struts>

<!-- 常量配置元素可以出现零次,也可以出现无数次 -->

<constant name="" value="" />

<!-- Bean配置元素可以出现零次,也可以出现无数次 -->

<bean type="" name="" class="" scope="" static="" optional="" />

<!-- 配置文件包含元素可以出现零次,也可以出现无数次 -->

<include file="" />

<!-- 包元素是Struts配置文件的核心,该元素可以出现零次,或者无数次 -->

<package name="必填的包名" extends="" namespace="" abstract="" externalReferenceResolver>

<!-- 返回结果类型集合元素可以出现,也可以不出现,最多出现一次 -->

<result-types>

<!-- 返回结果类型元素必须出现,可以出现无数次 -->

<result-type name="" class="" default="true|false">

<!-- 返回结果类型参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</result-type>

</result-types>

<!-- 拦截器集合元素可以出现,也可以不出现,最多出现一次 -->

<interceptors>

<!-- 拦截器集合元素的interceptor元素和interceptor-stack至少出现其中之一, 也可以二者都出现 -->

<!-- 拦截器元素可以出现零次,也可以无数次 -->

<interceptor name="" class="">

<!-- 拦截器参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</interceptor>

<!-- 拦截器栈元素可以出现零次,也可以无数次 -->

<interceptor-stack name="">

<!-- 引用拦截器元素必须出现,可以出现无数次 -->

<interceptor-ref name="">

<!-- 引用拦截器参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</interceptor-ref>

</interceptor-stack>

</interceptors>

<!-- 默认拦截器(栈)引用元素可以出现零次,也可以无数次 -->

<default-interceptor-ref name="">

<!-- 默认拦截器(栈)引用参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>

</default-interceptor-ref>

<!-- 默认Action引用元素可以出现零次,也可以无数次 -->

<default-action-ref name="">

<!-- 默认Action引用参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</default-action-ref>?

<!-- 全局返回结果集合元素可以出现零次,也可以无数次 -->

<global-results>

<!-- 返回结果元素必须出现,可以出现无数次 -->

<result name="" type="">

<!-- 该字符串内容可以出现零次或多次 -->

映射资源

<!-- 返回结果参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</result>

</global-results>

<!-- 全局异常映射集合元素可以出现零次,也可以无数次 -->

<global-exception-mappings>

<!-- 异常映射元素必须出现,可以出现无数次 -->

<exception-mapping name="" exception="" result="">

异常处理资源

<!-- 异常映射参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</exception-mapping>

</global-exception-mappings>

<!-- Action元素可以出现零次,也可以无数次 -->

<action name="" class="" method="" converter="">

<!-- Action参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

<!-- 返回结果元素可以出现零次,也可以无数次 -->

<result name="" type="">

映射资源

<!-- 结果参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</result>

<!-- 拦截器(栈)引用元素可以出现零次,也可以无数次 -->

<interceptor-ref name="">

<!-- 拦截器(栈)引用参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</interceptor-ref>

<!-- 异常映射元素可以出现零次,也可以无数次 -->

<exception-mapping name="" exception="" result="">

异常处理资源

<!—异常映射参数元素可以出现零次,也可以无数次 -->

<param name="参数名">参数值</param>*

</exception-mapping>

</action>

</package>*

<!-- 未知处理器栈元素可出现零次或1次 -->

<unknown-handler-stack>

<!-- 未知处理器元素可出现零次或多次 -->

<unknown-handler-ref name=" ">...</unknown-handler-ref>*

</unknown-handler-stack>?

<struts>

2.struts.xml标签使用介绍

a) 使用<include>标签重用配置文件

在Struts2中提供了一个默认的struts.xml文件,但如果package、action、

interceptors等配置比较多时,都放到一个struts.xml文件不太容易维护。因此,就需要将struts.xml文件分成多个配置文件,然后在struts.xml文件中使用<include>标签引用这些配置文件。这样做优点如下:

1) 结构更清晰,更容易维护配置信息;

2) 配置文件可以复用。如果在多个Web程序中都使用类似或相同的配置文件,那么可以使用<include>标签来引用这些配置文件,这样可以减少工作量。

clip_image014

小提示:

用<include>引用的xml文件也必须是完整的struts2配置,如:必须包括头部信息等。实际上<include>在引用时是单独解析的xml文件,而不是将被引用的文件插入到struts.xml文件中。

通常,将Struts2的所有配置文件都放在Web应用的WEB-INF/classes路径下,struts.xml文件包含了其他的配置文件,Struts2框架自动加载struts.xml文件时,完成加载所有配置信息。

b) 使用<constant>标签进行常量配置

在之前提到struts.properties配置文件的介绍中,我们曾经提到所有在struts.properties文件中定义的属性,都可以配置在struts.xml文件中。而在struts.xml中,是通过<constant>标签来进行配置的。

clip_image016

小提示:

通常推荐在struts.xml文件中配置Struts2常量,而不是在struts.properties文件中配置常量。之所以保留使用struts.properties文件配置Struts2常量的方式,主要是为了保持与WebWork之间的兼容性。

统一起来看,Struts2的常量配置可以在struts-plugin.xml、struts.xml、struts.properties、web.xml中配置,则Struts2框架会按如下搜索顺序加载Struts2常量:default.properties、struts-default.xml、struts-plugin.xml、struts.xml、struts.properties、web.xml,如果在多个文件中配置了同一个Struts2常量,则后面文件中配置的常量值会覆盖前面文件中配置的常量值。

通常推荐将Struts2常量集中在struts.xml文件中进行管理。

c) 使用<bean>标签配置Bean组件

Struts2框架是一个高度可扩展性的框架,框架大部分核心组件,Struts2并不是以硬编码的方式写在代码中的,而是以自己的IOC容器来管理框架的核心组件。

Struts2框架以可配置的方式来管理Struts2的核心组件,从而允许开发者可以很方便地扩展该框架的核心组件。当开发者需要扩展,或者替换Struts2的核心组件时,只需要提供自己的组件实现类,并将该组件实现类配置在Struts2的IOC容器中即可。

在strus.xml文件中定义Bean时,通常有两个作用:

1) 创建该Bean的实例,将该实例作为Struts2框架的核心组件使用;

2) Bean包含的静态方法需要注入一个值;

在第一种用法下,因为Bean实例往往是作为一个核心组件使用的,因此需要告诉Struts2容器该实例的作用-就是该实例实现了哪个接口,这个接口往往定义了该组件做必须遵守的规范,配置如下图所示:

clip_image018

在第二种用法下,则可以很方便允许不创建某个类的实例,却可以接受框架常量,通常需要设置static=true。

clip_image020

小提示:

对于绝大部分Struts2应用而言,我们无需重新定义Struts2框架的核心组件,也就无需在Struts.xml文件中定义Bean。

在使用<bean/>元素在struts.xml文件中定义Bean,bean元素有以下几个属性:

class:必填属性,它指定了Bean实例的实现类。

type:可选属性,它指定了Bean实例实现的Struts2的规范,该规范

通常是通过某个接口或者在此前定义过的Bean,因此该属性值通常是个接口或者此前定义过的Bean的name属性值。如果需要将Bean的实例作为Strut2组件使用,则应该指定该属性的值。

name:可选属性,它指定的Bean实例的名字,对于有相同type的多个Bean。则它们的name属性不能相同。

scope:可选属性,它指定Bean实例的作用域,该属性的值只能是default、singleton、request、session或thread之一。

static:可选属性,它指定Bean是否使用静态方法注入。通常而言,当指定了type属性时,该属性就不应该指定为true。

optional:可选属性,它指定Bean是否是一个可选Bean。

d) 使用<package>标签配置包

Struts2框架中核心组件就是Action、Interceptor、Result等,Struts2使用包来管理。每个包就是多个Action、多个Interceptor、多个Result、多个Interceptor引用的集合。

属性

必需

描述

name

包名,作为其它包应用本包的标记

extends

设置本包继承其它包

namespace

设置包的命名空间

abstract

设置为抽象包

1. name属性:必填属性,指定包的名字,该名字是该包被其他包引用的key;

2. abstract属性:该属性为true时,该包为抽象包,抽象包不能包含Action定义;

2. extends属性:当一个包通过配置extends属性继承了另一个包时,该包将会继承父包中所有的配置,包括action、result、interceptor等;由于包信息的获取是按照配置文件的先后顺序进行的,且Struts2配置文件是从上到下处理的,所以父包应该在子包前面定义;通常我们配置struts.xml时,都继承一个名为“struts-defaul”

的包,该包是struts2内置的包。

3. namespace属性:该属性针对大型项目中Action的管理,更重要的是解决Action重名问题,同一个命名空间里不能有同名的Action,不同的命名空间可以有同名的Action。

<package>标签具体配置,如下图所示:

clip_image022

4. Struts2如果没有为某个包指定命名空间,该包使用默认的命名空间,默认的命名空间总是"";

5. Struts2还可以显示指定根命名空间,通过设置包的namespace="/"来指定根命名空间;

6. Struts2会按顺序在命名空间中搜索请求的Action,如下:命名空间只有一个级别。如果请求的URL是/bookservice/search/get.action,系统将先在/bookservice/search的命名空间下查找名为get的Action,如果查找到,则有该Action处理;如果未查找到,系统直接进入默认的命名空间查找名为get的Action,而不会在/bookservice的命名空间下查找名为get的Action;

小提示:

查找Action会根据URL对应的命名空间(可能会是根命名空间)查找Action,若没有,则会在默认命名空间里查找。

7. Struts2默认命名空间和根命名空间两者区别:

默认的命名空间namespace="",根命名空间namespace="/";

clip_image024

如果未指定命名空间,则命名空间默认为namespace=""。默认命

名空间里的Action可以处理任何命名空间下的Action请求,而根命名空间里的Action只处理根命名空间下的Action请求。

Struts2查找对应的Action时,会根据URL首先在对应的命名空间下查找,若未查找到,则继续会在默认命名空间下查找。

e) 使用<interceptor-stack>、<interceptors>、<interceptor>标签配置拦截器

拦截器其实就是AOP的编程思想。拦截器允许在Action处理之前,或者Action处理之后,插入开发者自定义的代码。

通常,使用拦截器可以完成如下操作:进行权限控制、跟踪日志、跟踪系统的性能瓶颈。

Struts2允许多个拦截器组合在一起,形成一个拦截器栈。一个拦截器栈可以包含多个拦截器,多个拦截器组成一个拦截器栈。对于Struts2系统而言,多个拦截器组成的拦截器栈对外也表现成一个拦截器。

可以认为多个拦截器组成拦截器栈是一个大的拦截器。Struts2推荐定义多个小粒度的拦截器,然后组合成拦截器栈来完成复杂的功能,而不是直接定义大粒度拦截器。同一个小粒度的拦截器,可以与其他不同的拦截器组成不同的拦截器栈,从而提供更好的复用性。

定义拦截器栈之前,必须先定义组成拦截器栈的多个拦截器,相关配置如下图所示:

clip_image026

在package元素节点下,设置Action默认拦截器引用:

clip_image028

小提示:

使用<default-interceptor-ref>标签可以为其所在的Action添加默认拦截器功能。当为某个Action单独添加拦截器功能后,<default-interceptor-ref>中所指定的默认拦截器将不再对这个Action起作用,需要再次手动添加默认拦截器引用。

f) 使用<action>标签配置业务控制器Action

1. 实现Action处理类

相对于Struts1而言,Struts2采用了低侵入式的设计,Struts2不要求Action类继承任何的Struts2基类,甚至不要求实现任何Struts2接口,在这种设计方式下,Struts2的Action类是一个普通POJO类(通常应该包含一个无参数的execute方法),Struts2会默认执行该类的execute方法,从而有很好的代码复用性。这正如HelloWord应用中的Action实现类。

Struts2通常直接使用Action来封装Http请求参数,如下图所示:

clip_image030

小提示:

即使Action需要处理的请求包含username和password两个HTTP参数,Action类也可以不包含username和password属性。因为系统是通过对应的getter和setter方法来处理请求参数的,而不是通过属性名来处理请求参数的。也就是说,如果包含username的HTTP请求参数,Action类里是否包含username属性并不重要,重要的是须要包含setter和getter两个方法。

Action类里的属性,不仅用于封装请求参数,还可以用于封装处理结果。对系统而言,封装请求参数的属性和封装处理结果的属性是完全平等的。

如果HTTP请求里包含了名为username的请求参数,系统会调用Action类的setUsername方法,通过这种方法,名为username的请求参数就可以传递给Action实例;如果Action类里没有包含对应的set方法,则请求参数无法传入该Action。

同样,在jsp页面中输出Action属性username时,系统会调用Action类的getUsername方法,系统不会区分该属性是用于封装请求参数的属性还是用于封装处理结果的属性。因此,使用Struts2的标签既可以输出Action的处理结果,也可以输出HTTP请求参数值。

2. Action接口与ActionSupport类

虽然Struts2没有要求Action必须实现特定接口或继承特定类,但为了让用户开发的Action类规范,Struts2提供了一个Action接口,这个接口定义了Struts2的Action处理类应该实现的规范,开发者的Action类可以实现该接口。下面是标准Action接口的代码:

clip_image032

Struts2还为Action接口提供了一个实现类:ActionSupport,下面是该ActionSupport实现类的代码:

clip_image034

clip_image036

小提示:

ActionSupport是一个默认的Action类,该类已经提供了许多默认的方法,这些默认方法包括获取国际化信息的方法、数据校验的方法、默认的处理用户请求的方法等。实际上,ActionSupport类完全可以作为Struts2应用的Action处理类(因为它已经实现了execute方法),如果让开发者的Action类继承该ActionSupport类,则会大大简化Action的开发。

由于ActionSupport完全可作为Struts2应用的Action处理类,因此当用户配置Action类没有指定class属性时,系统会自动使用ActionSupport类作为Action默认的处理类。此时,该Action总是返回“success”字符窜作为逻辑视图名。配置Action默认的处理类,如下图所示:

clip_image038

3. Action访问Servlet API

Struts2的Action并未直接与任何Servlet API耦合,这是Struts2的一个改良之处,因为Action类不再与Servlet API耦合,从而能更轻松地测试该Action。

但对于Struts2应用中控制器而言,除了将请求参数自动设置到Action的字段中,不访问Servlet API几乎是不可能的。Struts2应用中通常需要访问的Servlet API就是HttpServletRequest、HttpSession和ServletContext,这3个类分别代表JSP内置对象中的request、session和application。Struts2通常会以下面两种方式,访问Servlet API:

非IOC方式

通过以非IOC的方式访问上述对象,关键是要通过Struts 2中com.opensymphony.xwork2.ActionContext类的方法获得Struts2封装的Servlet API的Map对象。

ActionContext是一个Action的上下文对象,Action运行期间所用到的数据都保存在ActionContext中(如Session,客户端提交的参数等信息)。上下文可以看作是一个容器(其实我们这里的容器就是一个Map而已),它存放的是Action在执行时需要用到的对象,比如:在使用WebWork时,我们的上下文放有请求的参数(Parameter)、会话(Session)、Servlet上下文(ServletContext)、本地化(Locale)信息等。在Action中可以通过下面的代码来创建和使用ActionContext类,关于该类的方法介绍如下所示:

ActionContext ac=ActionContext.getContext();//获取ActionContext对象

1.Object get(Object key) :通过参数key来查找当前ActionContext中的对应的value。该方法可获取HttpServletRequest属性。
2.Map getApplication() :返回一个Application级的Map对象,该对象模拟了该应用的ServletContext实例。
3.Static ActionContext getContext() :静态方法,获得当前线程的ActionContext对象。
4.Map getParameters() :返回一个包含所有HttpServletRequest参数信息的Map对象 。
5.Map getSession() :返回一个Map类型的HttpSession对象,该对象模拟了HttpSession实例。
6.Void put(Object key,Object value) :向当前ActionContext对象中存入键值对信息,该方法可用于向HttpServletRequest里存入属性。
7.Void setApplication(Map application) :直接传入一个Map实例,将该Map实例里的key-value对转换成application的属性名、属性值,以设置Application上下文对象。
8.Void setSession(Map session) :直接传入一个Map实例,将该Map实例里的key-value对转换成session的属性名、属性值。

小提示:

1.WebWork框架将与Web相关的很多对象重新进行了包装,比如这里就将HttpSession对象重新包装成了一个Map对象,供我们的Action使用,而不用直接和底层的HttpSession打交道。也正是框架的包装,让我们的Actoion可以完全的和Web层解藕。

2.ActionContext有一个内置的map,所有的参数都保存在这个map中,其中就有valuestack;

3.在每次执行Action之前都会创建新的ActionContext,ActionContext是线程安全的,也就是说在同一个线程里ActionContext里的属性是唯一的,这样我的Action就可以在多线程中使用。ActionContext中有个静态的ThreadLocal变量,用来存放每个Action的actionContext。如下图所示:

clip_image040

ActionContextThreadLocal是实现ThreadLocal的一个内部类。ThreadLocal可以命名为“线程局部变量”,它为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。这样,我们ActionContext里的属性只会在对应的当前请求线程中可见,从而保证它是线程安全的。

非IOC方式实现Action,如图所示:

 clip_image042

显然,相比Struts1中直接访问Servlet API,Struts2通过ActionContext访问Servlet API更加优雅。让Action彻底从Servlet API中分离出来,从而可以允许该Action脱离Web容器运行。最大的好处:可以脱离Web容器测试。

另外,为了直接访问Servlet API,Struts2提供了一个ServletActionContext,这个类包含了几个静态方法:

PageContext getPageContext():取得Web应用Http页面的PageContext对象。

HttpServletRequest getRequest():取得Web应用HttpServletRequest

对象。

HttpServletResponse getResponse():取得Web应用的

HttpServletResponse对象。

ServletContext getServletContext():取得Web应用的ServletContext对象。

具体使用,相关代码如图所示:

clip_image044

小提示:

借助ServletActionContext类的帮助,开发者也可以在Action中直接访问Servlet API,避免Action类需要实现XXXAware接口,虽然如此,此种方式仍不被推荐,该Action依然与Servlet API直接耦合,一样不利于程序解耦。

IOC方式

要使用IOC方式,通常首先要告诉IOC容器想取得某个对象的意愿,通过实现对应的接口可以做到这点。

ServletContextAware:实现了该接口的Action可以直接访问web应用的ServletContext实例。

SerlvetRequestAware:实现了该接口的Action可以直接访问webDe HttpSerlvetRequest实例。

ServletResponseAware:实现了该接口的Action可以直接访问服务器的相应的HttpServletResponse对象。

如果实现了ServletResponseAware只需要实现之中的public void setServletResponse(HttpServletResponse response)方法即可,然后就可以使用httpServletResponse对象进行操作。ServletRequestAware对象也是这样的。

相关代码如图所示:

clip_image046

小提示:

必须指出,虽然可以在Action类中获取HttpServletResponse,但如果希望通过HttpServletResponse来生成服务器响应是不可能的,因为Action只是控制器。即如果在Action中书写如下代码:

response.getWrite().println("Hello World");

上面代码在标准Servlet中会生成对客户端的输,但在Struts2的Action中,没有任何实际意义。

所以即使我们在Struts2的Action类中获得了HttpServletRequest对象,也不要尝试直接在Action中生成对客户端的输出。因为那很没意义。

4. 配置Action

一旦提供了Action的实现类后,就可以在struts.xml文件中配置该Action。配置Action就是让Struts2容器知道该Action的存在,并且能够调用该Action来处理用户请求。因此,Action是Struts2的基本“程序单位”。

<action>属性介绍

属性名称

是否必须

功能描述

name

请求的Action名称

class

Action处理类对应具体路径

method

指定Action中的方法名

converter

指定Action使用的类型转换器

1. name属性:必选属性,指定该Action的名字,也同时指定该Action需要处理的URL的后半部分,如:URL为/bookservice/search/get.action,则name应该为get;等同于Struts1中Action的path属性。

如果需要在name属性中使用斜线(/),则需要指定Struts2框架允许Action name中出现斜线。配置如图所示:

clip_image048

如果我们希望Struts2应用可以列出Web应用根路径下的所有页面,则可以在struts.xml文件中配置一个name=””的Action,该Action就可以处理列出Web应用根路径下的所有文件请求。配置如下图所示:

clip_image050

此外,还需要保证Web容器本身可以列出根路径下所有文件。比如Tomcat 5.5、6.0,它默认是不会列出的。所以要修改Tomcat的conf/web.xml文件98行的listings参数,将其修改为true。

2. class属性:可选属性,指定该Action的实现类。若未指定class属性,系统则默认使用系统的ActionSupport类。

3. method属性:可选属性,指定Action处理请求的方法名。若未指定method属性,则Action处理请求默认执行execute方法。

4. 动态方法调用:可以采用DMI调用来处理这种请求。动态方法调用是指表单元素的action并不是直接等于某个Action的名字。而是以如下来指定Form的action属性:

action=”action!methodName.action”(若以/开始,则为绝对路径;否则为相对路径。)

使用动态方法调用前必须设置Struts2允许动态方法调用。配置如下:

clip_image052

5. 使用通配符:在配置<action>元素时,需要指定name、class和method属性,其中name属性可支持通配符,然后可以在class、method属性中使用表达式。这种使用通配符的方式是另一种形式的动态方法调用。

clip_image054

实际上,Struts2不仅允许在class、name、method属性中使用表达式,还可以在<result>元素中使用表达式。

使用通配符模式配置Action时,URL与 Action的匹配规则如下:因为除非请求的URL与Action的name属性绝对相同,否则,将按先后顺序来决定由哪个Action来处理用户请求。因此,我们应该将名为星号“*”的Action配置在最后,否则Struts2将使用该Action来处理所有希望使用通配符匹配的请求。

6. 配置默认Action

对于使用Struts2框架的应用而言,尽量不要让超链接直接链接到某个视图资源,因为这种方式增加了额外的风险。推荐将所有请求都发送给Struts2框架,让该框架来处理用户请求,即使只是简单的超链接。

对于只是简单的超链接的请求,可以通过定义name为*的Action(该Action应该放在最后位置定义)实现。除此之外,Struts2还允许在容器中定义一个默认的Action,当用户请求的URL在容器中找不到对应的Action时,系统将使用默认Action来处理用户请求。相关配置如图所示:

clip_image056

<action>具体配置

clip_image058

小提示:

Action只是一个控制器,它并不会像Servlet那样直接对浏览者生成任何响应。所以,在Action中,任何的response输出都是无效的,非法的,因此,Action处理完用户请求后,Action需要将指定的视图资源呈现给用户,因此,配置Action时,应该配置逻辑视图资源和物理视图资源之间的映射。

j) 使用<result>标签配置返回结果

配置逻辑视图资源和物理视图资源之间的映射关系是通过<result>元素来定义的,每个<result>元素定义逻辑视图和物理视图之间的一次映射。

Action处理完用户请求后,并未直接将请求转发给任何具体的视图资源,而是返回一个逻辑视图,Struts2框架收到这个逻辑视图后,把请求转发到对应的视图资源,视图资源将处理结果呈现给用户。

简单的说,结果是告诉Struts2框架,当Action处理结束时,系统下一步做什么。当Action返回一个普通字符串时,系统下一步将做什么。

局部结果:将<result>作为<action>元素的子元素配置;

全局结果:将<result>作为<global-results>元素的子元素配置;

<result>属性介绍

属性名称

是否必须

功能描述

name

对应Action返回逻辑视图名称,默认为success

type

返回结果类型,默认为dispatcher

parse

指定是否允许在实际视图名字中使用OGNL表达式,默认为true。

小提示:

1. Struts2默认的结果类型是dispatcher,但我们可以通过修改配置文件,改变默认的结果类型。一旦改变了默认的结果类型,如果配置<result>元素时省略type元素时,则意味着使用默认的结果类型。

2. 如果配置<result>元素时没有指定location参数,系统将会把<result>…</result>中间的字符串当成实际视图资源;

如果没有指定name属性,则name属性采用默认值:success;

如果没有指定type属性,则采用Struts2的默认结果类型;

3. 全局结果的作用范围是对所有的Action都有效;局部结果的作用范围仅是当前Action有效。

4. 如果一个Action里包含了与全局结果里同名的结果,则Action里的局部Action会覆盖全局Action。也就是说,当Action处理用户请求结束后,会首先在本Action里的局部结果里搜索逻辑视图对应的结果,只有在Action里的局部结果里找不到逻辑视图对应的结果,才会到全局结果里搜索。

<result>具体配置

1. 全局结果配置

clip_image060

2. 局部结果配置

clip_image062

h) 使用<result-type>标签配置返回结果类型

Struts2支持使用多种视图技术,如:JSP、Velocity和FreeMarker等。当一个Action处理用户请求结束后,仅仅返回一个字符串,这个字符串只是逻辑视图名,该逻辑视图并未与任何的视图技术及任何的视图资源关联,直到我们在struts.xml文件中为该逻辑视图指定实际的视图资源。

结果类型决定了Action处理结束后,下一步将执行哪种类型的动作。

Struts2的结果类型要求实现com.opensymphony.xwork.Result接口,是所有Action执行结果的通用接口。如果我们需要自己的结果类型,我们应该提供一个实现该接口的类,并且在struts.xml文件中配置该结果类型。

以下列出Struts2框架自带的几种结果类型配置,并做了简要说明,如图所示:

clip_image064

k) 使用<global-exception-mapping>、<exception-mapping>标签配置异常映射

clip_image066

l) 使用<unknown-handler-stack>与<unknown-handler-ref>标签配置未知处理器

clip_image068

转载于:https://my.oschina.net/xianggao/blog/75951

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值