Struts教程

本文主要讲解什么是Struts Framework,它的框架结构,组件结构,以及简单的配置讲解。
文章的包括了如下七大部分:
Framework的概念和体系简介
Struts的概念和体系结构
Struts的工作原理和组件
Struts配置文件简介
Struts高级特性
Struts标记库
一个简单的示例
Framework概念
一直以来我们都说Struts是一个Web Framework。那么让我么先来看看什么是Framework。
Framework概念并不是很新了,伴随着软件开发的发展,在多层的软件开发项目中,可重用、易扩展的,而且是经过良好测试的软件组件,越来越为人们所青睐。这意味着人们可以将充裕的时间用来分析、构建业务逻辑的应用上,而非繁杂的代码工程。于是人们将相同类型问题的解决途径进行抽象,抽取成一个应用框架。这也就是我们所说的Framework。
Framework的体系提供了一套明确机制,从而让开发人员很容易的扩展和控制整个Framework开发上的结构。 通常,Framework的结构中都有一个“命令和控制”组件("command and control" component)——Framework Factory and Manager。
Struts教程
Framework体系
通过基于请求响应(Request-Response)模式的应用Framework,基本上有如下几个表现逻辑结构组成。
控制器(Controller)——控制整个Framework中各个组件的协调工作。
业务逻辑层(Business Logic)——对Framwork本身来说,这里仅仅只是概念和几个提够服务的基础组件,真正的实现与客户的业务逻辑接轨,还需要开发人员在Framework上再次扩展。
数据逻辑层(Data Logic)——绝大应用系统都需要涉及到数据交互,这一层次主要包括了数据逻辑和数据访问接口。对于数据逻辑来说,如果你了解数据建模(Data Modeling)可能就很容易理解。
Struts的概念和体系结构
Struts有一组相互协作的类、Serlvet以及Jsp TagLib组成。基于Struts构架的web应用程序基本上符合JSP Model2的设计标准,可以说是MVC设计模式的一种变化类型。根据上面对framework的描述,我们很容易理解为什么说Struts是一个web framwork,而不仅仅是一些标记库的组合。但 Struts 也包含了丰富的标记库和独立于该框架工作的实用程序类。
Struts有其自己的控制器(Controller),同时整合了其他的一些技术去实现模型层(Model)和视图层(View)。在模型层,Struts可以很容易的与数据访问技术相结合,包括EJB,JDBC和Object Relation Bridge。在视图层,Struts能够与JSP, Velocity Templates,XSL等等这些表示层组件想结合。
Struts的与Web App的关系
Struts教程
既然struts叫做web framework,那么其肯定主要基于web层的应用系统开发。按照J2EE Architecture的标准,struts应当和jsp/servlet一样,存在于web container一层。
Struts与WebApp的关系
Struts的体系结构
我们说struts framework是MVC 模式的体现,下面我们就从分别从模型、视图、控制来看看struts的体系结构(Architecture)。下图显示了struts framework的体系结构响应客户请求时候,各个部分工作的原理。
Struts教程
Struts体系结构
首先,Struts提供了Java类org. apache.struts.action.ActionForm,Java开发者将该类细分来创建表单bean。在运行时,该bean有两种用法:
―当JSP准备相关的HTML,表单以进行显示时,JSP将访问该
bean(它保存要放入表单中的值)。那些值是从业务逻辑或者是从先前的用户输入来提供的。
―当从Web浏览器中返回用户输入时,该bean将验证并保存该输入以供业务逻辑或(如果验证失败的话)后续重新显示使用。
其次,Struts提供了许多定制JSP标记,它们的使用简单,但是它们在隐藏信息方面功能强大。例如,除了bean名称和给定bean中每个段的名称之外,页面设计者不需要知道有关表单bean的更多信息。
Struts虽然不直接有助于模型开发。在Struts中,系统模型的状态主要由ActiomForm Bean和值对象体现。
在Struts framework中, Controller主要是ActionServlet,但是对于业务逻辑的操作则主要由Action、ActionMapping、ActionForward这几个组件协调完成(也许这几个组件,应该划分到模型中的业务逻辑一块)。其中,Action扮演了真正的控制逻辑的实现者,而ActionMapping和ActionForward则指定了不同业务逻辑或流程的运行方向。
Struts的基本组件包
整个struts大约有15包,近200个类所组成,而且数量还在不断的扩展。在此我们不能一一介绍,只能列举几个主要的简要的介绍一下。下表说明了目前struts api中基本的几个组件包,包括action,actions,config,util,taglib,validator。下图则显现了这几个组件包之间的关系。其中action是整个struts framework的核心
org.apache.struts.action
基本上,控制整个struts framework的运行的核心类、组件都在这个包中,比如我们上面提到的控制器ActionServlet。已经Action,ActionForm,ActionMapping等等。struts1.1比1.0多了 DynaActionForm 类。增加了动态扩展生成FormBean功能
org.apache.struts.actions
这个包是主要作用是提供客户的http请求和业务逻辑处理之间的特定适配器转换功能,而1.0版本中的部分动态增删FromBean的类,也在struts1.1中被Action包的DynaActionForm组件所取代
org.apache.struts.config
提供对配置文件struts-config.xml元素的映射。这也是sturts1.1中新增的功能
org.apache.struts.util
Struts为了更好支持web application的应用,体统了一个些常用服务的支持,比如Connection Pool和Message Source。详细信息请参考
http://jakarta.apache.org/struts/api/org/apache/struts/util/package-summary.html
org.apache.struts.taglib
这不是一个包,而是是一个客户标签类的集合。下面包括Bean Tags,HTML Tags,Logic Tags,Nested Tags,Template Tags这几个用于构建用户界面的标签类。
org.apache.struts.validator
Struts1.1 framework中增加了validator framework,用于动态的配置from表单的验证。详细信息请参阅 http://home.earthlink.net/~dwinterfeldt/

