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