Struts教程
目錄
Struts ActionServlet控制器對(duì)象... 8
Struts ActionForm Bean捕獲表單數(shù)據(jù)... 11
Validation Framework for Struts. 12
有關(guān)Struts Controller及其相關(guān)的的配置描述... 13
有關(guān)struts tag lib的配置描述... 14
有關(guān)Struts Action Mapping的配置描述... 14
Struts高級(jí)特性(Struts Advanced Feature)... 17
使用應(yīng)用模塊(Application Modules)... 21
把JSP放到WEB-INF后以保護(hù)JSP源代碼... 22
使用 Prebuilt Action類提升開發(fā)效率... 23
轉(zhuǎn)發(fā)和重定向標(biāo)記... 33
第一個(gè)實(shí)驗(yàn):簡(jiǎn)單的JSP頁(yè)... 41
第二個(gè)實(shí)驗(yàn):struts的國(guó)際化... 42
分離Book和BookForm的一個(gè)好方法... 51
概述
本文主要講解什么是Struts Framework,它的框架結(jié)構(gòu),組件結(jié)構(gòu),以及簡(jiǎn)單的配置講解。
文章的包括了如下七大部分:
Framework的概念和體系簡(jiǎn)介
Struts的概念和體系結(jié)構(gòu)
Struts的工作原理和組件
Struts配置文件簡(jiǎn)介
Struts高級(jí)特性
Struts標(biāo)記庫(kù)
一個(gè)簡(jiǎn)單的示例
Framework概念
一直以來我們都說Struts是一個(gè)Web Framework。那么讓我么先來看看什么是Framework。
Framework概念并不是很新了,伴隨著軟件開發(fā)的發(fā)展,在多層的軟件開發(fā)項(xiàng)目中,可重用、易擴(kuò)展的,而且是經(jīng)過良好測(cè)試的軟件組件,越來越為人們所青睞。這意味著人們可以將充裕的時(shí)間用來分析、構(gòu)建業(yè)務(wù)邏輯的應(yīng)用上,而非繁雜的代碼工程。于是人們將相同類型問題的解決途徑進(jìn)行抽象,抽取成一個(gè)應(yīng)用框架。這也就是我們所說的Framework。
Framework的體系提供了一套明確機(jī)制,從而讓開發(fā)人員很容易的擴(kuò)展和控制整個(gè)Framework開發(fā)上的結(jié)構(gòu)。 通常,Framework的結(jié)構(gòu)中都有一個(gè)“命令和控制”組件("command and control" component)——Framework Factory and Manager。
Framework體系
通過基于請(qǐng)求響應(yīng)(Request-Response)模式的應(yīng)用Framework,基本上有如下幾個(gè)表現(xiàn)邏輯結(jié)構(gòu)組成。
控制器(Controller)——控制整個(gè)Framework中各個(gè)組件的協(xié)調(diào)工作。
業(yè)務(wù)邏輯層(Business Logic)——對(duì)Framwork本身來說,這里僅僅只是概念和幾個(gè)提夠服務(wù)的基礎(chǔ)組件,真正的實(shí)現(xiàn)與客戶的業(yè)務(wù)邏輯接軌,還需要開發(fā)人員在Framework上再次擴(kuò)展。
數(shù)據(jù)邏輯層(Data Logic)——絕大應(yīng)用系統(tǒng)都需要涉及到數(shù)據(jù)交互,這一層次主要包括了數(shù)據(jù)邏輯和數(shù)據(jù)訪問接口。對(duì)于數(shù)據(jù)邏輯來說,如果你了解數(shù)據(jù)建模(Data Modeling)可能就很容易理解。
Struts的概念和體系結(jié)構(gòu)
Struts有一組相互協(xié)作的類、Serlvet以及Jsp TagLib組成。基于Struts構(gòu)架的web應(yīng)用程序基本上符合JSP Model2的設(shè)計(jì)標(biāo)準(zhǔn),可以說是MVC設(shè)計(jì)模式的一種變化類型。根據(jù)上面對(duì)framework的描述,我們很容易理解為什么說Struts是一個(gè)web framwork,而不僅僅是一些標(biāo)記庫(kù)的組合。但 Struts 也包含了豐富的標(biāo)記庫(kù)和獨(dú)立于該框架工作的實(shí)用程序類。
Struts有其自己的控制器(Controller),同時(shí)整合了其他的一些技術(shù)去實(shí)現(xiàn)模型層(Model)和視圖層(View)。在模型層,Struts可以很容易的與數(shù)據(jù)訪問技術(shù)相結(jié)合,包括EJB,JDBC和Object Relation Bridge。在視圖層,Struts能夠與JSP, Velocity Templates,XSL等等這些表示層組件想結(jié)合。
Struts的與Web App的關(guān)系
既然struts叫做web framework,那么其肯定主要基于web層的應(yīng)用系統(tǒng)開發(fā)。按照J2EE Architecture的標(biāo)準(zhǔn),struts應(yīng)當(dāng)和jsp/servlet一樣,存在于web container一層。
Struts與WebApp的關(guān)系
Struts的體系結(jié)構(gòu)
我們說struts framework是MVC 模式的體現(xiàn),下面我們就從分別從模型、視圖、控制來看看struts的體系結(jié)構(gòu)(Architecture)。下圖顯示了struts framework的體系結(jié)構(gòu)響應(yīng)客戶請(qǐng)求時(shí)候,各個(gè)部分工作的原理。
Struts體系結(jié)構(gòu)
從視圖角度(View)
首先,Struts提供了Java類org. apache.struts.action.ActionForm,Java開發(fā)者將該類細(xì)分來創(chuàng)建表單bean。在運(yùn)行時(shí),該bean有兩種用法:
― 當(dāng)JSP準(zhǔn)備相關(guān)的HTML,表單以進(jìn)行顯示時(shí),JSP將訪問該
bean(它保存要放入表單中的值)。那些值是從業(yè)務(wù)邏輯或者是從先前的用戶輸入來提供的。
― 當(dāng)從Web瀏覽器中返回用戶輸入時(shí),該bean將驗(yàn)證并保存該輸入以供業(yè)務(wù)邏輯或(如果驗(yàn)證失敗的話)后續(xù)重新顯示使用。
其次,Struts提供了許多定制JSP標(biāo)記,它們的使用簡(jiǎn)單,但是它們?cè)陔[藏信息方面功能強(qiáng)大。例如,除了bean名稱和給定bean中每個(gè)段的名稱之外,頁(yè)面設(shè)計(jì)者不需要知道有關(guān)表單bean的更多信息。
從模型角度(Model)
Struts雖然不直接有助于模型開發(fā)。在Struts中,系統(tǒng)模型的狀態(tài)主要由ActiomForm Bean和值對(duì)象體現(xiàn)。
從控制器角度(Controller)
在Struts framework中, Controller主要是ActionServlet,但是對(duì)于業(yè)務(wù)邏輯的操作則主要由Action、ActionMapping、ActionForward這幾個(gè)組件協(xié)調(diào)完成(也許這幾個(gè)組件,應(yīng)該劃分到模型中的業(yè)務(wù)邏輯一塊)。其中,Action扮演了真正的控制邏輯的實(shí)現(xiàn)者,而ActionMapping和ActionForward則指定了不同業(yè)務(wù)邏輯或流程的運(yùn)行方向。
Struts的基本組件包
整個(gè)struts大約有15包,近200個(gè)類所組成,而且數(shù)量還在不斷的擴(kuò)展。在此我們不能一一介紹,只能列舉幾個(gè)主要的簡(jiǎn)要的介紹一下。下表說明了目前struts api中基本的幾個(gè)組件包,包括action,actions,config,util,taglib,validator。下圖則顯現(xiàn)了這幾個(gè)組件包之間的關(guān)系。其中action是整個(gè)struts framework的核心
org.apache.struts.action |
基本上,控制整個(gè)struts framework的運(yùn)行的核心類、組件都在這個(gè)包中,比如我們上面提到的控制器ActionServlet。已經(jīng)Action,ActionForm,ActionMapping等等。struts1.1比1.0多了 DynaActionForm 類。增加了動(dòng)態(tài)擴(kuò)展生成FormBean功能 |
org.apache.struts.actions |
這個(gè)包是主要作用是提供客戶的http請(qǐng)求和業(yè)務(wù)邏輯處理之間的特定適配器轉(zhuǎn)換功能,而1.0版本中的部分動(dòng)態(tài)增刪FromBean的類,也在struts1.1中被Action包的DynaActionForm組件所取代 |
org.apache.struts.config |
提供對(duì)配置文件struts-config.xml元素的映射。這也是sturts1.1中新增的功能 |
org.apache.struts.util |
Strtuts為了更好支持web application的應(yīng)用,體統(tǒng)了一個(gè)些常用服務(wù)的支持,比如Connection Pool和Message Source。詳細(xì)信息請(qǐng)參考 http://jakarta.apache.org/struts/api/org/apache/struts/util/package-summary.html |
org.apache.struts.taglib |
這不是一個(gè)包,而是是一個(gè)客戶標(biāo)簽類的集合。下面包括Bean Tags,HTML Tags,Logic Tags,Nested Tags,Template Tags這幾個(gè)用于構(gòu)建用戶界面的標(biāo)簽類。 |
org.apache.struts.validator |
Struts1.1 framework中增加了validator framework,用于動(dòng)態(tài)的配置from表單的驗(yàn)證。詳細(xì)信息請(qǐng)參閱 http://home.earthlink.net/~dwinterfeldt/ |
Struts framework的工作原理和組件
對(duì)于Struts 如何控制、處理客戶請(qǐng)求,讓我們通過對(duì)struts的四個(gè)核心組件介紹來具體說明。這幾個(gè)組件就是:ActionServlet。Action Classes,Action Mapping(此處包括ActionForward),ActionFrom Bean。
Struts ActionServlet控制器對(duì)象
ActionServlet繼承自javax.servlet.http.HttpServlet類,其在Struts framework中扮演的角色是中心控制器。它提供一個(gè)中心位置來處理全部的終端請(qǐng)求。控制器ActionServlet主要負(fù)責(zé)將HTTP的客戶請(qǐng)求信息組裝后,根據(jù)配置文件的指定描述,轉(zhuǎn)發(fā)到適當(dāng)?shù)奶幚砥鳌?/span>
按照Servelt的標(biāo)準(zhǔn),所有得Servlet必須在web配置文件(web.xml)聲明。同樣,ActoinServlet必須在Web Application配置文件(web.xml)中描述,有關(guān)配置信息如下。
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
</servlet>
全部的請(qǐng)求URI以*.do的模式存在并映射到這個(gè)servlet,其配置如下:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
一個(gè)該模式的請(qǐng)求URI符合如下格式:
http://www.my_site_name.com/mycontext/actionName.do
中心控制器為所有的表示層請(qǐng)求提供了一個(gè)集中的訪問點(diǎn)。這個(gè)控制器提供的抽象概念減輕了開發(fā)者建立公共應(yīng)用系統(tǒng)服務(wù)的困難,如管理視圖、會(huì)話及表單數(shù)據(jù)。它也提供一個(gè)通用機(jī)制如錯(cuò)誤及異常處理,導(dǎo)航,國(guó)際化,數(shù)據(jù)驗(yàn)證,數(shù)據(jù)轉(zhuǎn)換等。
當(dāng)用戶向服務(wù)器端提交請(qǐng)求的時(shí)候,實(shí)際上信息是首先發(fā)送到控制器ActionServlet,一旦控制器獲得了請(qǐng)求,其就會(huì)將請(qǐng)求信息傳交給一些輔助類(help classes)處理。這些輔助類知道如何去處理與請(qǐng)求信息所對(duì)應(yīng)的業(yè)務(wù)操作。在Struts中,這個(gè)輔助類就是org.apache.struts.action.Action。通常開發(fā)者需要自己繼承Aciton類,從而實(shí)現(xiàn)自己的Action實(shí)例。
Struts Action Classes
ActionServlet把全部提交的請(qǐng)求都被控制器委托到RequestProcessor對(duì)象。RequestProcessor使用struts-config.xml文件檢查請(qǐng)求URI找到動(dòng)作Action標(biāo)示符。
一個(gè)Action 類的角色,就像客戶請(qǐng)求動(dòng)作和業(yè)務(wù)邏輯處理之間的一個(gè)適配器(Adaptor),其功能就是將請(qǐng)求與業(yè)務(wù)邏輯分開。這樣的分離,使得客戶請(qǐng)求和Action類之間可以有多個(gè)點(diǎn)對(duì)點(diǎn)的映射。而且Action類通常還提供了其它的輔助功能,比如:認(rèn)證(authorization)、日志(logging)和數(shù)據(jù)驗(yàn)證(validation)。
public ActionForward execute(ActionMapping mapping,
ActionForm form,
javax.servlet.ServletRequest request,
javax.servlet.ServletResponse response)
throws java.io.IOException,javax.servlet.ServletException
|
Action最為常用的是execute()方法。(注意,以前的perform方法在struts1.1中已經(jīng)不再支持),還有一個(gè)execute()方法,請(qǐng)參考apidoc,在此不在說明。
當(dāng)Controller收到客戶的請(qǐng)求的時(shí)候,在將請(qǐng)求轉(zhuǎn)移到一個(gè)Action實(shí)例時(shí),如果這個(gè)實(shí)例不存在,控制器會(huì)首先創(chuàng)建,然后會(huì)調(diào)用這個(gè)Action實(shí)例的execute()方法。Struts Framework為應(yīng)用系統(tǒng)中的每一個(gè)Action類只創(chuàng)建一個(gè)實(shí)例。因?yàn)樗械挠脩舳际褂眠@一個(gè)實(shí)例,所以你必須確定你的Action 類運(yùn)行在一個(gè)多線程的環(huán)境中。下圖顯示了一個(gè)execute()方法如何被訪問:
Action實(shí)例的execute()方法
注意,客戶自己繼承的Action子類,必須重寫execute()方法,因?yàn)?span>Action類在默認(rèn)情況下是返回null的。
Struts Action Mapping
上面講到了一個(gè)客戶請(qǐng)求是如何被控制器轉(zhuǎn)發(fā)和處理的,但是,控制器如何知道什么樣的信息轉(zhuǎn)發(fā)到什么樣的Action類呢?這就需要一些與動(dòng)作和請(qǐng)求信息相對(duì)應(yīng)的映射配置說明。在struts 中,這些配置映射信息是存儲(chǔ)在特定的XML文件(比如struts-config.xml)。
這些配置信息在系統(tǒng)啟動(dòng)的時(shí)候被讀入內(nèi)存,供struts framework在運(yùn)行期間使用。在內(nèi)存中,每一個(gè)<action>元素都與org.apache.struts.action.ActionMapping類的一個(gè)實(shí)例對(duì)應(yīng)。下表就顯示了一個(gè)登陸的配置映射。
<action-mappings> <action path="/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> |
上面的配置表示:當(dāng)可以通過/logonAction.do(此處假設(shè)配置的控制器映射為*.do)提交請(qǐng)求信息的時(shí)候,控制器將信息委托com.test.LogonAction處理。調(diào)用LogonAction實(shí)例的execute()方法。同時(shí)將Mapping實(shí)例和所對(duì)應(yīng)的LogonForm Bean信息傳入。其中name=LogonForm,使用的form-bean元素所聲明的ActionForm Bean。有關(guān)form-bean的申明如下顯示。
使用ActionForward導(dǎo)航
元素<forward>則表示了當(dāng)Action實(shí)例的execute()方法運(yùn)行完畢或,控制器根據(jù)Mapping可將響應(yīng)信息轉(zhuǎn)到適當(dāng)?shù)牡胤健H缟厦娆F(xiàn)實(shí),如果客戶登陸成功,則調(diào)用welcome forward,將成功信息返回到/welcome.jsp頁(yè)面。在你的execute()方法的結(jié)尾可以使用下面的實(shí)例代碼而返回welcome forward。當(dāng)然你的welcome forward必須在action元素屬性中定義,正如上面所聲明的那樣。
return (mapping.findForward("welcome")); |
ActionForward對(duì)象是配置對(duì)象。這些配置對(duì)象擁有獨(dú)一無二的標(biāo)識(shí)以允許它們按照有意義的名稱如“success”,“failure”等來檢索。ActionForward對(duì)象封裝了向前進(jìn)的URL路徑且被請(qǐng)求處理器用于識(shí)別目標(biāo)視圖。ActionForward對(duì)象建立自<forward>元素位于struts-config.xml。下面是一個(gè)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>
基于執(zhí)行請(qǐng)求處理器的execute(…)方法的結(jié)果,當(dāng)傳遞一個(gè)值匹配指定于<forward>元素中name屬性的值的時(shí)候,下一個(gè)視圖可以在execute(…)方法中被開發(fā)者用方便的方法org.apache.struts.action.ActionMapping.findForward(…)選擇。ActionMapping.findForward(…)方法既從它的本地范圍又從全局范圍提供一個(gè)ActionForward對(duì)象,該對(duì)象返回至RequestProcessor以RequestDispatcher.forward(…)或response.sendRedirect(…)調(diào)用下一個(gè)視圖。當(dāng)<forward>元素有redirect=“false”屬性或redirect屬性不存在的時(shí)候,RequestDispatcher.forward(…)被執(zhí)行;當(dāng)redirect=“true”是,將調(diào)用sendRedirect(…)方法。下例舉例說明了redirect屬性的用法:
<forward name="success" path="/Catalog.jsp" redirect="true"/>
如果redirect=true, URL建立如/contextPath/path因?yàn)?/span>HttpServletResponse.sendRedirect(…)中解釋URL采用”/”開頭相對(duì)于servlet容器根目錄。
如果redirect=false, URI建立如/path因?yàn)?/span>ServletContext.getRequestDisptacher(…)采用虛擬目錄相關(guān)URL。
在此稍稍說一下有關(guān)global-forwards的概念。其在配置文件中描述了整個(gè)應(yīng)用系統(tǒng)可以使用的ActionForward,而不是僅僅是一個(gè)特定的Action。
<global-forwards> <forward name="logout" path="/logout.do"/> <forward name="error" path="/error.jsp"/> </global-forwards> |
Struts ActionForm Bean捕獲表單數(shù)據(jù)
在上面講解ActionServlet,Action Classes和Action Mapping的時(shí)候,我們都提到了ActionForm Bean的概念。一個(gè)應(yīng)用系統(tǒng)的消息轉(zhuǎn)移(或者說狀態(tài)轉(zhuǎn)移)的非持久性數(shù)據(jù)存儲(chǔ),是由ActionForm Bean的負(fù)責(zé)保持的。
ActionForm派生的對(duì)象用于保存請(qǐng)求對(duì)象的參數(shù),因此它們和用戶緊密聯(lián)系。
一個(gè)ActionForm類被RequestProcessor建立。這是發(fā)生在已完成向前進(jìn)到一個(gè)URL,該URL為映射到控制器servlet而不是JSP和相應(yīng)的動(dòng)作映射指定的表單屬性的。在這個(gè)情況下,如果沒有在指定的活動(dòng)范圍內(nèi)找到,RequestProcessor將嘗試尋找可能導(dǎo)致創(chuàng)建一個(gè)新ActionForm對(duì)象的表單bean。該ActionForm對(duì)象在指定的活動(dòng)范圍內(nèi)被用<action>元素的name屬性找到;
RequestProcessor將隨后重新安排表單屬性,用請(qǐng)求時(shí)參數(shù)填充表單,隨即調(diào)用表單對(duì)象的validate(…)方法以履行服務(wù)器端用戶輸入驗(yàn)證。僅當(dāng)ActionMapping對(duì)象中validate屬性被設(shè)為true時(shí),validate(…)方法被調(diào)用;這就是默認(rèn)的行為。request.getParameterValues(parameterName)被用于得到一個(gè)String[]對(duì)象,它用來表單填充;驗(yàn)證的結(jié)果應(yīng)該是一個(gè)ActionErrors對(duì)象,用org.apache.struts.taglib.html.ErrorsTag來顯示驗(yàn)證錯(cuò)誤給用戶。ActionForm也可以被用于為當(dāng)前用戶保存即將被一個(gè)視圖引用的中間模型狀態(tài)。
當(dāng)一個(gè)表單對(duì)象被RequestProcessor找到,它被傳遞到請(qǐng)求處理器的execute(…)方法。一個(gè)ActionForm對(duì)象也可以被請(qǐng)求處理器建立。表單對(duì)象建立目的是提供中間模型狀態(tài)給使用請(qǐng)求范圍JSP;這將確保對(duì)象不會(huì)在有效性過期后仍然存在。默認(rèn)的,所有的表單都被保存為會(huì)話范圍。會(huì)話中表單對(duì)象脫離有效性的存在可能導(dǎo)致浪費(fèi)內(nèi)存,同樣的,請(qǐng)求處理器必須跟蹤保存在會(huì)話中的表單對(duì)象的生命周期。一個(gè)好的捕獲表單數(shù)據(jù)的實(shí)踐是為橫跨多用戶交互的相關(guān)表單用一個(gè)單獨(dú)的表單bean。表單bean也可以在反饋的時(shí)候用來儲(chǔ)存能夠被自定義標(biāo)簽改變的中間模型狀態(tài)。在視圖中標(biāo)簽用法避免結(jié)合Java代碼,因此要成一個(gè)好的任務(wù)劃分,web生產(chǎn)組主要處理標(biāo)志,而應(yīng)用開發(fā)組主要處理Java代碼。標(biāo)簽因素退出訪問中間模型狀態(tài)的邏輯;當(dāng)訪問嵌套的對(duì)象或當(dāng)通過聚集列舉時(shí)這個(gè)邏輯可能很復(fù)雜。
注意:在struts1.1中,ActionForm的校驗(yàn)功能,逐漸被剝離出來(當(dāng)然依然可以使用)。使用了validator framework對(duì)整個(gè)應(yīng)用系統(tǒng)的表單數(shù)據(jù)驗(yàn)證進(jìn)行統(tǒng)一管理。相信信息請(qǐng)參考:http://home.earthlink.net/~dwinterfeldt
在ActionForm的使用中,Struts提倡使用到值對(duì)象(Value Object)。這樣將客戶或開發(fā)人員,對(duì)數(shù)據(jù)狀態(tài)與對(duì)象狀態(tài)能夠更加清晰的理解和使用。
對(duì)于每一個(gè)客戶請(qǐng)求,Struts framework在處理ActionForm的時(shí)候,一般需要經(jīng)歷如下幾個(gè)步驟:
(1)檢查Action的映射,確定Action中已經(jīng)配置了對(duì)ActionForm的映射
(2)根據(jù)name屬性,查找form bean的配置信息
(3)檢查Action的formbean的使用范圍,確定在此范圍下,是否已經(jīng)有此form bean的實(shí)例。
(4)假如當(dāng)前范圍下,已經(jīng)存在了此form bean的實(shí)例,而是對(duì)當(dāng)前請(qǐng)求來說,是同一種類型的話,那么就重用。
(5)否則,就重新構(gòu)建一個(gè)form bean的實(shí)例
(6)form bean的reset()方法備調(diào)用
(7)調(diào)用對(duì)應(yīng)的setter方法,對(duì)狀態(tài)屬性賦值
(8)如果validatede的屬性北設(shè)置為true,那么就調(diào)用form bean的validate()方法。
(9)如果validate()方法沒有返回任何錯(cuò)誤,控制器將ActionForm作為參數(shù),傳給Action實(shí)例的execute()方法并執(zhí)行。
注意:直接從ActionFrom類繼承的reset()和validate()方法,并不能實(shí)現(xiàn)什么處理功能,所以有必要自己重新覆蓋。
Struts的其他組件
Struts framework本身提供了很多可擴(kuò)展的組件或sub framework,方便的開發(fā)人員在其構(gòu)架上構(gòu)建web層的應(yīng)用系統(tǒng)。比如upload,collections ,logging等等。讓我們來看看兩個(gè)比較重要的組件:validationg framework和struts taglib。有關(guān)其他組件請(qǐng)參考Struts用戶手冊(cè)(http://jakarta.apache.org/struts/userGuide)。
Validation Framework for Struts
在struts1.1中,新增了validation framework。增加了對(duì)form數(shù)據(jù)提交的驗(yàn)證。將原本需要在ActionFrom Bean的validate()進(jìn)行的驗(yàn)證通過配置文件的描述進(jìn)行驗(yàn)證。
有關(guān)其詳細(xì)信息,請(qǐng)參考http://home.earthlink.net/~dwinterfeldt 。個(gè)人建議對(duì)于小型應(yīng)用系統(tǒng)可以采用這種配置方式,但是對(duì)于應(yīng)用系統(tǒng)中有大量web層表單應(yīng)用的系統(tǒng),并且業(yè)務(wù)需求變動(dòng)比較大的,使用validation framework 可能會(huì)加重開發(fā)難度、系統(tǒng)維護(hù)難度。可以借鑒validation framework的Javascript Validator Tag。
Struts TagLib
struts提供了一組可擴(kuò)展的自定義標(biāo)簽庫(kù)(TagLib),可以簡(jiǎn)化創(chuàng)建用戶界面的過程。目前包括:Bean Tags,HTML Tags,Logic Tags,Nested Tags,Template Tags 這幾個(gè)Taglib。有關(guān)Struts Taglib的結(jié)構(gòu)和使用,可以參考前面有關(guān)Cutomer Tag Lib的介紹,有關(guān)起詳細(xì)資料,請(qǐng)參考
BeanUtils
這個(gè)組件的全稱是Bean Introspection Utilites。是屬于Jakarta Commons項(xiàng)目組的。主要是幫助構(gòu)建javabean的屬性操作的(getter,setter),已經(jīng)提供一種動(dòng)態(tài)定義和訪問bean的屬性。有關(guān)詳細(xì)信息,請(qǐng)參考。
http://jakarta.apache.org/commons/beanutils.html
如果各位對(duì)這方面有很興趣,可以參考一些有關(guān)java反射(Reflectio)方面的資料。
Collections
這個(gè)組件主要是提供了一些集合或列表對(duì)象,在原有的java collections framework的基礎(chǔ)上進(jìn)行了擴(kuò)展。詳細(xì)資料請(qǐng)參考:
http://jakarta.apache.org/commons/collections.html 以及
http://cvs.apache.org/viewcvs/~checkout~/jakarta-commons/collections/STATUS.html?rev=1.13
Digester
這個(gè)組件翻譯成中文的意思是“匯編”。其主要功能是根據(jù)xml配置文件,初始化系統(tǒng)的一些java類對(duì)象。Digester幫助你指定XML與java對(duì)象之間映射模型,而且允許客戶話定制映射規(guī)則(rules)。詳細(xì)資料請(qǐng)參考
http://jakarta.apache.org/commons/digester.html
Struts配置文件簡(jiǎn)介
Struts framework根據(jù)配置文件使得ServletAction,ActionMapping,Action , ActionForm這幾個(gè)不同層次的組件相互交互,協(xié)調(diào)的工作。這些配置文件是在系統(tǒng)啟動(dòng)的時(shí)候,讀入導(dǎo)內(nèi)存中,供控制器使用的。
Struts framework主要包括三部分的配置描述,一個(gè)是指定有關(guān)Struts Controller及其相關(guān)的的配置描述(Initialization Parameters),一個(gè)對(duì)struts tag lib的描述,一個(gè)是struts組件(ActionMapping,Action,ActionForm)之間相互映射協(xié)調(diào)的關(guān)系
有關(guān)Struts Controller及其相關(guān)的的配置描述
因?yàn)?span>Struts Controller的主要類ActionServlet是繼承自HttpServlet,所以必須像配置一個(gè)Servlet那樣在部署描述符(Web.xml)中配置ActionServlet類及其訪問映射。
當(dāng)您第一次創(chuàng)建基于Struts的Web應(yīng)用程序時(shí),將為您創(chuàng)建一個(gè)部署描述符,這通常就足夠了。該文件包括下列條目:
l <servlet>條目定義用于Web應(yīng)用程序的servlet(在本例中,這是唯一的servlet):
― <servlet-name> 和<servlet-class>指示ActionServlet (標(biāo)識(shí)為“操作”)接收HTTP請(qǐng)求并確定如何響應(yīng)。
― <init-param>表示servlet初始化參數(shù).
- “config”指示ActionServlet的行為由指定的配置文件來指導(dǎo),該配置文件通常具有以下名稱:
\WEB-INF\struts-config.xml
- “debug”具有整數(shù)值,它指示將有關(guān)處理的詳細(xì)信息寫至控制臺(tái)的程度。
- ”detail”具有整數(shù)值,它指示將“映射”詳細(xì)信息(如后面所述)寫至控制臺(tái)的程度。
― <load-on-startup>導(dǎo)致在啟動(dòng)應(yīng)用程序時(shí)裝入servlet。
l <servlet-mapping>元素標(biāo)識(shí)這樣的命名模式:當(dāng)命名模式由URL進(jìn)行匹配時(shí),Web服務(wù)器就將控制權(quán)移交給ActionServlet。考慮下面各種情況:
― 訪問了ActionServlet,原因是“操作”(<servlet-mapping>中的<servlet-name>元素的內(nèi)容)與“操作”(<servlet>中的<servlet-name>元素的內(nèi)容)相匹配。
― <servlet-mapping>元素指定URL的結(jié)尾的命名模式。每個(gè)URL的開頭都是應(yīng)用程序上下文路徑。按照慣例,ActionServlet調(diào)用對(duì)象以響應(yīng)與命名模式“*do”(其中“*”是通配符)一致的URL。
l <welcome-file-list>元素指示獲得初始控制權(quán)的特定于應(yīng)用程序的代碼;在本例中,Web服務(wù)器直接從Web Content目錄中調(diào)用index.jsp。
l <error-page>元素指示顯示哪個(gè)JSP來響應(yīng)錯(cuò)誤;在本例中,錯(cuò)誤為如下所示:
― 404 (找不到資源)
― 500 (Web服務(wù)器內(nèi)部發(fā)生錯(cuò)誤)
l 每個(gè)<taglib>元素都使相對(duì)URL(相對(duì)于Web.xml)與標(biāo)記庫(kù)描述符(相對(duì)于Web應(yīng)用程序根目錄)相關(guān)聯(lián)。每個(gè)JSP都可以使用同一個(gè)URL來表示給定的標(biāo)記庫(kù),而Web.xml確定引用了哪個(gè)文件。
有關(guān)struts tag lib的配置描述
如果你的web application打算使用Struts的taglib,那么你有必要在web.xml中對(duì)struts taglib進(jìn)行配置描述。
有關(guān)Struts Action Mapping的配置描述
作為先前描述的web.xml設(shè)置的結(jié)果,Web應(yīng)用程序服務(wù)器將請(qǐng)求的一個(gè)子集按路徑發(fā)送至ActionServlet,它通常調(diào)用一系列操作和JSP。ActionServlet的響應(yīng)是基于配置文件struts-config.xml的內(nèi)容的。有關(guān)其DTD文檔的描述,請(qǐng)參考http://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd
一般struts-config(version1.1)包含了如下幾個(gè)部分:
(1)form-bean
(2)global-forwards
(3)action-mappings
(4)data-sources
我們知道,對(duì)于這樣的一個(gè)請(qǐng)求(例如,表示為“/login.do”),執(zhí)行下列步驟:
1、 尋找操作類對(duì)象(繼承org. apache.struts.action.Action的類)
2、 ActionServlet調(diào)用操作類對(duì)象的執(zhí)行方法
操作類中的執(zhí)行方法的特征符為如下所示:
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
l 映射對(duì)象(ActionMapping),它包含指示如何響應(yīng)方法的每個(gè)可能結(jié)果的規(guī)則(“映射”)
l Struts表單bean(ActionForm),它保存發(fā)送至HTML表單或接收自HTML表單的數(shù)據(jù)
l 請(qǐng)求和響應(yīng)對(duì)象(HttpServletReques/ HttpServletResponse)
3、 從執(zhí)行方法返回ActionForward對(duì)象,用于指導(dǎo)ActionServlet接著訪問哪個(gè)操作類或JSP
返回的ActionForward對(duì)象中的信息取決于兩個(gè)值:
l 方法的結(jié)果(如在“成功”或“故障”等字符串中所述)
l 映射對(duì)象,它包含從Struts配置文件中讀取的信息
要弄明白某些運(yùn)行時(shí)關(guān)系,要明白struts-config.xml該文件包括下面的一組條目:
l <form-beans>標(biāo)記標(biāo)識(shí)每個(gè)表單bean
l <action-mappings>標(biāo)記包括用于指導(dǎo)應(yīng)用程序流的信息,每個(gè)<action>子標(biāo)記都使相對(duì)URL與操作類和潛在的后續(xù)操作相關(guān)。
Form-bean元素
Struts配置文件中的一個(gè)示例<form-bean>子元素為如下所示:
<form-bean name=“registerForm” type=“strutscommon.RegisterForm”/>
每個(gè)<form-bean>子元素都包括下列屬性:
name
表單bean的名稱,稍后在配置文件中會(huì)用到。ActionServlet舉例說明了該bean(如果需要的話)并在將對(duì)bean的引用存儲(chǔ)在請(qǐng)求或會(huì)話對(duì)象中時(shí)將該名稱用作鍵。
type
類的全限定名稱,它繼承org.apache.struts.action.ActionForm該類必須在類路徑中。接受“Struts貿(mào)易樣本”中的注冊(cè)的表單bean包括HTML注冊(cè)表單中每個(gè)字段的getter 和setter方法。該bean還包括驗(yàn)證方法,如下節(jié)“驗(yàn)證”中所述。
Action元素
Struts配置文件中的一個(gè)示例<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>
每個(gè)<action>元素都包括下列屬性中的某些屬性或所有屬性:
path
將請(qǐng)求指定為非限定URL,不帶文件擴(kuò)展名(例如,“/register”)請(qǐng)求是根據(jù)<action>元素中的其它屬性來處理的,并且是用戶輸入的結(jié)果或者是在different<action>元素中標(biāo)識(shí)的轉(zhuǎn)發(fā)的結(jié)果。
type
指定在發(fā)出請(qǐng)求時(shí)調(diào)用其執(zhí)行方法的操作類的全限定名。該類必須在類路徑中。
注:不指定要實(shí)例化的類,可以通過使用forward屬性來轉(zhuǎn)發(fā)請(qǐng)求,該屬性在“Struts貿(mào)易樣本”中未使用,并且與后面描述的<forward>子元素不相同。
name
用于保存發(fā)送至HTML表單或接收自HTML表單的數(shù)據(jù)表單bean的名稱。
input
指定相對(duì)URL(例如,“/register.do”或“/index.jsp”)必須包括后綴,
如果表單bean的驗(yàn)證方法指示發(fā)生了輸入錯(cuò)誤,則會(huì)調(diào)用URL;有關(guān)詳細(xì)信息,參見下節(jié)的“驗(yàn)證”。
scope
指定將對(duì)表單 bean的引用存儲(chǔ)在哪個(gè)作用域中。其值為“會(huì)話”(缺省值)或“請(qǐng)求”。
Struts配置文件中的每個(gè)<action>元素還包括子元素<forward>,它指定從方法結(jié)果至后續(xù)調(diào)用的映射。每個(gè)<forward>子元素都包括下列屬性
name
指定導(dǎo)致在運(yùn)行時(shí)使用當(dāng)前映射的字符串(例如,“success”),但是
只限于以下情況:在 type 中引用的操作類的執(zhí)行方法使用完全相同
的字符串來配置返回至ActionServlet的 ActionForward對(duì)象。下面
的執(zhí)行方法不是很重要,但是會(huì)導(dǎo)致使用“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”)必須包括文件擴(kuò)展名,僅當(dāng)使用當(dāng)前映射時(shí)才會(huì)調(diào)用該URL,轉(zhuǎn)發(fā)操作類是根據(jù)different<action>元素中的屬性來處理的,尤其是,在其path屬性標(biāo)識(shí)相同URL的<action>元素中。
有必要提一下的是,在struts1.1中,提出了對(duì)Multiple Application Support。在struts的早先版本中,只有一個(gè)struts配置文件,一般叫struts-config.xml。但是,對(duì)于越來越復(fù)雜的應(yīng)用系統(tǒng)的發(fā)展,只有一個(gè)地方存放這個(gè)一個(gè)文件,對(duì)大型項(xiàng)目來說,使用和修改這個(gè)配置文件,使其成為了一個(gè)應(yīng)用的瓶頸問題。在struts1.1中,你可以定義多了配置文件協(xié)同工作。
注:當(dāng)用戶或ActionServlet調(diào)用JSP時(shí),請(qǐng)求是由Web應(yīng)用程序服務(wù)器直接處理的不會(huì)受到ActionServlet的干預(yù)。
Struts高級(jí)特性(Struts Advanced Feature)
驗(yàn)證
僅當(dāng)在下列情況下才會(huì)在表單bean中對(duì)用戶輸入進(jìn)行驗(yàn)證:
l 表單bean覆蓋超類的驗(yàn)證方法
l Struts配置文件中的<action>元素的驗(yàn)證屬性顯式地或者缺省設(shè)置為TRUE。表單bean沒有關(guān)于應(yīng)用程序的業(yè)務(wù)邏輯的信息;因此該bean提供的驗(yàn)證僅限于一些相對(duì)簡(jiǎn)單的問題,例如,用戶是否在每個(gè)必填字段中都輸入了數(shù)據(jù)?
Struts框架的各種部件使得可以進(jìn)行驗(yàn)證
l Struts配置文件中的以下<action>子元素將導(dǎo)致使用表單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>
如果缺少驗(yàn)證屬性,則意味著當(dāng)ActionServlet接收到來自HTML表單對(duì)“/register”的請(qǐng)求時(shí),ActionServlet將在接收用戶數(shù)據(jù)的表單bean中調(diào)用驗(yàn)證方法。此驗(yàn)證在ActionServlet訪問操作類之前進(jìn)行。如果丟失了該方法,不會(huì)發(fā)生任何錯(cuò)誤,在該情況下,驗(yàn)證總是會(huì)成功。
l 如果發(fā)生了錯(cuò)誤,則表單bean的驗(yàn)證方法將舉例說明錯(cuò)誤類并將錯(cuò)誤條目添加至該類。registerForm的驗(yàn)證方法的一個(gè)子集為如下所示:
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方法包括兩個(gè)參數(shù):
property
用來標(biāo)識(shí)錯(cuò)誤類別的Java字符串。
如果想要在特定的輸入字段或輸入字段的子集發(fā)生錯(cuò)誤時(shí)
標(biāo)識(shí)該錯(cuò)誤,則指定屬性值。例如,指定諸如“username”
之類的值的優(yōu)點(diǎn)在于:報(bào)告了錯(cuò)誤的JSP中,可以在屏幕上
靠近發(fā)生錯(cuò)誤的字段的位置顯示有關(guān)特定HTML字段的錯(cuò)
誤消息,但是,要指示所有錯(cuò)誤都屬于同一類別,可以對(duì)屬
性參數(shù)指定以下常量:
ActionErrors.GLOBAL_ERROR
error
包含從屬性文件派生的“鍵-字符串”對(duì)的鍵的ActionError 對(duì)象。當(dāng)配置ActionError對(duì)象時(shí),最多可以包括要代入字符串中用來替代{0}、{1}等的四個(gè)值。
l 如果從驗(yàn)證方法返回了錯(cuò)誤,則ActionServlet指導(dǎo)對(duì)在<action>元素的輸入屬性中指定的對(duì)象或JSP進(jìn)行處理;在本例中,將處理register.jsp.
l JSP register.jsp. 包括用于顯示從驗(yàn)證方法派生的任何錯(cuò)誤消息的以下
標(biāo)記:
<html:errors/>
如果在未發(fā)生輸入錯(cuò)誤的情況下調(diào)用JSP,則該標(biāo)記不顯示任何內(nèi)容,
而在JSP中將繼續(xù)進(jìn)行處理。但是,如果因發(fā)生驗(yàn)證故障而調(diào)用了JSP,
則為用戶顯示的內(nèi)容將受到屬性文件中是否包括下列鍵的影響:
― errors.header,它導(dǎo)致在所有錯(cuò)誤消息前面顯示一個(gè)字符串;或者
― errors.footer,它導(dǎo)致在所有錯(cuò)誤消息后面顯示一個(gè)字符串;或者
― errors.hiader,和errors.footer兩者
例如,在ApplicationResources.properties 中,errors.header和 errors.footer的“鍵-字符串”對(duì)以及先前顯示的這兩個(gè)消息鍵為如下所示,它們各自都在單獨(dú)的一行上(但是分成了多行顯示以便于您復(fù)查):
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>
如果在注冊(cè)時(shí)用戶對(duì)用戶名輸入了空白,對(duì)余額輸入零,則用戶將接收到一個(gè)包括兩個(gè)錯(cuò)誤的列表的屏幕:
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.
可以為標(biāo)記<html:errors/>指定屬性以支持國(guó)際化或者只顯示有關(guān)指定了給定屬性值的錯(cuò)誤的信息。通過使用相異屬性值,可以在相鄰的不同字段中顯示每條錯(cuò)誤消息而不是將所有錯(cuò)誤置于單個(gè)列表中。
使用異常處理聲明
要定義應(yīng)用程序的邏輯流程,成熟的經(jīng)驗(yàn)是推薦在代碼之外,用配置的方法來實(shí)現(xiàn),而不是寫死在程序代碼中的。在J2EE中,這樣的例子比比皆是。從實(shí)現(xiàn)EJB的安全性和事務(wù)性行為到描述JMS消息和目的地之間的關(guān)系,很多運(yùn)行時(shí)的處理流程都是可以在程序之外定義的。
Struts 創(chuàng)建者從一開始就采用這種方法,通過配置Struts的配置文件來定制應(yīng)用系統(tǒng)運(yùn)行時(shí)的各個(gè)方面。這一點(diǎn)在版本1.1的新特性上得到延續(xù),包括新的異常處理功能。在Struts framework以前的版本中,開發(fā)人員不得不自己處理Struts應(yīng)用中發(fā)生的錯(cuò)誤情況。在最新的版本中,情況大大的改觀了,Struts Framework提供了內(nèi)置的一個(gè)稱為 ExceptionHandler 的類, 用于系統(tǒng)缺省處理action類運(yùn)行中產(chǎn)生的錯(cuò)誤。這也是在上一個(gè)技巧中我們提到的framework許多可擴(kuò)展接口之一。
Struts缺省的 ExceptionHandler類會(huì)生成一個(gè)ActionError對(duì)象并保存在適當(dāng)?shù)姆秶?span>scope)對(duì)象中。這樣就允許JSP頁(yè)面使用錯(cuò)誤類來提醒用戶出現(xiàn)什么問題。如果你認(rèn)為這不能滿足你的需求,那么可以很方便的實(shí)現(xiàn)你自己的ExcepionHandler類。
具體定制異常處理的方法和機(jī)制
要定制自己的異常處理機(jī)制,第一步是繼承org.apache.struts.action.ExceptionHandler類。這個(gè)類有2個(gè)方法可以覆蓋,一個(gè)是excute()另外一個(gè)是storeException(). 在多數(shù)情況下,只需要覆蓋其中的excute()方法。下面是ExceptionHandler類的excute()方法聲明:
正如你看到的,該方法有好幾個(gè)參數(shù),其中包括原始的異常。方法返回一個(gè)ActionForward對(duì)象,用于異常處理結(jié)束后將controller類帶到請(qǐng)求必須轉(zhuǎn)發(fā)的地方去。
當(dāng)然您可以實(shí)現(xiàn)任何處理,但一般而言,我們必須檢查拋出的異常,并針對(duì)該類型的異常進(jìn)行特定的處理。缺省的,系統(tǒng)的異常處理功能是創(chuàng)建一個(gè)出錯(cuò)信息,同時(shí)把請(qǐng)求轉(zhuǎn)發(fā)到配置文件中指定的地方去。定制異常處理的一個(gè)常見的例子是處理嵌套異常。假設(shè)該異常包含有嵌套異常,這些嵌套異常又包含了其他異常,因此我們必須覆蓋原來的execute()方法,對(duì)每個(gè)異常編寫出錯(cuò)信息。
一旦你創(chuàng)建了自己的ExceptionHandler 類,就應(yīng)該在Struts配置文件中的部分聲明這個(gè)類,以便讓Struts知道改用你自定義的異常處理取代缺省的異常處理.
可以配置你自己的ExceptionHandler 類是用于Action Mapping特定的部分還是所有的Action對(duì)象。如果是用于Action Mapping特定的部分就在元素中配置。如果想讓這個(gè)類可用于所有的Action對(duì)象,可以在元素中指定。例如,假設(shè)我們創(chuàng)建了異常處理類CustomizedExceptionHandler用于所有的Action類, 元素定義如下所示:
在元素中可以對(duì)很多屬性進(jìn)行設(shè)置。在本文中,最重要的屬性莫過于handler屬性, handler屬性的值就是自定義的繼承了ExceptionHandler類的子類的全名。假如該屬性沒有定義,Struts會(huì)采用自己的缺省值。當(dāng)然,其他的屬性也很重要,但如果想覆蓋缺省的異常處理的話,handler無疑是最重要的屬性。
最后必須指出的一點(diǎn)是,你可以有不同的異常處理類來處理不同的異常。在上面的例子中,CustomizedExceptionHandler用來處理任何java.lang.Exception的子類. 其實(shí),你也可以定義多個(gè)異常處理類,每一個(gè)專門處理不同的異常樹。下面的XML片斷解釋了如何配置以實(shí)現(xiàn)這一點(diǎn)。
在這里,一旦有異常拋出,struts framework將試圖在配置文件中找到ExceptionHandler,如果沒有找到,那么struts將沿著該異常的父類鏈一層層往上找直到發(fā)現(xiàn)匹配的為止。因此,我們可以定義一個(gè)層次型的異常處理關(guān)系結(jié)構(gòu),在配置文件中已經(jīng)體現(xiàn)了這一點(diǎn)。
使用應(yīng)用模塊(Application Modules)
Struts 1.1的一個(gè)新特性是應(yīng)用模塊的概念。應(yīng)用模塊允許將單個(gè)Struts應(yīng)用劃分成幾個(gè)模塊,每個(gè)模塊有自己的Struts配置文件,JSP頁(yè)面,Action等等。這個(gè)新特性是為了解決大中型的開發(fā)隊(duì)伍抱怨最多的一個(gè)問題,即為了更好的支持并行開發(fā)允許多個(gè)配置文件而不是單個(gè)配置文件。
顯然,當(dāng)很多開發(fā)人員一起參加一個(gè)項(xiàng)目時(shí),單個(gè)的Struts配置文件很容易引起資源沖突。應(yīng)用模塊允許Struts按照功能要求進(jìn)行劃分,許多情況已經(jīng)證明這樣更貼近實(shí)際。例如,假設(shè)我們要開發(fā)一個(gè)典型的商店應(yīng)用程序。可以將組成部分劃分成模塊比如catalog(商品目錄), customer(顧客), customer service(顧客服務(wù)), order(訂單)等。每個(gè)模塊可以分布到不同的目錄下,這樣各部分的資源很容易定位,有助于開發(fā)和部署。圖1 顯示了該應(yīng)用的目錄結(jié)構(gòu)。
一個(gè)典型的商店應(yīng)用程序的目錄結(jié)構(gòu)
注:如果你無需將項(xiàng)目劃分成多個(gè)模塊,Struts框架支持一個(gè)缺省的應(yīng)用模塊。這就使得應(yīng)用程序也可以在1.0版本下創(chuàng)建,具有可移植性,因?yàn)閼?yīng)用程序會(huì)自動(dòng)作為缺省的應(yīng)用模塊。
為了使用多應(yīng)用模塊功能,必須執(zhí)行以下幾個(gè)準(zhǔn)備步驟:
· 為每個(gè)應(yīng)用模塊創(chuàng)建獨(dú)立的Struts配置文件。
· 配置Web 部署描述符 Web.xml文件。
· 使用org.apache.struts.actions.SwitchAction 來實(shí)現(xiàn)程序在模塊之間的跳轉(zhuǎn).
創(chuàng)建獨(dú)立的Struts配置文件
每個(gè)Struts應(yīng)用模塊必須擁有自己的配置文件。允許創(chuàng)建自己的獨(dú)立于其他模塊的Action,ActionForm,異常處理甚至更多。
繼續(xù)以上面的商店應(yīng)用程序?yàn)槔覀兛梢詣?chuàng)建以下的配置文件:一個(gè)文件名為struts-config-catalog.xml,包含catalog(商品目錄)、items(商品清單)、和其它與庫(kù)存相關(guān)的功能的配置信息;另一個(gè)文件名為struts- config-order.xml, 包含對(duì)order(訂單)和order tracking(訂單跟蹤)的設(shè)置。第三個(gè)配置文件是struts-config.xml,其中含有屬于缺省的應(yīng)用模塊中的一般性的功能。
在為每個(gè)應(yīng)用模塊創(chuàng)建獨(dú)立的配置文件之后,我們就有可能需要調(diào)用不同的模塊中Action。為此必須使用Struts框架提供的SwitchAction類。Struts 會(huì)自動(dòng)將應(yīng)用模塊的名字添加到URL,就如Struts 自動(dòng)添加應(yīng)用程序的名字加到URL一樣。應(yīng)用模塊是對(duì)框架的一個(gè)新的擴(kuò)充,有助于進(jìn)行并行的團(tuán)隊(duì)開發(fā)。如果你的團(tuán)隊(duì)很小那就沒必要用到這個(gè)特性,不必進(jìn)行模塊化。當(dāng)然,就算是只有一個(gè)模塊,系統(tǒng)還是一樣的運(yùn)作。
把JSP放到WEB-INF后以保護(hù)JSP源代碼
為了更好地保護(hù)你的JSP避免未經(jīng)授權(quán)的訪問和窺視,一個(gè)好辦法是將頁(yè)面文件存放在Web應(yīng)用的WEB-INF目錄下。
通常JSP開發(fā)人員會(huì)把他們的頁(yè)面文件存放在Web應(yīng)用相應(yīng)的子目錄下。一個(gè)典型的商店應(yīng)用程序的目錄結(jié)構(gòu)如圖2所示。跟catalog (商品目錄)相關(guān)的JSP被保存在catalog子目錄下。跟customer相關(guān)的JSP,跟訂單相關(guān)的JSP等都按照這種方法存放。
基于不同的功能 JSP 被放置在不同的目錄下
這種方法的問題是這些頁(yè)面文件容易被偷看到源代碼,或被直接調(diào)用。某些場(chǎng)合下這可能不是個(gè)大問題,可是在特定情形中卻可能構(gòu)成安全隱患。用戶可以繞過Struts的controller直接調(diào)用JSP同樣也是個(gè)問題。
為了減少風(fēng)險(xiǎn),可以把這些頁(yè)面文件移到WEB-INF 目錄下。基于Servlet的聲明,WEB-INF不作為Web應(yīng)用的公共文檔樹的一部分。因此,WEB-INF 目錄下的資源不是為客戶直接服務(wù)的。我們?nèi)匀豢梢允褂?span>WEB-INF目錄下的JSP頁(yè)面來提供視圖給客戶,客戶卻不能直接請(qǐng)求訪問JSP。
采用前面的例子,圖3顯示將JSP頁(yè)面移到WEB-INF 目錄下后的目錄結(jié)構(gòu)
JSP存放在 WEB-INF 目錄下更為安全
如果把這些JSP頁(yè)面文件移到WEB-INF 目錄下,在調(diào)用頁(yè)面的時(shí)候就必須把"WEB-INF"添加到URL中。例如,在一個(gè)Struts配置文件中為一個(gè)logoff action寫一個(gè)Action mapping。其中JSP的路徑必須以"WEB-INF"開頭。如下所示:請(qǐng)注意粗體部分.
這個(gè)方法在任何情況下都不失為Struts實(shí)踐中的一個(gè)好方法。是唯一要注意的技巧是你必須把JSP和一個(gè)Struts action聯(lián)系起來。即使該Action只是一個(gè)很基本的很簡(jiǎn)單JSP,也總是要調(diào)用一個(gè)Action,再由它調(diào)用JSP。
最后要說明的是,并不是所有的容器都能支持這個(gè)特性。WebLogic早期的版本不能解釋Servlet聲明,因此無法提供支持,據(jù)報(bào)道在新版本中已經(jīng)改進(jìn)了。總之使用之前先檢查一下你的Servlet容器。
使用 Prebuilt Action類提升開發(fā)效率
Struts framework帶有好幾個(gè)prebuilt Action類,使用它們可以大大節(jié)省開發(fā)時(shí)間。其中最有用的是org.apache.struts.actions.ForwardAction 和 org.apache.struts.actions.DispatchAction.
使用 ForwardAction
在應(yīng)用程序中,可能會(huì)經(jīng)常出現(xiàn)只要將Action對(duì)象轉(zhuǎn)發(fā)到某個(gè)JSP的情況。在上一點(diǎn)中曾提到總是由Action調(diào)用JSP是個(gè)好習(xí)慣。如果我們不必在Action中執(zhí)行任何業(yè)務(wù)邏輯,卻又想遵循從Action訪問頁(yè)面的話,就可以使用ForwardAction,它可以使你免去創(chuàng)建許多空的Action類。運(yùn)用ForwardAction的好處是不必創(chuàng)建自己的Action類,你需要做的僅僅是在Struts配置文件中配置一個(gè)Action mapping。
舉個(gè)例子,假定你有一個(gè)JSP文件index.jsp ,而且不能直接調(diào)用該頁(yè)面,必須讓程序通過一個(gè)Action類調(diào)用,那么,你可以建立以下的Action mapping來實(shí)現(xiàn)這一點(diǎn):
正如你看到的,當(dāng) /home 被調(diào)用時(shí), 就會(huì)調(diào)用ForwardAction 并把請(qǐng)求轉(zhuǎn)發(fā)到 index.jsp 頁(yè)面.
再討論一下不通過一個(gè)Action類直接轉(zhuǎn)發(fā)到某個(gè)頁(yè)面的情況,必須注意我們?nèi)匀皇褂迷刂械?span>forward屬性來實(shí)現(xiàn)轉(zhuǎn)發(fā)的目標(biāo)。這時(shí)元素定義如下:
以上兩種方法都可以節(jié)省你的時(shí)間,并有助于減少一個(gè)應(yīng)用所需的文件數(shù)。
使用 DispatchAction
DispatchAction是Struts包含的另一個(gè)能大量節(jié)省開發(fā)時(shí)間的Action類。與其它Action類僅提供單個(gè)execute()方法實(shí)現(xiàn)單個(gè)業(yè)務(wù)不同,DispatchAction允許你在單個(gè)Action類中編寫多個(gè)與業(yè)務(wù)相關(guān)的方法。這樣可以減少Action類的數(shù)量,并且把相關(guān)的業(yè)務(wù)方法集合在一起使得維護(hù)起來更容易。
要使用DispatchAction的功能,需要自己創(chuàng)建一個(gè)類,通過繼承抽象的DispatchAction得到。對(duì)每個(gè)要提供的業(yè)務(wù)方法必須有特定的方法signature。例如,我們想要提供一個(gè)方法來實(shí)現(xiàn)對(duì)購(gòu)物車添加商品清單,創(chuàng)建了一個(gè)類ShoppingCartDispatchAction提供以下的方法:
那么,這個(gè)類很可能還需要一個(gè)deleteItem()方法從客戶的購(gòu)物車中刪除商品清單,還有clearCart()方法清除購(gòu)物車等等。這時(shí)我們就可以把這些方法集合在單個(gè)Action類,不用為每個(gè)方法都提供一個(gè)Action類。
在調(diào)用ShoppingCartDispatchAction里的某個(gè)方法時(shí),只需在URL中提供方法名作為參數(shù)值。就是說,調(diào)用addItem()方法的 URL看起來可能類似于:
http://myhost/storefront/action/cart?method=addItem
其中method參數(shù)指定ShoppingCartDispatchAction中要調(diào)用的方法。參數(shù)的名稱可以任意配置,這里使用的"method"只是一個(gè)例子。參數(shù)的名稱可以在Struts配置文件中自行設(shè)定。
Struts標(biāo)記庫(kù)
定制JSP標(biāo)記
Struts提供了用來封裝邏輯的各種定制JSP標(biāo)記,因此頁(yè)面設(shè)計(jì)者可以將主要精力花在頁(yè)面的可視特征上,而不必主要考慮Java語(yǔ)法或其它JSP語(yǔ)法,在下列標(biāo)識(shí)庫(kù)描述符中引用了Struts標(biāo)記:
Struts-bean.tld
使訪問bean以及新bean的定義更容易,,為了實(shí)現(xiàn)國(guó)際化,應(yīng)使用不同的屬性文件
struts-html.tld
提供顯示HTML對(duì)象(例如,表單、按鈕和復(fù)選框)的簡(jiǎn)便方法
struts-logic.tld
支持邏輯構(gòu)造,以便可以有條件地顯示文本或者作為處理循環(huán)的結(jié)果來顯示文本
struts-template.tld
支持使用在運(yùn)行時(shí)可以修改的JSP模板
要在JSP文件頂部的<taglib>偽指令如下所示:
<%@ taglib uri=“struts-html. tld” prefix=“html”%>
<%@ taglib uri=“struts-bean.tld”prefix=“bean”%>
<%@ taglib uri=“struts-logic.tld”prefix=“logic”%>
每個(gè)<taglib>偽指令都具有與基于 web.xml的< taglib>標(biāo)記中的URL相匹配的URL。另外JSP中的每個(gè) struts標(biāo)記都使用一個(gè)使標(biāo)記與特定標(biāo)記庫(kù)描述符相關(guān)的前綴:
― 沒有嵌套內(nèi)容的標(biāo)記可以采用以下格式:
<prefix:tagName attributesAndValues/>
― 嵌套內(nèi)容是在一對(duì)標(biāo)記之間嵌套的:
<prefix:tagName attributesAndValues />
</prefix:tagName>
prefix
在JSP taglib偽指令中指定的前綴
tagName
標(biāo)記的名稱,如標(biāo)記庫(kù)描述符中所述;描述符條目指定提供標(biāo)記邏輯的Jave類
attributesAndValues
― 系列屬性與值的配對(duì)(是必需的或者是可選的),每個(gè)配對(duì)都包括一種屬性、一個(gè)等號(hào)(沒有前導(dǎo)或結(jié)尾空白)和一個(gè)引起來的字符串
文件resource.jsp包含bean:message標(biāo)記的幾個(gè)實(shí)例。以下是標(biāo)記的示例用法:
<bean:message key=“market. text. title”/>
資源束
在最簡(jiǎn)單的情況下,bean:message標(biāo)記解析為存儲(chǔ)在根據(jù)屬性文件創(chuàng)建的資源束中的字符串:
― 屬性文件的名稱是用來調(diào)用ActoinServlet的web.xml “application”參數(shù)的值。如:
\WEB-INF\classes\ApplicationResources.properties
― 消息標(biāo)記中的key屬性指向?qū)傩晕募械?#8220;鍵-字符串”對(duì);在本例中,指向下面的“鍵-字符串”對(duì):
market. text.title=Current Market Conditions
可以采用各種方法來定制bean:message標(biāo)記,以便(例如)JSP在運(yùn)行時(shí)引用不同的屬性文件。標(biāo)記提供了一種方法來支持多種語(yǔ)言以及最多將四個(gè)替代值插入到字符串中來代替{0}、{1}等等。
l 僅當(dāng)指定的對(duì)象或值存在時(shí),logic:present 標(biāo)記才會(huì)導(dǎo)致顯示嵌套的文本。在register.jsp中,僅當(dāng)操作類創(chuàng)建了作為 tickerBean引用(在任何作用域中)的 Java bean 時(shí)才為用戶提供HTML表行。 Struts標(biāo)記為如下所示:
<logic:present name=“tickerBean”>
-->nested content for presentation<--
</logic:present>
l Struts標(biāo)記允許很方便地訪問Java bean內(nèi)容。例如,以下標(biāo)記將解析為存儲(chǔ)在 tickerBean中的值:
<bean:write name= “tickerBean”property=“DJChange”/>
tickerBean的源代碼在以下目錄中:
Trade\Java Source\tradeCommon\tickerBean.java
l HTML表單與表單bean之間的數(shù)據(jù)傳送是通過使用html:form 和html:text標(biāo)記來完成的。 register.jsp中的輸入表單是按如下所示構(gòu)建的:
<html:form action= “/register”>
-->nested form content with html: text tags<--
</html:form action>
html:form 標(biāo)記解析為HTML FORM 標(biāo)記并導(dǎo)致html: text 標(biāo)記引用適當(dāng)?shù)谋韱?/span>bean;特別是在 path=“/register”的 Struts配置文件的 <action>標(biāo)記中標(biāo)識(shí)的表單 bean。
html:text標(biāo)記建立HTML輸入字段。例如,以下標(biāo)記確保在HTML輸入字段與表單bean的用戶名字段之間傳送信息:
<html:text property=“username”size=“40”/>
JSP視窗組件所使用的 struts標(biāo)記庫(kù)由四類標(biāo)記組成:
l Bean標(biāo)記:用來在JSP頁(yè)中管理bean
l 邏輯標(biāo)記:用來在JSP頁(yè)中控制流程
l HTML標(biāo)記:用來生成HTML標(biāo)記,在表單中顯示數(shù)據(jù),使用會(huì)話ID對(duì)URL進(jìn)行編程
l 模板標(biāo)記:使用動(dòng)態(tài)模板構(gòu)造普通格式的頁(yè)
Bean標(biāo)記
這個(gè)標(biāo)記庫(kù)中包含用于定義新bean、訪問bean及其屬性的標(biāo)記。Struts框架提供了多種自定義標(biāo)記用來在JSP頁(yè)中處理JavaBean。這些標(biāo)記被封裝在一個(gè)普通的標(biāo)記庫(kù)中,在文件struts-bean.tld中定義了它的標(biāo)記庫(kù)描述器。Bean標(biāo)記庫(kù)將標(biāo)記定義在四個(gè)子類別中:
l 創(chuàng)建和復(fù)制bean的標(biāo)記
l 腳本變量定義標(biāo)記
l bean翻譯標(biāo)記
l 消息國(guó)際化標(biāo)記
Bean復(fù)制標(biāo)記
可定義新bean,可復(fù)制現(xiàn)有bean,還可從現(xiàn)有bean復(fù)制屬性。
<bean:define>標(biāo)記用來:
l 定義新字符串常數(shù)
l 將現(xiàn)有的bean復(fù)制到新定義的bean對(duì)象
l 復(fù)制現(xiàn)有bean的屬性來創(chuàng)建新的bean
<bean:define>標(biāo)記屬性:
屬性 |
描述 |
Id |
新定義的bean腳本變量名稱,必須設(shè)置 |
Type |
定義引入腳本變量的類 |
Value |
為id屬性定義的腳本變量分配一個(gè)新的對(duì)象 |
Name |
目標(biāo)bean的名稱。若value屬性沒有設(shè)置,這個(gè)屬性就必須設(shè)置 |
property |
Name屬性定義的bean的屬性名稱,用來定義新的bean |
Scope |
源bean的作用域。若沒有設(shè)置,搜索范圍是從頁(yè)作用域到應(yīng)用程序作用域 |
toScope |
目標(biāo)bean的作用域。若沒有設(shè)置,默認(rèn)值是頁(yè)作用域 |
例如:定義一個(gè)bean:
<bean:define id=”test” value=”this is a test”/>
源bean在頁(yè)作用域中被拷貝大哦請(qǐng)求作用域中的另一個(gè)bean:
<bean:define id=”targetBean” name=”sourceBean”
scope=”page” toScope=”request”/>
定義腳本變量的標(biāo)記
從多種資源中定義和生成腳本變量,這些資源包括cookie,請(qǐng)求參數(shù),HTTP標(biāo)頭等等。屬性如下:
屬性 |
描述 |
Id |
腳本變量和要定義的頁(yè)作用域?qū)傩缘拿Q |
Name |
cookie/標(biāo)頭/參數(shù)的名稱 |
multiple |
如果這個(gè)屬性設(shè)置了任意一個(gè)數(shù)值,所有匹配的cookie都會(huì)被積累并存儲(chǔ)到一個(gè)Cookie[](一個(gè)數(shù)組)類型的bean里。若無設(shè)置,指定cookie的第一個(gè)值將作為Cookie類型的值 |
Value |
如果沒有匹配的cookie或數(shù)值,就返回這個(gè)屬性指定的默認(rèn)值 |
例如:
<bean:cookie id=”myCookie” name=”userName”/>
腳本變量名稱是myCookie,用來創(chuàng)建這個(gè)屬性的cookie的名稱是userName。
<bean:header id=”myHeader” name=”Accept-Language”/>
腳本變量名稱是myHeader,請(qǐng)求標(biāo)頭的名稱是Accept-Language.
<bean:parameter id=”myParameter” name=”myParameter”>
腳本變量名稱是myPatameter,它保存的請(qǐng)求參數(shù)的名稱也是myParameter.
<bean:include>標(biāo)記將對(duì)一個(gè)資源的響應(yīng)進(jìn)行檢索,并引入一個(gè)腳本變量和字符串類型的頁(yè)作用域?qū)傩浴_@個(gè)資源可以是一個(gè)頁(yè),一個(gè)ActionForward或一個(gè)外部URL。與<jsp:include>的不同是資源的響應(yīng)被存儲(chǔ)到一個(gè)頁(yè)作用域的bean中,而不是寫入到輸出流。屬性如下:
屬性 |
描述 |
Id |
腳本變量和要定義的頁(yè)作用域?qū)傩缘拿Q |
Page |
一個(gè)內(nèi)部資源 |
forward |
一個(gè)ActionForward |
Href |
要包含的資源的完整URL |
例如:
<bean:include id=”myInclude” page=”MyJsp?x=1”/>
腳本變量的名稱是myInclude,要檢索的響應(yīng)來自資源MyJsp?x=1。
<bean:resource>標(biāo)記將檢索web應(yīng)用中的資源,并引入一個(gè)腳本變量和InputStream或字符串類型的頁(yè)作用域?qū)傩浴H绻跈z索資源時(shí)發(fā)生問題,就會(huì)產(chǎn)生一個(gè)請(qǐng)求時(shí)間異常。屬性如下:
屬性 |
描述 |
Id |
腳本變量和要定義的頁(yè)作用域?qū)傩缘拿Q |
Name |
資源的相對(duì)路徑 |
Input |
如果這個(gè)屬性不存在,資源的類型就是字符串 |
例如:
<bean:resource id=”myResource” name=”/WEB-INF/images/myResource.xml”/>
腳本變量的名稱是myResource,要檢索的資源的名稱是myResource.xml。
顯示Bean屬性
標(biāo)記庫(kù)中定義了<bean:write>標(biāo)記,用來將bean的屬性輸送到封裝的JSP頁(yè)寫入器。這個(gè)標(biāo)記與<jsp:getProperty>類似,屬性如下:
屬性 |
描述 |
Name |
要進(jìn)行屬性顯示的bean的名稱 |
property |
要顯示的屬性的名稱。如果這個(gè)屬性類有java.beans.PropertyEditor,getAsText()或toString 方法會(huì)被調(diào)用 |
Scope |
Bean的作用域,若沒有設(shè)置,搜索范圍是從頁(yè)到應(yīng)用程序作用域 |
Filter |
如果設(shè)置true,屬性中的所有特殊HTML字符都將被轉(zhuǎn)化為相應(yīng)的實(shí)體引用 |
Ignore |
如果設(shè)置false,當(dāng)發(fā)現(xiàn)屬性時(shí)會(huì)產(chǎn)生一個(gè)請(qǐng)求時(shí)間異常,否則返回null |
例如:
<bean:write name=”myBean” property=”myProperty” scope=”request”
filter=”true”/>
myBean的屬性myProperty將會(huì)被顯示,作用域?yàn)檎?qǐng)求,如果發(fā)現(xiàn)任何HTML特殊字符都將被轉(zhuǎn)化為相應(yīng)的實(shí)體引用。
消息標(biāo)記和國(guó)際化
strtus框架支持國(guó)際化和本地化。用戶在他們的計(jì)算機(jī)中定義自己所在的區(qū)域,當(dāng)web應(yīng)用程序需要輸出一條消息時(shí),它將引用一個(gè)資源文件,在這個(gè)文件中所有的消息都使用了適當(dāng)?shù)恼Z(yǔ)言。一個(gè)應(yīng)用程序可能提供了很多資源文件,每個(gè)文件提供了用不同語(yǔ)言編寫的消息。如果沒有找到所選語(yǔ)言的資源文件,就將使用默認(rèn)的資源文件。
struts框架對(duì)國(guó)際化的支持是使用<bean:message>標(biāo)記,以及使用java.util數(shù)據(jù)包中定義的Locale和ResourceBundle類來實(shí)現(xiàn)Java2平臺(tái)對(duì)這些任務(wù)的支持。Java.text.MessageFormat類定義的技術(shù)可以支持消息的格式。利用此功能,開發(fā)人員不需了解這些類的細(xì)節(jié)就可進(jìn)行國(guó)際化和設(shè)置消息的格式。
用strtus實(shí)現(xiàn)國(guó)際化和本地化:
第一步要定義資源文件的名稱,這個(gè)文件會(huì)包含用默認(rèn)語(yǔ)言編寫的在程序中會(huì)出現(xiàn)的所有消息。這些消息以“關(guān)鍵字-值”的形式存儲(chǔ),如下:
error.validation.location = The entered location is invalid
這個(gè)文件需要存儲(chǔ)在類的路徑下,而且它的路徑要作為初始化參數(shù)傳送給ActionServlet作為參數(shù)進(jìn)行傳遞時(shí),路徑的格式要符合完整Java類的標(biāo)準(zhǔn)命名規(guī)范。比如,如果資源文件存儲(chǔ)在WEB-INF\classes目錄中,文件名是ApplicationResources.properties,那么需要傳遞的參數(shù)值是ApplicationResources。如果文件在WEB-INF\classes\com\test中,那么參數(shù)值就應(yīng)該是com.test. ApplicationResources.
為了實(shí)現(xiàn)國(guó)際化,所有的資源文件必須都存儲(chǔ)在基本資源文件所在的目錄中。基本資源文件包含的是用默認(rèn)地區(qū)語(yǔ)言-本地語(yǔ)言編寫的消息。如果基本資源文件的名稱是ApplicationResources.properties,那么用其他特定語(yǔ)言編寫的資源文件的名稱就應(yīng)該是ApplicationResources_xx.properties(xx為ISO編碼,如英語(yǔ)是en)。因此這些文件應(yīng)包含相同的關(guān)鍵字,但關(guān)鍵字的值是用特定語(yǔ)言編寫的。
ActionServlet的區(qū)域初始化參數(shù)必須與一個(gè)true值一起傳送,這樣ActionServlet就會(huì)在用戶會(huì)話中的Action.LOCALE_KEY關(guān)鍵字下存儲(chǔ)一個(gè)特定用戶計(jì)算機(jī)的區(qū)域?qū)ο蟆,F(xiàn)在可以運(yùn)行一個(gè)國(guó)際化的web站點(diǎn),它可以根據(jù)用戶計(jì)算機(jī)上的設(shè)置的區(qū)域自動(dòng)以相應(yīng)的語(yǔ)言顯示。
我們還可以使用特定的字符串來替換部分消息,就象用java.text.MessageFormat的方法一樣:
error.invalid.number = The number {0} is valid
我們可以把字符串{0}替換成任何我們需要的數(shù)字。<bean:message>標(biāo)簽屬性如下:
屬性 |
描述 |
Key |
資源文件中定義消息關(guān)鍵字 |
Locale |
用戶會(huì)話中存儲(chǔ)的區(qū)域?qū)ο蟮膶傩悦Q。若沒有設(shè)置,默認(rèn)值是Action.LOCALE_KEY |
Bundle |
在應(yīng)用程序上下文中,存儲(chǔ)資源對(duì)象的屬性的名稱。如果沒有設(shè)置這個(gè)屬性,默認(rèn)值是Action.MESSAGE_KEY |
arg0 |
第一個(gè)替換參數(shù)值 |
arg1 |
第二個(gè)替換參數(shù)值 |
arg2 |
第三個(gè)替換參數(shù)值 |
arg3 |
第四個(gè)替換參數(shù)值 |
例如:資源文件中定義了一個(gè)消息:
info.myKey = The numbers entered are {0},{1},{2},{3}
我們可使用下面的消息標(biāo)記:
<bean:message key=”info.myKey” arg0=”5” arg1=”6” arg2=”7” arg3=”8”/>
這個(gè)信息標(biāo)記輸出到JSP頁(yè)會(huì)顯示為:The numbers entered are 5,6,7,8
邏輯標(biāo)記
邏輯庫(kù)的標(biāo)記能夠用來處理外觀邏輯而不需要使用scriptlet。Struts邏輯標(biāo)簽庫(kù)包含的標(biāo)記能夠有條件地產(chǎn)生輸出文本,在對(duì)象集合中循環(huán)從而重復(fù)地產(chǎn)生輸出文本,以及應(yīng)用程序流程控制。它也提供了一組在JSP頁(yè)中處理流程控制的標(biāo)記。這些標(biāo)記封裝在文件名為struts-logic.tld的標(biāo)記包中。邏輯標(biāo)記庫(kù)定義的標(biāo)記能夠執(zhí)行下列三個(gè)功能:
l 條件邏輯
l 重復(fù)
l 轉(zhuǎn)發(fā)/重定向響應(yīng)
條件邏輯
struts有三類條件邏輯。第一類可以比較下列實(shí)體與一個(gè)常數(shù)的大小:
l cookie
l 請(qǐng)求參數(shù)
l bean或bean的參數(shù)
l 請(qǐng)求標(biāo)頭
以下列出了這一類標(biāo)記:
標(biāo)記 |
功能 |
<equal> |
如果常數(shù)與被定義的實(shí)體相等,返回true |
<notEqual> |
如果常數(shù)與被定義的實(shí)體不相等,返回true |
<greaterEqual> |
如果常數(shù)大于等于被定義的實(shí)體,返回true |
<lessEqual> |
如果常數(shù)小于等于被定義的實(shí)體,返回true |
<lessThan> |
如果常數(shù)小于被定義的實(shí)體,返回true |
<greaterThan> |
如果常數(shù)大于被定義的實(shí)體,返回true |
這一類的所有標(biāo)記有相同的屬性
屬性 |
描述 |
Value |
要進(jìn)行比較的常數(shù)值 |
Cookie |
要進(jìn)行比較的HTTP cookie的名稱 |
Header |
要進(jìn)行比較的HTTP請(qǐng)求標(biāo)頭的名稱 |
parameter |
要進(jìn)行比較的HTTP請(qǐng)求參數(shù)的名稱 |
Name |
如果要進(jìn)行比較的是bean或bean的屬性,則這個(gè)屬性代表bean的名稱 |
property |
要進(jìn)行比較的bean屬性的名稱 |
Scope |
Bean的作用域,如果沒有指定作用域,則它的搜索范圍是從頁(yè)到應(yīng)用程序 |
例如:
<logic:equal parameter=”name” value=”SomeName”>
The entered name is SomeName
</logic:equal>
判斷名為”name”的請(qǐng)求參數(shù)的值是否是”SomeName”。
<logic:greaterThan name=”bean” property=”prop” scope=”page” value=”7”>
The value of bean.Prop is greater than 7
</logic:greaterThan>
判斷在頁(yè)的作用域中是否有一個(gè)名為”bean”的bean,它有一個(gè)prop屬性,這個(gè)屬性的值是否大于7。如果這個(gè)屬性能夠轉(zhuǎn)化為數(shù)值,就進(jìn)行數(shù)值比較,否則就進(jìn)行字符串比較。
第二類條件標(biāo)記定義了兩個(gè)標(biāo)記:
l <logic:present>
l <logic:notPresent>
它們的功能是在計(jì)算標(biāo)記體之前判斷特定的項(xiàng)目是否存在。標(biāo)記的屬性和屬性值決定了要進(jìn)行檢查的項(xiàng)目。
屬性 |
描述 |
Cookie |
由這個(gè)屬性指定的cookie將被檢查是否存在 |
Header |
由這個(gè)屬性指定的請(qǐng)求標(biāo)頭將被檢查是否存在 |
parameter |
由這個(gè)屬性指定的請(qǐng)求參數(shù)將被檢查是否存在 |
Name |
如果沒有設(shè)置property屬性,那么有這個(gè)屬性指定的bean將被檢查是否存在。如果設(shè)置了,那么bean和bean屬性都將被檢查是否存在。 |
property |
檢查有name屬性指定的bean中是否存在指定的屬性 |
Scope |
如果指定了bean的名稱,這就是bean的作用域。如果沒有指定作用域,搜索的范圍從頁(yè)到應(yīng)用程序作用域。 |
Role |
檢查當(dāng)前已經(jīng)確認(rèn)的用戶是否屬于特殊的角色 |
User |
檢查當(dāng)前已經(jīng)確認(rèn)的用戶是否有特定的名稱 |
例如:
<logic:notPresent name=”bean” property=”prop” scope=”page”>
The bean property bean.prop is present
</logic:notPresent>
標(biāo)記判斷在頁(yè)作用域中是否存在一個(gè)名為”bean”的bean,這個(gè)bean有一個(gè)prop屬性。
第三類條件標(biāo)記比較復(fù)雜,這些標(biāo)記根據(jù)模板匹配的結(jié)果檢查標(biāo)記體的內(nèi)容。換句話說,這些標(biāo)記判斷一個(gè)指定項(xiàng)目的值是否是一個(gè)特定常數(shù)的子字符串:
l <logic:match>
l <logic:notMatch>
這些標(biāo)記允許JSP引擎在發(fā)現(xiàn)了匹配或是沒有發(fā)現(xiàn)時(shí)計(jì)算標(biāo)記主體。屬性如下:
屬性 |
描述 |
Cookie |
要進(jìn)行比較的HTTP cookie的名稱 |
Header |
要進(jìn)行比較的的HTTP標(biāo)頭 的名稱 |
parameter |
要進(jìn)行比較的的HTTP請(qǐng)求參數(shù)的名稱 |
Name |
若要對(duì)bean或bean的屬性進(jìn)行比較,這個(gè)屬性是用戶指定bean的名稱 |
location |
如果設(shè)置了這個(gè)屬性的值,將會(huì)在這個(gè)指定的位置(索引值)進(jìn)行匹配 |
scope |
如果對(duì)bean進(jìn)行比較,這個(gè)屬性指定了bean的作用域。如果沒有設(shè)置這個(gè)參數(shù),搜索范圍是從頁(yè)到應(yīng)用程序作用域 |
property |
要進(jìn)行比較的bean的屬性名稱 |
value |
要進(jìn)行比較的常數(shù)值 |
例如:
<logic:match parameter=”name” value=”xyz” location=”1”>
The parameter name is a sub-string of the string xyz from index 1
</logic:match>
標(biāo)記檢查名為”name”的請(qǐng)求參數(shù)是否是”xyz”的子字符串,但是子字符串必須從”xyz”的索引位置1開始(也就是說子字符串必須是”y”或”yz”)。
重復(fù)標(biāo)記
在邏輯標(biāo)記庫(kù)中定義了<logic:iterate>標(biāo)記,它能夠根據(jù)特定集合中元素的數(shù)目對(duì)標(biāo)記體的內(nèi)容進(jìn)行重復(fù)的檢查。集合的類型可以是java.util.Iterator,java.util.Collection
,java.util.Map或是一個(gè)數(shù)組。有三種方法可以定義這個(gè)集合:
l 使用運(yùn)行時(shí)間表達(dá)式來返回一個(gè)屬性集合的集合
l 將集合定義為bean,并且使用name屬性指定存儲(chǔ)屬性的名稱。
l 使用name屬性定義一個(gè)bean,并且使用property屬性定義一個(gè)返回集合的bean屬性。
當(dāng)前元素的集合會(huì)被定義為一個(gè)頁(yè)作用域的bean。屬性如下,所有這些屬性都能使用運(yùn)行時(shí)表達(dá)式。
屬性 |
描述 |
collection |
如果沒有設(shè)置name屬性,它就指定了要進(jìn)行重復(fù)的集合 |
Id |
頁(yè)作用域bean和腳本變量的名稱,它保存著集合中當(dāng)前元素的句柄 |
indexed |
頁(yè)作用域JSP bean的名稱,它包含著每次重復(fù)完成后集合的當(dāng)前索引 |
Length |
重復(fù)的最大次數(shù) |
Name |
作為集合的bean的名稱,或是一個(gè)bean名稱,它由property屬性定義的屬性,是個(gè)集合 |
Offset |
重復(fù)開始位置的索引 |
property |
作為集合的Bean屬性的名稱 |
Scope |
如果指定了bean名稱,這個(gè)屬性設(shè)置bean的作用域。若沒有設(shè)置,搜索范圍從頁(yè)到應(yīng)用程序作用域 |
Type |
為當(dāng)前定義的頁(yè)作用域bean的類型 |
例如:
<logic:iterate id=”currentInt”
collection=”<% =myList %>”
type=”java.lang.Integer”
offset=”1”
length=”2”>
<% =currentint %>
</logic:iterate>
代碼將從列表中的第一個(gè)元素開始重復(fù)兩個(gè)元素并且能夠讓當(dāng)前元素作為頁(yè)作用域和java.lang.Integer類型的腳本變量來使用。也就是說,如果myList包含元素1,2,3,4等,代碼將會(huì)打印1和2。
轉(zhuǎn)發(fā)和重定向標(biāo)記
轉(zhuǎn)發(fā)標(biāo)記
<logic:forward>標(biāo)記能夠?qū)㈨憫?yīng)轉(zhuǎn)發(fā)給重定向到特定的全局ActionForward上。ActionForward的類型決定了是使用PageContext轉(zhuǎn)發(fā)響應(yīng),還是使用sendRedirect將響應(yīng)進(jìn)行重定向。此標(biāo)記只有一個(gè)”name”屬性,用來指定全局ActionForward的名稱,例如:
<logic:forward name=”myGlobalForward”/>
重定向標(biāo)記
<logic:redirect>標(biāo)記是一個(gè)能夠執(zhí)行HTTP重定向的強(qiáng)大工具。根據(jù)指定的不同屬性,它能夠通過不同的方式實(shí)現(xiàn)重定向。它還允許開發(fā)人員指定重定向URL的查詢參數(shù)。屬性如下:
屬性 |
描述 |
Forward |
映射了資源相對(duì)路徑的ActionForward |
Href |
資源的完整URL |
Page |
資源的相對(duì)路徑 |
Name |
Map類型的頁(yè)名稱,請(qǐng)求,會(huì)話或程序?qū)傩缘拿Q,其中包含要附加大哦重定向URL(如果沒有設(shè)置 property屬性)上的“名稱-值”參數(shù)。或是具有Map類型屬性的bean名稱,其中包含相同的信息(沒有設(shè)置property屬性) |
Property |
Map類型的bean屬性的名稱。Bean的名稱由name屬性指定。 |
Scope |
如果指定了bean的名稱,這個(gè)屬性指定搜索bean的范圍。如果沒有設(shè)置,搜索范圍從頁(yè)到應(yīng)用程序作用域 |
ParamID |
定義特定查詢參數(shù)的名稱 |
ParamName |
字符串類型的bean的名稱,其中包含查詢參數(shù)的值(如果沒有設(shè)置paramProperty屬性);或是一個(gè)bean的名稱,它的屬性(在paramProperty屬性中指定)包含了查詢參數(shù)值 |
paramProperty |
字符串bean屬性的名稱,其中包含著查詢參數(shù)的值 |
ParamScope |
ParamName定義的bean的搜索范圍 |
使用這個(gè)標(biāo)記時(shí)至少要指定forward,href或page中的一個(gè)屬性,以便標(biāo)明將響應(yīng)重定向到哪個(gè)資源。
HTML標(biāo)記
Struts HTML標(biāo)記可以大致地分為以下幾個(gè)功能:
l 顯示表單元素和輸入控件
l 顯示錯(cuò)誤信息
l 顯示其他HTML元素
顯示表單元素和輸入控件
struts將HTML表單與為表單操作而定義的ActionForm bean緊密聯(lián)系在一起。表單輸入字段的名稱與ActionForm bean里定義的屬性名稱是對(duì)應(yīng)的。當(dāng)?shù)谝淮物@示表單時(shí),表單的輸入字段是從ActionForm bean中移植過來的,當(dāng)表單被提交時(shí),請(qǐng)求參數(shù)將移植到ActionForm bean實(shí)例。
所有可以在<form>標(biāo)記中使用的用來顯示HTML輸入控件的內(nèi)嵌標(biāo)記都使用下列屬性來定義JavaScript事件處理器。
屬性 |
描述 |
Onblur |
字段失去了焦點(diǎn) |
Onchange |
字段失去了焦點(diǎn)并且數(shù)值被更改了 |
Onclick |
字段被鼠標(biāo)點(diǎn)擊 |
Ondblclick |
字段被鼠標(biāo)雙擊 |
Onfocus |
字段接收到輸入焦點(diǎn) |
Onkeydown |
字段擁有焦點(diǎn)并且有鍵按下 |
onkeypress |
字段擁有焦點(diǎn)并且有鍵按下并釋放 |
Onkeyup |
字段擁有焦點(diǎn)并且有鍵被釋放 |
onmousedown |
鼠標(biāo)指針指向字段并且點(diǎn)擊 |
onmousemove |
鼠標(biāo)指針指向字段并且在字段內(nèi)移動(dòng) |
onmouseout |
鼠標(biāo)指針指向控件,但是指針在元素外圍移動(dòng) |
onmouseover |
鼠標(biāo)指針沒有指向字段,但是指針在元素內(nèi)部移動(dòng) |
Onmouseup |
鼠標(biāo)指針指向字段,并且釋放了鼠標(biāo)按鍵 |
<form>元素中能夠被定義的其他一般屬性有:
屬性 |
描述 |
Accesskey |
定義訪問輸入字段的快捷鍵 |
Style |
定義輸入字段的樣式 |
styleClass |
定義輸入字段的樣式表類 |
Tabindex |
輸入字段的tab順序 |
表單標(biāo)記
<html:form>標(biāo)記用來顯示HTML標(biāo)記,可以指定AcitonForm bean的名稱和它的類名。如果沒有設(shè)置這些屬性,就需要有配置文件來指定ActionMapping以表明當(dāng)前輸入的是哪個(gè)JSP頁(yè),以及從映射中檢索的bean名和類。如果在ActionMapping指定的作用域中沒有找到指定的名稱,就會(huì)創(chuàng)建并存儲(chǔ)一個(gè)新的bean,否則將使用找到的bean。
<form>標(biāo)記能夠包含與各種HTML輸入字段相對(duì)應(yīng)的子標(biāo)記。
<html:form>標(biāo)記屬性如下:
屬性 |
描述 |
Action |
與表單相關(guān)的操作。在配置中,這個(gè)操作也用來標(biāo)識(shí)與表單相關(guān)的ActionForm bean |
Enctype |
表單HTTP方法的編碼類型 |
Focus |
表單中需要初始化焦點(diǎn)的字段 |
Method |
表單使用的HTTP方法 |
Name |
與表單相關(guān)的ActionForm bean的名稱。如果沒有設(shè)置這個(gè)屬性,bean的名稱將會(huì)從配置信息中獲得 |
Onreset |
表單復(fù)位時(shí)的JavaScript事件句柄 |
Onsubmit |
表單提交時(shí)的JavaScript事件句柄 |
Scope |
搜索ActionForm bean的范圍。如果沒有設(shè)置,將從配置文件中獲取 |
Style |
使用的格式 |
styleClass |
這個(gè)元素的格式表類 |
Type |
ActionForm bean的完整名稱。如果沒有設(shè)置,將從配置文件獲得 |
例如:
<html:form action=”validateEmploee.do” method=”post”>
</html:form>
與表單相關(guān)的操作路徑是validateEmployee,而表單數(shù)據(jù)是通過POST傳遞的。對(duì)于這個(gè)表單來說,ActionForm bean的其他信息,如bean名稱類型,作用域,都是從表單指定操作的ActionMapping中檢索得到的:
<form-bean name=”empForm” type=”com.example.EmployeeForm”/>
</form-beans>
<action-mappings>
<action path=”/validateEmployee”
type=”com.example.ValidateExampleAction”
name=”empForm”
scope=”request”
input=”/employeeInput.jsp”>
<forward name=”success” path=”/employeeOutput.jsp”>
</action>
</action-mapping>
如果配置文件中包含上述信息,并且請(qǐng)求URI的*.do被映射到ActionServlet,與表單相關(guān)的ActionForm bean的名稱,類型和作用域分別是empForm,com.example.EmployeeForm和request.這些屬性也可以使用<html:form>標(biāo)記屬性進(jìn)行顯示的定義。
以下標(biāo)記必須嵌套在<html:form>標(biāo)記里
按鈕和取消標(biāo)記
<html:button>標(biāo)記顯示一個(gè)按鈕控件;<html:cancel>標(biāo)記顯示一個(gè)取消按鈕。屬性如下:
屬性 |
描述 |
Property |
定義在表單被提交時(shí)返回到服務(wù)器的請(qǐng)求參數(shù)的名稱 |
Value |
按鈕上的標(biāo)記 |
復(fù)位和提交標(biāo)記
<html:reset>和<html:submit>標(biāo)記分別能夠顯示HTML復(fù)位按鈕和提交按鈕。
文本和文本區(qū)標(biāo)記
<html:text>和<html:textarea>標(biāo)記分別HTML文本框和文本區(qū),屬性如下:
屬性 |
描述 |
Property |
定義當(dāng)表單被提交時(shí)送回到服務(wù)器的請(qǐng)求參數(shù)的名稱,或用來確定文本元素當(dāng)前值的bean的屬性名稱 |
Name |
屬性被查詢的bean的名稱,它決定了文本框和文本區(qū)的值。如果沒有設(shè)置,將使用與這個(gè)內(nèi)嵌表單相關(guān)的ActionForm的名稱 |
<html:text>標(biāo)記還有以下屬性:
屬性 |
描述 |
Maxlength |
能夠輸入的最大字符數(shù) |
Size |
文本框的大小(字符數(shù)) |
<html:textarea>標(biāo)記特有的屬性如下:
屬性 |
描述 |
Rows |
文本區(qū)的行數(shù) |
Cols |
文本區(qū)的列數(shù) |
檢查框和復(fù)選框標(biāo)記
<html:checkbox>標(biāo)記能夠顯示檢查框控件。<html:multibox>標(biāo)記能夠顯示HTML復(fù)選框控件,請(qǐng)求對(duì)象在傳遞檢查框名稱時(shí)使用的getParameterValues()調(diào)用將返回一個(gè)字符串?dāng)?shù)組。屬性如下:
屬性 |
描述 |
Name |
Bean的名稱,其屬性會(huì)被用來確定檢查是否以選中的狀態(tài)顯示。如果沒有設(shè)置,將使用與這個(gè)內(nèi)嵌表單相關(guān)的ActionFrom bean的名稱。 |
Property |
檢查框的名稱,也是決定檢查框是否以選中的狀態(tài)顯示的bean屬性名稱。在復(fù)選框的情況下,這個(gè)屬性必須是一個(gè)數(shù)組。 |
Value |
當(dāng)檢查框被選中時(shí)返回到服務(wù)器的請(qǐng)求參數(shù)的值 |
例如:
<html:checkbox property=”married” value=”Y”/>
一個(gè)名為married的檢查框,在表單提交時(shí)會(huì)返回一個(gè)”Y”.
文件標(biāo)記
<html:file>標(biāo)記可以顯示HTML文件控件。屬性如下:
屬性 |
描述 |
Name |
Bean的名稱,它的屬性將確定文件控件中顯示的內(nèi)容。如果沒設(shè)置,將使用與內(nèi)嵌表單相關(guān)的ActionForm bean的名稱 |
property |
這個(gè)屬性定義了當(dāng)表單被提交時(shí)送回到服務(wù)器的請(qǐng)求參數(shù)的名稱,以及用來確定文件控件中顯示內(nèi)容的bean屬性名稱 |
Accept |
服務(wù)器能夠處理的內(nèi)容類型集。它也將對(duì)客戶瀏覽器對(duì)話框中的可選文件類型進(jìn)行過濾 |
Value |
按鈕上的標(biāo)記,這個(gè)按鈕能夠在本地文件系統(tǒng)中瀏覽文件 |
單選鈕標(biāo)記
<html:radio>標(biāo)記用來顯示HTML單選鈕控件,屬性如下:
屬性 |
描述 |
Name |
Bean的名稱,其屬性會(huì)被用來確定單選鈕是否以選中的狀態(tài)顯示。如果沒有設(shè)置,將使用與這個(gè)內(nèi)嵌表單相關(guān)的ActionFrom bean的名稱。 |
property |
當(dāng)表單被提交時(shí)送回到服務(wù)器的請(qǐng)求參數(shù)的名稱,以及用來確定單選鈕是否以被選中狀態(tài)進(jìn)行顯示的bean屬性的名稱 |
Value |
當(dāng)單選鈕被選中時(shí)返回到服務(wù)器的值 |
隱藏標(biāo)記
<html:hidden>標(biāo)記能夠顯示HTML隱藏輸入元素,屬性如下:
屬性 |
描述 |
Name |
Bean的名稱,其屬性會(huì)被用來確定隱藏元素的當(dāng)前值。如果沒有設(shè)置,將使用與這個(gè)內(nèi)嵌表單相關(guān)的ActionFrom bean的名稱。 |
property |
定義了當(dāng)表單被提交時(shí)送回到服務(wù)器的請(qǐng)求參數(shù)的名稱,以及用來確定隱藏元素當(dāng)前值的bean屬性的名稱 |
Value |
用來初始化隱藏輸入元素的值 |
密碼標(biāo)記
<html:password>標(biāo)記能夠顯示HTML密碼控件,屬性如下:
屬性 |
描述 |
maxlength |
能夠輸入的最大字符數(shù) |
Name |
Bean的名稱,它的屬性將用來確定密碼元素的當(dāng)前值。如果沒有設(shè)置,將使用與這個(gè)內(nèi)嵌表單相關(guān)的ActionFrom bean的名稱。 |
property |
定義了當(dāng)表單被提交時(shí)送回到服務(wù)器的請(qǐng)求參數(shù)的名稱,以及用來確定密碼元素當(dāng)前值的bean屬性的名稱 |
redisplay |
在顯示這個(gè)字段時(shí),如果相應(yīng)的bean屬性已經(jīng)被設(shè)置了數(shù)據(jù),這個(gè)屬性決定了是否顯示密碼的內(nèi)容 |
Size |
字段的大小 |
選擇標(biāo)記
<html:select>標(biāo)記能夠顯示HTML選擇控件,屬性如下:
屬性 |
描述 |
multiple |
表明這個(gè)選擇控件是否允許進(jìn)行多選 |
Name |
Bean的名稱,它的屬性確定了哪個(gè)。如果沒有設(shè)置,將使用與這個(gè)內(nèi)嵌表單相關(guān)的ActionFrom bean的名稱。 |
property |
定義了當(dāng)表單被提交時(shí)送回到服務(wù)器的請(qǐng)求參數(shù)的名稱,以及用來確定哪個(gè)選項(xiàng)需要被選中的bean屬性的名稱 |
Size |
能夠同時(shí)顯示的選項(xiàng)數(shù)目 |
Value |
用來表明需要被選中的選項(xiàng) |
選項(xiàng)標(biāo)記(這個(gè)元素需要嵌套在<html:select>標(biāo)記里)
<html:option>標(biāo)記用來顯示HTML選項(xiàng)元素集合,屬性如下:
屬性 |
描述 |
collection |
Bean集合的名稱,這個(gè)集合存儲(chǔ)在某個(gè)作用域的屬性中。選項(xiàng)的數(shù)目與集合中元素的數(shù)目相同。Property屬性能夠定義選項(xiàng)值所使用的bean屬性,而labelProperty屬性定義選項(xiàng)標(biāo)記所使用的bean的屬性 |
labelName |
用來指定存儲(chǔ)于某個(gè)作用域的bean,這個(gè)bean是一個(gè)字符串的集合,能夠定義<html:option>元素的標(biāo)記(如果標(biāo)志與值不相同) |
labelProperty |
與collection屬性共同使用時(shí),用來定義了存儲(chǔ)于某個(gè)作用域的bean,這個(gè)bean將返回一個(gè)字符串集合,能夠用來寫入<html:option>元素的value屬性 |
Name |
如果這是唯一被指定的屬性,它就定義了存儲(chǔ)于某個(gè)作用域的bean,這個(gè)bean將返回一個(gè)字符串集合,能夠用來寫入<html:option>元素的value屬性 |
property |
這個(gè)屬性在與collection屬性共同使用時(shí),定義了每個(gè)要顯示選項(xiàng)值的獨(dú)立bean的name屬性。如果不是與collection屬性共同使用,這個(gè)屬性定義了由name屬性指定的bean的屬性名稱(如果有name屬性),或是定義了一個(gè)ActionForm bean,這個(gè)bean將返回一個(gè)集合來寫入選項(xiàng)的值 |
我們看一下這個(gè)標(biāo)記的一些例子:
<html:option collection=”optionCollection” property=”optionValue”
labelProperty=”optionLabel”/>
標(biāo)記假設(shè)在某個(gè)作用域中有一個(gè)名為optionCollection的集合,它包含了一些具有optionValue屬性的獨(dú)立的bean,每個(gè)屬性將作為一個(gè)選項(xiàng)的值。每個(gè)選項(xiàng)的標(biāo)志由bean的optionLabel屬性屬性進(jìn)行定義。
<html:option name=”optionValues” labelName=”optionLabels”/>
標(biāo)記中optionValues代表一個(gè)存儲(chǔ)在某個(gè)作用域中的bean,它是一個(gè)字符串集合,能夠用來寫入選項(xiàng)的值,而optionLabels代表一個(gè)存儲(chǔ)在某個(gè)作用域中的bean,它也是一個(gè)字符串集合,能夠用來寫入選項(xiàng)的標(biāo)志。
顯示錯(cuò)誤信息的標(biāo)記
<html:errors>標(biāo)記能夠與ActionErrors結(jié)合在一起來顯示錯(cuò)誤信息。這個(gè)標(biāo)記首先要從當(dāng)前區(qū)域的資源文件中讀取消息關(guān)鍵字errors.header,然后顯示消息的文本。接下去它會(huì)在ActionErrors對(duì)象(通常作為請(qǐng)求參數(shù)而存儲(chǔ)在Action.ERROR_KEY關(guān)鍵字下)中循環(huán),讀取單個(gè)ActionError對(duì)象的消息關(guān)鍵字,從當(dāng)前區(qū)域的資源文件中讀取并格式化相應(yīng)的消息,并且顯示它們。然后它讀取與errors.footer關(guān)鍵字相對(duì)應(yīng)的消息并且顯示出來。
通過定義property屬性能夠過濾要顯示的消息,這個(gè)屬性的值應(yīng)該與ActionErrors對(duì)象中存儲(chǔ)ActionError對(duì)象的關(guān)鍵字對(duì)應(yīng)。屬性如下:
屬性 |
描述 |
Bundle |
表示應(yīng)用程序作用域?qū)傩缘拿Q,它包含著消息資源,其默認(rèn)值Acion.MESSAGE_KEY |
Locale |
表示會(huì)話作用域?qū)傩缘拿Q,它存儲(chǔ)著用戶當(dāng)前登錄的區(qū)域信息。其默認(rèn)值是Action.ERROR_KEY |
Name |
表示請(qǐng)求屬性的名稱,它存儲(chǔ)著ActionErrors對(duì)象。其默認(rèn)值是Action.ERROR_KEY |
property |
這個(gè)屬性指定了ActionErrors對(duì)象中存儲(chǔ)每個(gè)獨(dú)立ActionError對(duì)象的關(guān)鍵字,它可以過濾消息 |
例子:
<html:errors/>
顯示集合中所有的錯(cuò)誤。
<html:errors property=”missing.name”/>
顯示存儲(chǔ)在missing.name關(guān)鍵字的錯(cuò)誤。
其他HTML標(biāo)記
struts HTML標(biāo)記還定義了下列標(biāo)記來顯示其他HTML元素:
l <html:html> : 顯示HTML元素
l <html:img> : 顯示圖象標(biāo)記
l <html:link> : 顯示HTML鏈接或錨點(diǎn)
l <html:rewrite> : 創(chuàng)建沒有錨點(diǎn)標(biāo)記的URI
這些標(biāo)記的詳細(xì)內(nèi)容請(qǐng)參照struts文檔。
模板標(biāo)記
動(dòng)態(tài)模板是模塊化WEB頁(yè)布局設(shè)計(jì)的強(qiáng)大手段。Struts模板標(biāo)記庫(kù)定義了自定義標(biāo)記來實(shí)現(xiàn)動(dòng)態(tài)模板。
插入標(biāo)記
<template:insert>標(biāo)記能夠在應(yīng)用程序的JSP頁(yè)中插入動(dòng)態(tài)模板。這個(gè)標(biāo)記只有一個(gè)template屬性,用來定義模板JSP頁(yè)。要插入到模板的頁(yè)是有多個(gè)<template:put>標(biāo)記來指定的,而這些標(biāo)記被定義為<template:insert>標(biāo)記的主體內(nèi)容。
放置標(biāo)記
<template:put>標(biāo)記是<template:insert>標(biāo)記內(nèi)部使用的,用來指定插入到模板的資源。屬性如下:
屬性 |
描述 |
content |
定義要插入的內(nèi)容,比如一個(gè)JSP文件或一個(gè)HTML文件 |
direct |
如果這個(gè)設(shè)置為true,由content屬性指定的內(nèi)容將直接顯示在JSP上而不是作為包含文件 |
Name |
要插入的內(nèi)容的名稱 |
Role |
如果設(shè)置了這個(gè)屬性,只有在當(dāng)前合法用戶具有特定角色時(shí)才能進(jìn)行內(nèi)容的插入。 |
獲得標(biāo)記
在模板JSP頁(yè)中使用<template:get>標(biāo)記能夠檢索由<template:put>標(biāo)記插入到JSP頁(yè)的資源。屬性如下:
屬性 |
描述 |
Name |
由<template:put>標(biāo)記插入的內(nèi)容的名稱 |
Role |
如果設(shè)置了這個(gè)屬性,只有在當(dāng)前合法用戶具有特定角色時(shí)才能進(jìn)行內(nèi)容的檢索 |
使用模板標(biāo)記
首先編寫一個(gè)模板JSP頁(yè),它將被所有的web頁(yè)使用:
<%@ taglib uri=”/template” prefix=”template” %>
<head>
<title></title>
</head>
<body>
<table width=”100%” height=”100%” >
<td>
<template:get name=”header”/>
</td>
</tr>
<tr height=”80%”>
<td>
<template:get name=”content”/>
</td>
</tr>
<tr height=”10%”>
<td>
<template:get name=”footer”/>
</td>
</tr>
</body>
我們將這個(gè)文件命名為template.jsp。這個(gè)文件使用<template:get>標(biāo)記來獲得由JSP頁(yè)使用<template:put>標(biāo)記提供的內(nèi)容,并且將內(nèi)容在一個(gè)HTML表格中顯示出來。這三個(gè)內(nèi)容是標(biāo)題,內(nèi)容和頁(yè)腳。典型的內(nèi)容JSP會(huì)是這樣:
<%@ taglib uri=”/template” prefix=”/template” %>
<template:insert template=”template.jsp”>
<template:put name=”header” content=”header.html”/>
<template:put name=”content” content=”employeeList.jsp”/>
<template:put name=”footer” content=”footer.html”/>
這個(gè)應(yīng)用程序JSP頁(yè)使用<template:insert標(biāo)記來定義模板,然后使用<template:put>標(biāo)記將特定內(nèi)容名稱指定的資源放到模板JSP頁(yè)中。如果我們有上百個(gè)布局相同的頁(yè),但突然想改變這個(gè)模板,我們只需要改變template.jsp文件。
一個(gè)簡(jiǎn)單的示例
在這個(gè)指導(dǎo)中我們將step by step開發(fā)一個(gè)小的應(yīng)用程序。你應(yīng)該有一些JSP和XML的經(jīng)驗(yàn),并且有一個(gè)可以運(yùn)行的應(yīng)用服務(wù)器。
Struts的安裝
請(qǐng)先將Struts.jar和所有相關(guān)common拷貝到你應(yīng)用程序的lib目錄中,不用刪除你的struts目錄中的其他文件。結(jié)果如圖1所示。
第一個(gè)實(shí)驗(yàn):簡(jiǎn)單的JSP頁(yè)
現(xiàn)在我們要做一個(gè)簡(jiǎn)單的JSP頁(yè),用來確認(rèn)至此我們的操作是正確的。
在strutsShop里建一個(gè)BookView.jsp的文件。內(nèi)容如下,按圖2所示在瀏覽器中運(yùn)行:
第二個(gè)實(shí)驗(yàn):struts的國(guó)際化
我們將使用戶能用本國(guó)的語(yǔ)言瀏覽預(yù)定義的文本,進(jìn)而接觸一些struts的功能。首先你要按照?qǐng)D3拷貝一些文件到WEB-INF目錄下。在struts-html.tld文件里有我們要用的標(biāo)簽。這些我們?cè)谏辖右呀?jīng)介紹了,你可以簡(jiǎn)短的回顧一下。
struts-config.xml的配置清單如下,這是一個(gè)標(biāo)準(zhǔn)的清單,你以后的程序都可以以此為基礎(chǔ)進(jìn)行擴(kuò)展:
web.xml的配置清單如下,這是一個(gè)標(biāo)準(zhǔn)的清單,你以后的程序都可以以此為基礎(chǔ)進(jìn)行擴(kuò)展:
在classes目錄下創(chuàng)建一個(gè)ApplicationResources.properties的文件(此文件名在web.xml中定義),打開它,輸入一行:index.title=Struts Tutorial。然后在創(chuàng)建一個(gè)ApplicationResources_de.properties文件,也輸入一行:index.title=Struts Einführung。其實(shí)這兩個(gè)文件就是當(dāng)加載時(shí)會(huì)根據(jù)當(dāng)前的瀏覽器而選擇英文或德文,這里我們只能了解國(guó)際化過程來測(cè)試前者了。我們還需編寫BookView.jsp文件,如下:
可在瀏覽器中瀏覽,你可能需要重啟你的tomcat:
其實(shí)我們可以將國(guó)際化寫在一個(gè)文件中,就是將參數(shù)寫在一個(gè)屬性文件中。(這是作者的意圖,但我沒有各種版本的IE進(jìn)行實(shí)驗(yàn))
struts中的Forms
在這一章我們將創(chuàng)建一個(gè)簡(jiǎn)單的Bean(Book.java)和兩個(gè)JSP頁(yè)面,一個(gè)是創(chuàng)建新書的,另一個(gè)是顯示它的,我們也會(huì)第一次使用struts-config.xml文件。
我們先在你的classes目錄下創(chuàng)建如下Book.java文件。
我們還需要?jiǎng)?chuàng)建新書的JSP頁(yè)。我們將使用title,auther和number of pages三個(gè)字段,在此之前我們先要做一些工作,對(duì)于一個(gè)初學(xué)者這將有些難度。在你的BookView中加上以下內(nèi)容:
再次運(yùn)行,你將得到圖5所示內(nèi)容,如果沒有錯(cuò),那你需要重啟tomcat;如果錯(cuò)誤不一樣,沒關(guān)系,因?yàn)樗际菦]有在配置文件中找到mapping路徑。
接下來我們需要第二個(gè)JSP頁(yè)面CreateBook.jsp,代碼如下:
在classes目錄下創(chuàng)建一個(gè)BookAction文件:
它沒按照struts要求編寫僅僅創(chuàng)建一本書并給它標(biāo)題。然后編寫你的struts-config.xml:
我們希望在struts中在bookForm和Book間建立連接。而且我們還用bookCreated定義了一個(gè)到BookView.jsp的轉(zhuǎn)發(fā)。最后我們用action=createBook.do屬性定義了我們的form做什么。關(guān)于do:與接受CreateBook.jsp輸入信息的bookForm相關(guān)的bean,由createBook命令創(chuàng)建。
按圖6編譯你的類。由于我是初手,在這里遇見很多問題,所以耽誤了很久,不過它讓你學(xué)到很多東東。比如:javax.servlet要用到servlet.jar包;javac后跟a.java, 而java后跟a;還有我遇見了很原文提到的問題,很多都是由于自己編寫(沒有copy)而造成的馬虎。希望大家也能引起注意,到此除了ActionForm我們都已用到了。
編譯成功后,在你的classes目錄下會(huì)增加兩個(gè)文件:Book.class和BookAction.class.
重啟你的tomcat(每次改動(dòng)config文件你都需要重啟,改動(dòng)注冊(cè)表需要重啟機(jī)器)。現(xiàn)在在你的瀏覽器里登陸CreateBook.jsp,如圖7:
當(dāng)你填寫后提交,另你失望的是什么也沒有得到。這是由于我們并沒有ActionForm bean.
struts:介紹ActionForm
這節(jié)我們繼續(xù)做ActionForm bean來完成我們的例子。我們將用ActionForm得到合法的book的信息,并進(jìn)行一些檢驗(yàn),例如沒有輸入標(biāo)題等,向用戶提供錯(cuò)誤或成功的信息。我們還將得到book的屬性并且能夠更改它。
為此我們需要一個(gè)ActionForm:它僅是一個(gè)簡(jiǎn)單的容器,沒有應(yīng)用程序邏輯,只有兩個(gè)方法:reset(),validate().在struts1.1里,validate()方法被單獨(dú)作為一個(gè)validate.xml文件。詳見參考資料二。
現(xiàn)在我們做另一個(gè)類:BookForm.java。它將包含book的實(shí)例,并且有一些getXXX和setXXX的方法來訪問它。關(guān)于內(nèi)部的方法可看struts架構(gòu)介紹。
我們還要做一些額外的工作。去看struts-config.xml文件,我們需要用這個(gè)新類與Form關(guān)聯(lián),從而替代Book.java。因此我們必須改變form-beans: <form-bean name="bookForm" type="BookForm"/>.
另外我們還有定義一下當(dāng)錯(cuò)誤發(fā)生時(shí)的信息,在你的配置文件中輸入:error.book.title=Error
現(xiàn)在編譯你的類,重新啟動(dòng)tomcat,重新登陸CreateBook.jsp.,輸入onebook,你將在tomcat的dos窗口看見如下圖所示:
你也可以在重輸入其他的title,看看tomcat的dos窗口有什么變化。
分離Book和BookForm的一個(gè)好方法
上一節(jié)我們使用一個(gè)新類BookForm.java去訪問Book.java,而不用struts直接連接到Book.java。接下來,我們要解決在這兩個(gè)類中重復(fù)輸入getXXX和setXXX。Struts允許我們直接訪問實(shí)例的方法。這很容易,但需要理解。我們給出改變的CreateBook.jsp的代碼:
正如你看到的,除了將title改為book.title,我們什么也沒做。現(xiàn)在你可以去掉BookForm.java中的getXXX和setXXX方法了,如下圖:(別忘記了也更改BookView.jsp,否則在你的tomcat窗口下After creation of book : null)
你還應(yīng)該改動(dòng)BookAction.java,把String title = req.getParameter("title");中的title改為book.title,然后重新編譯,這樣你的tomcat下的After creation of book :none中的none就會(huì)出現(xiàn)你輸入的名了。