Struts教程

Runtime Error
Description:An application error occurred on the server. The current custom error settings for this application prevent the details of the application error from being viewed remotely (for security reasons). It could, however, be viewed by browsers running on the local server machine.

Details:To enable the details of this specific error message to be viewable on remote machines, please create a <customErrors> tag within a "web.config" configuration file located in the root directory of the current web application. This <customErrors> tag should then have its "mode" attribute set to "Off".

<!-- Web.Config Configuration File -->

<configuration>
    <system.web>
        <customErrors mode="Off"/>
    </system.web>
</configuration>

Notes:The current error page you are seeing can be replaced by a custom error page by modifying the "defaultRedirect" attribute of the application's <customErrors> configuration tag to point to a custom error page URL.

<!-- Web.Config Configuration File -->

<configuration>
    <system.web>
        <customErrors mode="RemoteOnly" defaultRedirect="mycustompage.htm"/>
    </system.web>
</configuration>

'>1
Struts的基本组件关系图

 

Struts framework的工作原理和组件
对于Struts 如何控制、处理客户请求,让我们通过对struts的四个核心组件介绍来具体说明。这几个组件就是:ActionServlet。Action Classes,Action Mapping(此处包括ActionForward),ActionFrom Bean。
Struts ActionServlet控制器对象
ActionServlet继承自javax.servlet.http.HttpServlet类,其在Struts framework中扮演的角色是中心控制器。它提供一个中心位置来处理全部的终端请求。控制器ActionServlet主要负责将HTTP的客户请求信息组装后,根据配置文件的指定描述,转发到适当的处理器。
按照Servelt的标准,所有得Servlet必须在web配置文件(web.xml)声明。同样,ActoinServlet必须在Web Application配置文件(web.xml)中描述,有关配置信息如下。
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
</servlet>
全部的请求URI以*.do的模式存在并映射到这个servlet,其配置如下:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
一个该模式的请求URI符合如下格式:
http://www.my_site_name.com/mycontext/actionName.do
中心控制器为所有的表示层请求提供了一个集中的访问点。这个控制器提供的抽象概念减轻了开发者建立公共应用系统服务的困难,如管理视图、会话及表单数据。它也提供一个通用机制如错误及异常处理,导航,国际化,数据验证,数据转换等。
当用户向服务器端提交请求的时候,实际上信息是首先发送到控制器ActionServlet,一旦控制器获得了请求,其就会将请求信息传交给一些辅助类(help classes)处理。这些辅助类知道如何去处理与请求信息所对应的业务操作。在Struts中,这个辅助类就是org.apache.struts.action.Action。通常开发者需要自己继承Aciton类,从而实现自己的Action实例。
ActionServlet把全部提交的请求都被控制器委托到RequestProcessor对象。RequestProcessor使用struts-config.xml文件检查请求URI找到动作Action标示符。
一个Action 类的角色,就像客户请求动作和业务逻辑处理之间的一个适配器(Adaptor),其功能就是将请求与业务逻辑分开。这样的分离,使得客户请求和Action类之间可以有多个点对点的映射。而且Action类通常还提供了其它的辅助功能,比如:认证(authorization)、日志(logging)和数据验证(validation)。
public ActionForward execute(ActionMappingmapping,
 ActionFormform,
 javax.servlet.ServletRequestrequest,
 javax.servlet.ServletResponseresponse)
 throws java.io.IOException,javax.servlet.ServletException


Action最为常用的是execute()方法。(注意,以前的perform方法在struts1.1中已经不再支持),还有一个execute()方法,请参考apidoc,在此不在说明。

当Controller收到客户的请求的时候,在将请求转移到一个Action实例时,如果这个实例不存在,控制器会首先创建,然后会调用这个Action实例的execute()方法。Struts Framework为应用系统中的每一个Action类只创建一个实例。因为所有的用户都使用这一个实例,所以你必须确定你的Action 类运行在一个多线程的环境中。下图显示了一个execute()方法如何被访问:
Struts教程
Action实例的execute()方法
注意,客户自己继承的Action子类,必须重写execute()方法,因为Action类在默认情况下是返回null的。
上面讲到了一个客户请求是如何被控制器转发和处理的,但是,控制器如何知道什么样的信息转发到什么样的Action类呢?这就需要一些与动作和请求信息相对应的映射配置说明。在struts 中,这些配置映射信息是存储在特定的XML文件(比如struts-config.xml)。
这些配置信息在系统启动的时候被读入内存,供struts framework在运行期间使用。在内存中,每一个<action>元素都与org.apache.struts.action.ActionMapping类的一个实例对应。下表就显示了一个登陆的配置映射。
<action-mappings>
<actionpath="/logonAction"
type="com.test.LogonAction"
name="LogonForm"
scope="request"
input="logoncheck.jsp"
validate="false">
<forward name="welcome" path="/welcome.jsp"/>
<forward name="failure" path="/logon_failure.jsp "/>
</action>
</action-mappings>


<form-beans>
<form-bean name="LoginForm"
type="com.test.LoginForm"/>
</form-beans>


上面的配置表示:当可以通过/logonAction.do(此处假设配置的控制器映射为*.do)提交请求信息的时候,控制器将信息委托com.test.LogonAction处理。调用LogonAction实例的execute()方法。同时将Mapping实例和所对应的LogonForm Bean信息传入。其中name=LogonForm,使用的form-bean元素所声明的ActionForm Bean。有关form-bean的申明如下显示。

使用ActionForward导航
元素<forward>则表示了当Action实例的execute()方法运行完毕或,控制器根据Mapping可将响应信息转到适当的地方。如上面现实,如果客户登陆成功,则调用welcome forward,将成功信息返回到/welcome.jsp页面。在你的execute()方法的结尾可以使用下面的实例代码而返回welcome forward。当然你的welcome forward必须在action元素属性中定义,正如上面所声明的那样。
return (mapping.findForward("welcome"));


ActionForward对象是配置对象。这些配置对象拥有独一无二的标识以允许它们按照有意义的名称如“success”,“failure”等来检索。ActionForward对象封装了向前进的URL路径且被请求处理器用于识别目标视图。ActionForward对象建立自<forward>元素位于struts-config.xml。下面是一个Struts中<forward>元素例子,属于<action>元素范围。
<action path="/editCustomerProfile"
type="packageName.EditCustomerProfileAction"
name="customerProfileForm" scope="request">
<forward name="success" path="/MainMenu.jsp"/>
<forward name="failure" path="/CustomerService.jsp"/>
</action>
基于执行请求处理器的execute(…)方法的结果,当传递一个值匹配指定于<forward>元素中name属性的值的时候,下一个视图可以在execute(…)方法中被开发者用方便的方法org.apache.struts.action.ActionMapping.findForward(…)选择。ActionMapping.findForward(…)方法既从它的本地范围又从全局范围提供一个ActionForward对象,该对象返回至RequestProcessor以RequestDispatcher.forward(…)或response.sendRedirect(…)调用下一个视图。当<forward>元素有redirect=“false”属性或redirect属性不存在的时候,RequestDispatcher.forward(…)被执行;当redirect=“true”是,将调用sendRedirect(…)方法。下例举例说明了redirect属性的用法:
<forward name="success" path="/Catalog.jsp" redirect="true"/>
如果redirect=true, URL建立如/contextPath/path因为HttpServletResponse.sendRedirect(…)中解释URL采用”/”开头相对于servlet容器根目录。
如果redirect=false, URI建立如/path因为ServletContext.getRequestDisptacher(…)采用虚拟目录相关URL。
在此稍稍说一下有关global-forwards的概念。其在配置文件中描述了整个应用系统可以使用的ActionForward,而不是仅仅是一个特定的Action。
<global-forwards>
<forward name="logout" path="/logout.do"/>
<forward name="error"path="/error.jsp"/>
</global-forwards>


Struts ActionForm Bean捕获表单数据
在上面讲解ActionServlet,Action Classes和Action Mapping的时候,我们都提到了ActionForm Bean的概念。一个应用系统的消息转移(或者说状态转移)的非持久性数据存储,是由ActionForm Bean的负责保持的。
ActionForm派生的对象用于保存请求对象的参数,因此它们和用户紧密联系。
一个ActionForm类被RequestProcessor建立。这是发生在已完成向前进到一个URL,该URL为映射到控制器servlet而不是JSP和相应的动作映射指定的表单属性的。在这个情况下,如果没有在指定的活动范围内找到,RequestProcessor将尝试寻找可能导致创建一个新ActionForm对象的表单bean。该ActionForm对象在指定的活动范围内被用<action>元素的name属性找到;
RequestProcessor将随后重新安排表单属性,用请求时参数填充表单,随即调用表单对象的validate(…)方法以履行服务器端用户输入验证。仅当ActionMapping对象中validate属性被设为true时,validate(…)方法被调用;这就是默认的行为。request.getParameterValues(parameterName)被用于得到一个String[]对象,它用来表单填充;验证的结果应该是一个ActionErrors对象,用org.apache.struts.taglib.html.ErrorsTag来显示验证错误给用户。ActionForm也可以被用于为当前用户保存即将被一个视图引用的中间模型状态。
当一个表单对象被RequestProcessor找到,它被传递到请求处理器的execute(…)方法。一个ActionForm对象也可以被请求处理器建立。表单对象建立目的是提供中间模型状态给使用请求范围JSP;这将确保对象不会在有效性过期后仍然存在。默认的,所有的表单都被保存为会话范围。会话中表单对象脱离有效性的存在可能导致浪费内存,同样的,请求处理器必须跟踪保存在会话中的表单对象的生命周期。一个好的捕获表单数据的实践是为横跨多用户交互的相关表单用一个单独的表单bean。表单bean也可以在反馈的时候用来储存能够被自定义标签改变的中间模型状态。在视图中标签用法避免结合Java代码,因此要成一个好的任务划分,web生产组主要处理标志,而应用开发组主要处理Java代码。标签因素退出访问中间模型状态的逻辑;当访问嵌套的对象或当通过聚集列举时这个逻辑可能很复杂。
注意:在struts1.1中,ActionForm的校验功能,逐渐被剥离出来(当然依然可以使用)。使用了validator framework对整个应用系统的表单数据验证进行统一管理。相信信息请参考:http://home.earthlink.net/~dwinterfeldt
在ActionForm的使用中,Struts提倡使用到值对象(Value Object)。这样将客户或开发人员,对数据状态与对象状态能够更加清晰的理解和使用。
对于每一个客户请求,Struts framework在处理ActionForm的时候,一般需要经历如下几个步骤:
(1)检查Action的映射,确定Action中已经配置了对ActionForm的映射
(2)根据name属性,查找form bean的配置信息
(3)检查Action的formbean的使用范围,确定在此范围下,是否已经有此form bean的实例。
(4)假如当前范围下,已经存在了此form bean的实例,而是对当前请求来说,是同一种类型的话,那么就重用。
(5)否则,就重新构建一个form bean的实例
(6)form bean的reset()方法备调用
(7)调用对应的setter方法,对状态属性赋值
(8)如果validatede的属性北设置为true,那么就调用form bean的validate()方法。
(9)如果validate()方法没有返回任何错误,控制器将ActionForm作为参数,传给Action实例的execute()方法并执行。
注意:直接从ActionFrom类继承的reset()和validate()方法,并不能实现什么处理功能,所以有必要自己重新覆盖。
Struts的其他组件
Struts framework本身提供了很多可扩展的组件或sub framework,方便的开发人员在其构架上构建web层的应用系统。比如upload,collections ,logging等等。让我们来看看两个比较重要的组件:validationg framework和struts taglib。有关其他组件请参考Struts用户手册(http://jakarta.apache.org/struts/userGuide)。
在struts1.1中,新增了validation framework。增加了对form数据提交的验证。将原本需要在ActionFrom Bean的validate()进行的验证通过配置文件的描述进行验证。
有关其详细信息,请参考http://home.earthlink.net/~dwinterfeldt 。个人建议对于小型应用系统可以采用这种配置方式,但是对于应用系统中有大量web层表单应用的系统,并且业务需求变动比较大的,使用validation framework 可能会加重开发难度、系统维护难度。可以借鉴validation framework的Javascript Validator Tag。
struts提供了一组可扩展的自定义标签库(TagLib),可以简化创建用户界面的过程。目前包括:Bean Tags,HTML Tags,Logic Tags,Nested Tags,Template Tags 这几个Taglib。有关Struts Taglib的结构和使用,可以参考前面有关Cutomer Tag Lib的介绍,有关起详细资料,请参考
这个组件的全称是Bean Introspection Utilites。是属于Jakarta Commons项目组的。主要是帮助构建javabean的属性操作的(getter,setter),已经提供一种动态定义和访问bean的属性。有关详细信息,请参考。
http://jakarta.apache.org/commons/beanutils.html
如果各位对这方面有很兴趣,可以参考一些有关java反射(Reflectio)方面的资料。
这个组件主要是提供了一些集合或列表对象,在原有的java collections framework的基础上进行了扩展。详细资料请参考:
http://jakarta.apache.org/commons/collections.html 以及
http://cvs.apache.org/viewcvs/~checkout~/jakarta-commons/collections/STATUS.html?rev=1.13
这个组件翻译成中文的意思是“汇编”。其主要功能是根据xml配置文件,初始化系统的一些java类对象。Digester帮助你指定XML与java对象之间映射模型,而且允许客户话定制映射规则(rules)。详细资料请参考
http://jakarta.apache.org/commons/digester.html
Struts配置文件简介
Struts framework根据配置文件使得ServletAction,ActionMapping,Action , ActionForm这几个不同层次的组件相互交互,协调的工作。这些配置文件是在系统启动的时候,读入导内存中,供控制器使用的。
Struts framework主要包括三部分的配置描述,一个是指定有关Struts Controller及其相关的的配置描述(Initialization Parameters),一个对struts tag lib的描述,一个是struts组件(ActionMapping,Action,ActionForm)之间相互映射协调的关系
有关Struts Controller及其相关的的配置描述
因为Struts Controller的主要类ActionServlet是继承自HttpServlet,所以必须像配置一个Servlet那样在部署描述符(Web.xml)中配置ActionServlet类及其访问映射。
当您第一次创建基于Struts的Web应用程序时,将为您创建一个部署描述符,这通常就足够了。该文件包括下列条目:
l<servlet>条目定义用于Web应用程序的servlet(在本例中,这是唯一的servlet):
―<servlet-name> 和<servlet-class>指示ActionServlet (标识为“操作”)接收HTTP请求并确定如何响应。
―<init-param>表示servlet初始化参数.
-“config”指示ActionServlet的行为由指定的配置文件来指导,该配置文件通常具有以下名称:
\WEB-INF\struts-config.xml
-“debug”具有整数值,它指示将有关处理的详细信息写至控制台的程度。
-”detail”具有整数值,它指示将“映射”详细信息(如后面所述)写至控制台的程度。
―<load-on-startup>导致在启动应用程序时装入servlet。
l<servlet-mapping>元素标识这样的命名模式:当命名模式由URL进行匹配时,Web服务器就将控制权移交给ActionServlet。考虑下面各种情况:
―访问了ActionServlet,原因是“操作”(<servlet-mapping>中的<servlet-name>元素的内容)与“操作”(<servlet>中的<servlet-name>元素的内容)相匹配。
―<servlet-mapping>元素指定URL的结尾的命名模式。每个URL的开头都是应用程序上下文路径。按照惯例,ActionServlet调用对象以响应与命名模式“*do”(其中“*”是通配符)一致的URL。
l<welcome-file-list>元素指示获得初始控制权的特定于应用程序的代码;在本例中,Web服务器直接从Web Content目录中调用index.jsp。
l<error-page>元素指示显示哪个JSP来响应错误;在本例中,错误为如下所示:
―404(找不到资源)
―500(Web服务器内部发生错误)
l每个<taglib>元素都使相对URL(相对于Web.xml)与标记库描述符(相对于Web应用程序根目录)相关联。每个JSP都可以使用同一个URL来表示给定的标记库,而Web.xml确定引用了哪个文件。
有关struts tag lib的配置描述
如果你的web application打算使用Struts的taglib,那么你有必要在web.xml中对struts taglib进行配置描述。
  作为先前描述的web.xml设置的结果,Web应用程序服务器将请求的一个子集按路径发送至ActionServlet,它通常调用一系列操作和JSP。ActionServlet的响应是基于配置文件struts-config.xml的内容的。有关其DTD文档的描述,请参考http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd
一般struts-config(version1.1)包含了如下几个部分:
(1)form-bean
(2)global-forwards
(3)action-mappings
(4)data-sources
我们知道,对于这样的一个请求(例如,表示为“/login.do”),执行下列步骤:
1、寻找操作类对象(继承org. apache.struts.action.Action的类)
2、ActionServlet调用操作类对象的执行方法
操作类中的执行方法的特征符为如下所示:
public ActionForwardexecute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
l映射对象(ActionMapping),它包含指示如何响应方法的每个可能结果的规则(“映射”)
lStruts表单bean(ActionForm),它保存发送至HTML表单或接收自HTML表单的数据
l请求和响应对象(HttpServletReques/ HttpServletResponse)
3、从执行方法返回ActionForward对象,用于指导ActionServlet接着访问哪个操作类或JSP
返回的ActionForward对象中的信息取决于两个值:
l方法的结果(如在“成功”或“故障”等字符串中所述)
l映射对象,它包含从Struts配置文件中读取的信息
要弄明白某些运行时关系,要明白struts-config.xml该文件包括下面的一组条目:
l<form-beans>标记标识每个表单bean
l<action-mappings>标记包括用于指导应用程序流的信息,每个<action>子标记都使相对URL与操作类和潜在的后续操作相关。
Form-bean元素
Struts配置文件中的一个示例<form-bean>子元素为如下所示:
 <form-bean name=“registerForm”type=“strutscommon.RegisterForm”/>
每个<form-bean>子元素都包括下列属性:
name
表单bean的名称,稍后在配置文件中会用到。ActionServlet举例说明了该bean(如果需要的话)并在将对bean的引用存储在请求或会话对象中时将该名称用作键。
type
     类的全限定名称,它继承org.apache.struts.action.ActionForm该类必须在类路径中。接受“Struts贸易样本”中的注册的表单bean包括HTML注册表单中每个字段的getter 和setter方法。该bean还包括验证方法,如下节“验证”中所述。
Action元素
Struts配置文件中的一个示例<action>元素为如下所示:
  <action path=“/register”
type=“strutsEGL.RegisterAction”
name=“registerForm”
input=“/register.jsp”
scope=“request”
<forward name=“success”path=“/home.do”/>
< forward name=“failure”path=“/register.jsp”/>
</action>
每个<action>元素都包括下列属性中的某些属性或所有属性:
path
将请求指定为非限定URL,不带文件扩展名(例如,“/register”)请求是根据<action>元素中的其它属性来处理的,并且是用户输入的结果或者是在different<action>元素中标识的转发的结果。
type
指定在发出请求时调用其执行方法的操作类的全限定名。该类必须在类路径中。
   注:不指定要实例化的类,可以通过使用forward属性来转发请求,该属性在“Struts贸易样本”中未使用,并且与后面描述的<forward>子元素不相同。
name
用于保存发送至HTML表单或接收自HTML表单的数据表单bean的名称。
  input
指定相对URL(例如,“/register.do”或“/index.jsp”)必须包括后缀,
如果表单bean的验证方法指示发生了输入错误,则会调用URL;有关详细信息,参见下节的“验证”。
  scope
指定将对表单 bean的引用存储在哪个作用域中。其值为“会话”(缺省值)或“请求”。
    Struts配置文件中的每个<action>元素还包括子元素<forward>,它指定从方法结果至后续调用的映射。每个<forward>子元素都包括下列属性
  name
指定导致在运行时使用当前映射的字符串(例如,“success”),但是
只限于以下情况:在 type 中引用的操作类的执行方法使用完全相同
的字符串来配置返回至ActionServlet的 ActionForward对象。下面
的执行方法不是很重要,但是会导致使用“success”映射:
public ActionForward exectue(
ActionMapping mapping,
ActoinForm form,
HttpServletRequest request,
HttpServletResponse response)
Throws IOException,ServletException
ActionForward forward=new ActionForward();
Forward=mapping,findForward(“success”);
return(forward);
path
指定非限定URL(例如,“/home.do” 或“/index.jsp”)必须包括文件扩展名,仅当使用当前映射时才会调用该URL,转发操作类是根据different<action>元素中的属性来处理的,尤其是,在其path属性标识相同URL的<action>元素中。
有必要提一下的是,在struts1.1中,提出了对Multiple Application Support。在struts的早先版本中,只有一个struts配置文件,一般叫struts-config.xml。但是,对于越来越复杂的应用系统的发展,只有一个地方存放这个一个文件,对大型项目来说,使用和修改这个配置文件,使其成为了一个应用的瓶颈问题。在struts1.1中,你可以定义多了配置文件协同工作。
注:当用户或ActionServlet调用JSP时,请求是由Web应用程序服务器直接处理的不会受到ActionServlet的干预。
Struts高级特性(Struts Advanced Feature)
  仅当在下列情况下才会在表单bean中对用户输入进行验证:
l表单bean覆盖超类的验证方法
lStruts配置文件中的<action>元素的验证属性显式地或者缺省设置为TRUE。表单bean没有关于应用程序的业务逻辑的信息;因此该bean提供的验证仅限于一些相对简单的问题,例如,用户是否在每个必填字段中都输入了数据?
Struts框架的各种部件使得可以进行验证
lStruts配置文件中的以下<action>子元素将导致使用表单bean registerForm:
<action path=“/register”
type=“strutsEGL.RegisterAction”
name=“registerForm”
input=“/register.jsp”
scope=“request”
<forward name=“success” path=“/home.do”/>
<forward name=“failure”path=“/register.jsp”/>
</action>
如果缺少验证属性,则意味着当ActionServlet接收到来自HTML表单对“/register”的请求时,ActionServlet将在接收用户数据的表单bean中调用验证方法。此验证在ActionServlet访问操作类之前进行。如果丢失了该方法,不会发生任何错误,在该情况下,验证总是会成功。
l如果发生了错误,则表单bean的验证方法将举例说明错误类并将错误条目添加至该类。registerForm的验证方法的一个子集为如下所示:
ActionErrors errors=new ActionErrors();
If (username= =unll║username.equals(“”))
{
errors.add(“register”,
new ActionError(“error. Register.username”));
}
if (openingBalance<0.01)
{
errors.add(“register”,
new ActionError(“error. register. balance”));
}
return errors;
errors.add方法包括两个参数:
property
用来标识错误类别的Java字符串。
  如果想要在特定的输入字段或输入字段的子集发生错误时
标识该错误,则指定属性值。例如,指定诸如“username”
之类的值的优点在于:报告了错误的JSP中,可以在屏幕上
靠近发生错误的字段的位置显示有关特定HTML字段的错
误消息,但是,要指示所有错误都属于同一类别,可以对属
性参数指定以下常量:
  ActionErrors.GLOBAL_ERROR
error
包含从属性文件派生的“键-字符串”对的键的ActionError 对象。当配置ActionError对象时,最多可以包括要代入字符串中用来替代{0}、{1}等的四个值。
l如果从验证方法返回了错误,则ActionServlet指导对在<action>元素的输入属性中指定的对象或JSP进行处理;在本例中,将处理register.jsp.
lJSP register.jsp.包括用于显示从验证方法派生的任何错误消息的以下
标记:
<html:errors/>
如果在未发生输入错误的情况下调用JSP,则该标记不显示任何内容,
而在JSP中将继续进行处理。但是,如果因发生验证故障而调用了JSP,
则为用户显示的内容将受到属性文件中是否包括下列键的影响:
― errors.header,它导致在所有错误消息前面显示一个字符串;或者
― errors.footer,它导致在所有错误消息后面显示一个字符串;或者
― errors.hiader,和errors.footer两者
例如,在ApplicationResources.properties 中,errors.header和 errors.footer的“键-字符串”对以及先前显示的这两个消息键为如下所示,它们各自都在单独的一行上(但是分成了多行显示以便于您复查):
errors.header=
<p class=“errors”>
The Action failed because of the following reason(s):
<ul class=“errors”>
error.register.username=<li>you must enter a User ID.
error.register.balance=
<li>Your account must start with a positive balance.
Errors.footer=</ul></p>
如果在注册时用户对用户名输入了空白,对余额输入零,则用户将接收到一个包括两个错误的列表的屏幕:
The Action failed because of the following reason(s):
o You must enter a User ID.
o Your account must start with a positive balance.
可以为标记<html:errors/>指定属性以支持国际化或者只显示有关指定了给定属性值的错误的信息。通过使用相异属性值,可以在相邻的不同字段中显示每条错误消息而不是将所有错误置于单个列表中。
  要定义应用程序的逻辑流程,成熟的经验是推荐在代码之外,用配置的方法来实现,而不是写死在程序代码中的。在J2EE中,这样的例子比比皆是。从实现EJB的安全性和事务性行为到描述JMS消息和目的地之间的关系,很多运行时的处理流程都是可以在程序之外定义的。
  Struts 创建者从一开始就采用这种方法,通过配置Struts的配置文件来定制应用系统运行时的各个方面。这一点在版本1.1的新特性上得到延续,包括新的异常处理功能。在Struts framework以前的版本中,开发人员不得不自己处理Struts应用中发生的错误情况。在最新的版本中,情况大大的改观了,Struts Framework提供了内置的一个称为 ExceptionHandler 的类,用于系统缺省处理action类运行中产生的错误。这也是在上一个技巧中我们提到的framework许多可扩展接口之一。
  Struts缺省的 ExceptionHandler类会生成一个ActionError对象并保存在适当的范围(scope)对象中。这样就允许JSP页面使用错误类来提醒用户出现什么问题。如果你认为这不能满足你的需求,那么可以很方便的实现你自己的ExcepionHandler类。
具体定制异常处理的方法和机制
  要定制自己的异常处理机制,第一步是继承org.apache.struts.action.ExceptionHandler类。这个类有2个方法可以覆盖,一个是excute()另外一个是storeException(). 在多数情况下,只需要覆盖其中的excute()方法。下面是ExceptionHandler类的excute()方法声明:
Struts教程
  正如你看到的,该方法有好几个参数,其中包括原始的异常。方法返回一个ActionForward对象,用于异常处理结束后将controller类带到请求必须转发的地方去。
  当然您可以实现任何处理,但一般而言,我们必须检查抛出的异常,并针对该类型的异常进行特定的处理。缺省的,系统的异常处理功能是创建一个出错信息,同时把请求转发到配置文件中指定的地方去。定制异常处理的一个常见的例子是处理嵌套异常。假设该异常包含有嵌套异常,这些嵌套异常又包含了其他异常,因此我们必须覆盖原来的execute()方法,对每个异常编写出错信息。
  一旦你创建了自己的ExceptionHandler 类,就应该在Struts配置文件中的部分声明这个类,以便让Struts知道改用你自定义的异常处理取代缺省的异常处理.
  可以配置你自己的ExceptionHandler 类是用于Action Mapping特定的部分还是所有的Action对象。如果是用于Action Mapping特定的部分就在元素中配置。如果想让这个类可用于所有的Action对象,可以在 元素中指定。例如,假设我们创建了异常处理类CustomizedExceptionHandler用于所有的Action类, 元素定义如下所示:
Struts教程
  在元素中可以对很多属性进行设置。在本文中,最重要的属性莫过于handler属性, handler属性的值就是自定义的继承了ExceptionHandler类的子类的全名。假如该属性没有定义,Struts会采用自己的缺省值。当然,其他的属性也很重要,但如果想覆盖缺省的异常处理的话,handler无疑是最重要的属性。
  最后必须指出的一点是,你可以有不同的异常处理类来处理不同的异常。在上面的例子中,CustomizedExceptionHandler用来处理任何java.lang.Exception的子类. 其实,你也可以定义多个异常处理类,每一个专门处理不同的异常树。下面的XML片断解释了如何配置以实现这一点。
Struts教程
  在这里,一旦有异常抛出,struts framework将试图在配置文件中找到ExceptionHandler,如果没有找到,那么struts将沿着该异常的父类链一层层往上找直到发现匹配的为止。因此,我们可以定义一个层次型的异常处理关系结构,在配置文件中已经体现了这一点。
使用应用模块(Application Modules)
  Struts 1.1的一个新特性是应用模块的概念。应用模块允许将单个Struts应用划分成几个模块,每个模块有自己的Struts配置文件,JSP页面,Action等等。这个新特性是为了解决大中型的开发队伍抱怨最多的一个问题,即为了更好的支持并行开发允许多个配置文件而不是单个配置文件。
  显然,当很多开发人员一起参加一个项目时,单个的Struts配置文件很容易引起资源冲突。应用模块允许Struts按照功能要求进行划分,许多情况已经证明这样更贴近实际。例如,假设我们要开发一个典型的商店应用程序。可以将组成部分划分成模块比如catalog(商品目录), customer(顾客), customer service(顾客服务), order(订单)等。每个模块可以分布到不同的目录下,这样各部分的资源很容易定位,有助于开发和部署。图1 显示了该应用的目录结构。
Struts教程
一个典型的商店应用程序的目录结构
  注:如果你无需将项目划分成多个模块,Struts框架支持一个缺省的应用模块。这就使得应用程序也可以在1.0版本下创建,具有可移植性,因为应用程序会自动作为缺省的应用模块。
  为了使用多应用模块功能,必须执行以下几个准备步骤:
  · 为每个应用模块创建独立的Struts配置文件。
  · 配置Web 部署描述符 Web.xml文件。
  · 使用org.apache.struts.actions.SwitchAction 来实现程序在模块之间的跳转.
  创建独立的Struts配置文件
  每个Struts应用模块必须拥有自己的配置文件。允许创建自己的独立于其他模块的Action,ActionForm,异常处理甚至更多。
  继续以上面的商店应用程序为例,我们可以创建以下的配置文件:一个文件名为struts-config-catalog.xml,包含catalog(商品目录)、items(商品清单)、和其它与库存相关的功能的配置信息;另一个文件名为struts- config-order.xml, 包含对order(订单)和order tracking(订单跟踪)的设置。第三个配置文件是struts-config.xml,其中含有属于缺省的应用模块中的一般性的功能。
  在为每个应用模块创建独立的配置文件之后,我们就有可能需要调用不同的模块中Action。为此必须使用Struts框架提供的SwitchAction类。Struts 会自动将应用模块的名字添加到URL,就如Struts 自动添加应用程序的名字加到URL一样。应用模块是对框架的一个新的扩充,有助于进行并行的团队开发。如果你的团队很小那就没必要用到这个特性,不必进行模块化。当然,就算是只有一个模块,系统还是一样的运作。
JSP放到WEB-INF后以保护JSP源代码
  为了更好地保护你的JSP避免未经授权的访问和窥视, 一个好办法是将页面文件存放在Web应用的WEB-INF目录下。
  通常JSP开发人员会把他们的页面文件存放在Web应用相应的子目录下。一个典型的商店应用程序的目录结构如图2所示。跟catalog (商品目录)相关的JSP被保存在catalog子目录下。跟customer相关的JSP,跟订单相关的JSP等都按照这种方法存放。
Struts教程
基于不同的功能JSP 被放置在不同的目录下
  这种方法的问题是这些页面文件容易被偷看到源代码,或被直接调用。某些场合下这可能不是个大问题,可是在特定情形中却可能构成安全隐患。用户可以绕过Struts的controller直接调用JSP同样也是个问题。
为了减少风险,可以把这些页面文件移到WEB-INF 目录下。基于Servlet的声明,WEB-INF不作为Web应用的公共文档树的一部分。因此,WEB-INF 目录下的资源不是为客户直接服务的。我们仍然可以使用WEB-INF目录下的JSP页面来提供视图给客户,客户却不能直接请求访问JSP。
  采用前面的例子,图3显示将JSP页面移到WEB-INF 目录下后的目录结构
Struts教程
JSP存放在WEB-INF 目录下更为安全
  如果把这些JSP页面文件移到WEB-INF 目录下,在调用页面的时候就必须把"WEB-INF"添加到URL中。例如,在一个Struts配置文件中为一个logoff action写一个Action mapping。其中JSP的路径必须以"WEB-INF"开头。如下所示:请注意粗体部分.
  这个方法在任何情况下都不失为Struts实践中的一个好方法。是唯一要注意的技巧是你必须把JSP和一个Struts action联系起来。即使该Action只是一个很基本的很简单JSP,也总是要调用一个Action,再由它调用JSP。
  最后要说明的是,并不是所有的容器都能支持这个特性。WebLogic早期的版本不能解释Servlet声明,因此无法提供支持,据报道在新版本中已经改进了。总之使用之前先检查一下你的Servlet容器。
使用Prebuilt Action类提升开发效率
  Struts framework带有好几个prebuilt Action类,使用它们可以大大节省开发时间。其中最有用的是org.apache.struts.actions.ForwardAction 和 org.apache.struts.actions.DispatchAction.
使用 ForwardAction
  在应用程序中,可能会经常出现只要将Action对象转发到某个JSP的情况。在上一点中曾提到总是由Action调用JSP是个好习惯。如果我们不必在Action中执行任何业务逻辑,却又想遵循从Action访问页面的话,就可以使用ForwardAction,它可以使你免去创建许多空的Action类。运用ForwardAction的好处是不必创建自己的Action类,你需要做的仅仅是在Struts配置文件中配置一个Action mapping。
  举个例子,假定你有一个JSP文件index.jsp ,而且不能直接调用该页面,必须让程序通过一个Action类调用,那么,你可以建立以下的Action mapping来实现这一点:
Struts教程
  正如你看到的,当/home 被调用时, 就会调用ForwardAction 并把请求转发到 index.jsp 页面.
再讨论一下不通过一个Action类直接转发到某个页面的情况,必须注意我们仍然使用元素中的forward属性来实现转发的目标。这时元素定义如下:
Struts教程
  以上两种方法都可以节省你的时间,并有助于减少一个应用所需的文件数。
使用 DispatchAction
  DispatchAction是Struts包含的另一个能大量节省开发时间的Action类。与其它Action类仅提供单个execute()方法实现单个业务不同,DispatchAction允许你在单个Action类中编写多个与业务相关的方法。这样可以减少Action类的数量,并且把相关的业务方法集合在一起使得维护起来更容易。
  要使用DispatchAction的功能,需要自己创建一个类,通过继承抽象的DispatchAction得到。对每个要提供的业务方法必须有特定的方法signature。例如,我们想要提供一个方法来实现对购物车添加商品清单,创建了一个类ShoppingCartDispatchAction提供以下的方法:
Struts教程
  那么,这个类很可能还需要一个deleteItem()方法从客户的购物车中删除商品清单,还有clearCart()方法清除购物车等等。这时我们就可以把这些方法集合在单个Action类,不用为每个方法都提供一个Action类。
  在调用ShoppingCartDispatchAction里的某个方法时,只需在URL中提供方法名作为参数值。就是说,调用addItem()方法的 URL看起来可能类似于:
  http://myhost/storefront/action/cart?method=addItem
  其中method参数指定ShoppingCartDispatchAction中要调用的方法。参数的名称可以任意配置,这里使用的"method"只是一个例子。参数的名称可以在Struts配置文件中自行设定。
Struts标记库
定制JSP标记
Struts提供了用来封装逻辑的各种定制JSP标记,因此页面设计者可以将主要精力花在页面的可视特征上,而不必主要考虑Java语法或其它JSP语法,在下列标识库描述符中引用了Struts标记:
Struts-bean.tld
使访问bean以及新bean的定义更容易,,为了实现国际化,应使用不同的属性文件
struts-html.tld
提供显示HTML对象(例如,表单、按钮和复选框)的简便方法
struts-logic.tld
支持逻辑构造,以便可以有条件地显示文本或者作为处理循环的结果来显示文本
  struts-template.tld
支持使用在运行时可以修改的JSP模板
  要在JSP文件顶部的<taglib>伪指令如下所示:
<%@ taglib uri=“struts-bean.tld”prefix=“bean”%>
<%@ taglib uri=“struts-logic.tld”prefix=“logic”%>
每个<taglib>伪指令都具有与基于 web.xml的< taglib>标记中的URL相匹配的URL。另外JSP中的每个 struts标记都使用一个使标记与特定标记库描述符相关的前缀:
― 没有嵌套内容的标记可以采用以下格式:
<prefix:tagName attributesAndValues/>
―嵌套内容是在一对标记之间嵌套的:
       <prefix:tagName attributesAndValues />
</prefix:tagName>
prefix
在JSPtaglib伪指令中指定的前缀
      tagName
标记的名称,如标记库描述符中所述;描述符条目指定提供标记逻辑的Jave类
attributesAndValues
―系列属性与值的配对(是必需的或者是可选的),每个配对都包括一种属性、一个等号(没有前导或结尾空白)和一个引起来的字符串
文件resource.jsp包含bean:message标记的几个实例。以下是标记的示例用法:
<bean:message key=“market. text. title”/>
在最简单的情况下,bean:message标记解析为存储在根据属性文件创建的资源束中的字符串:
― 属性文件的名称是用来调用ActoinServlet的web.xml “application”参数的值。如:
\WEB-INF\classes\ApplicationResources.properties
― 消息标记中的key属性指向属性文件中的“键-字符串”对;在本例中,指向下面的“键-字符串”对:
 market. text.title=Current Market Conditions
可以采用各种方法来定制bean:message标记,以便(例如)JSP在运行时引用不同的属性文件。标记提供了一种方法来支持多种语言以及最多将四个替代值插入到字符串中来代替{0}、{1}等等。
l仅当指定的对象或值存在时,logic:present 标记才会导致显示嵌套的文本。在register.jsp中,仅当操作类创建了作为 tickerBean引用(在任何作用域中)的 Java bean 时才为用户提供HTML表行。 Struts标记为如下所示:
    <logic:present name=“tickerBean”>
-->nested content for presentation<--
</logic:present>
lStruts标记允许很方便地访问Java bean内容。例如,以下标记将解析为存储在 tickerBean中的值:
   <bean:write name= “tickerBean”property=“DJChange”/>
tickerBean的源代码在以下目录中:
Trade\Java Source\tradeCommon\tickerBean