|
Struts教程
概述本文主要講解什么是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概念一直以來(lái)我們都說(shuō)Struts是一個(gè)Web Framework。那么讓我么先來(lái)看看什么是Framework。 Framework概念并不是很新了,伴隨著軟件開發(fā)的發(fā)展,在多層的軟件開發(fā)項(xiàng)目中,可重用、易擴(kuò)展的,而且是經(jīng)過(guò)良好測(cè)試的軟件組件,越來(lái)越為人們所青睞。這意味著人們可以將充裕的時(shí)間用來(lái)分析、構(gòu)建業(yè)務(wù)邏輯的應(yīng)用上,而非繁雜的代碼工程。于是人們將相同類型問(wèn)題的解決途徑進(jìn)行抽象,抽取成一個(gè)應(yīng)用框架。這也就是我們所說(shuō)的Framework。 Framework的體系提供了一套明確機(jī)制,從而讓開發(fā)人員很容易的擴(kuò)展和控制整個(gè)Framework開發(fā)上的結(jié)構(gòu)。 通常,F(xiàn)ramework的結(jié)構(gòu)中都有一個(gè)“命令和控制”組件("command and control" component)——Framework Factory and Manager。 Framework體系
通過(guò)基于請(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本身來(lái)說(shuō),這里僅僅只是概念和幾個(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ù)訪問(wèn)接口。對(duì)于數(shù)據(jù)邏輯來(lái)說(shuō),如果你了解數(shù)據(jù)建模(Data Modeling)可能就很容易理解。
Struts的概念和體系結(jié)構(gòu)Struts有一組相互協(xié)作的類、Serlvet以及Jsp TagLib組成?;赟truts構(gòu)架的web應(yīng)用程序基本上符合JSP Model2的設(shè)計(jì)標(biāo)準(zhǔn),可以說(shuō)是MVC設(shè)計(jì)模式的一種變化類型。根據(jù)上面對(duì)framework的描述,我們很容易理解為什么說(shuō)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ù)訪問(wèn)技術(shù)相結(jié)合,包括EJB,JDBC和Object Relation Bridge。在視圖層,Struts能夠與JSP, Velocity Templates,XSL等等這些表示層組件想結(jié)合。 Struts的與Web App的關(guān)系
Struts與WebApp的關(guān)系
Struts的體系結(jié)構(gòu)我們說(shuō)struts framework是MVC 模式的體現(xiàn),下面我們就從分別從模型、視圖、控制來(lái)看看struts的體系結(jié)構(gòu)(Architecture)。下圖顯示了struts framework的體系結(jié)構(gòu)響應(yīng)客戶請(qǐng)求時(shí)候,各個(gè)部分工作的原理。
從視圖角度(View)首先,Struts提供了Java類org. apache.struts.action.ActionForm,Java開發(fā)者將該類細(xì)分來(lái)創(chuàng)建表單bean。在運(yùn)行時(shí),該bean有兩種用法: ― 當(dāng)JSP準(zhǔn)備相關(guān)的HTML,表單以進(jìn)行顯示時(shí),JSP將訪問(wèn)該 bean(它保存要放入表單中的值)。那些值是從業(yè)務(wù)邏輯或者是從先前的用戶輸入來(lái)提供的。 ― 當(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)要的介紹一下。下表說(shuō)明了目前struts api中基本的幾個(gè)組件包,包括action,actions,config,util,taglib,validator。下圖則顯現(xiàn)了這幾個(gè)組件包之間的關(guān)系。其中action是整個(gè)struts framework的核心
Struts framework的工作原理和組件對(duì)于Struts 如何控制、處理客戶請(qǐng)求,讓我們通過(guò)對(duì)struts的四個(gè)核心組件介紹來(lái)具體說(shuō)明。這幾個(gè)組件就是:ActionServlet。Action Classes,Action Mapping(此處包括ActionForward),ActionFrom Bean。 Struts ActionServlet控制器對(duì)象ActionServlet繼承自javax.servlet.http.HttpServlet類,其在Struts framework中扮演的角色是中心控制器。它提供一個(gè)中心位置來(lái)處理全部的終端請(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è)集中的訪問(wèn)點(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 ClassesActionServlet把全部提交的請(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)。
Action最為常用的是execute()方法。(注意,以前的perform方法在struts1.1中已經(jīng)不再支持),還有一個(gè)execute()方法,請(qǐng)參考apidoc,在此不在說(shuō)明。 當(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()方法如何被訪問(wèn): Action實(shí)例的execute()方法
注意,客戶自己繼承的Action子類,必須重寫execute()方法,因?yàn)锳ction類在默認(rèn)情況下是返回null的。 Struts Action Mapping上面講到了一個(gè)客戶請(qǐng)求是如何被控制器轉(zhuǎn)發(fā)和處理的,但是,控制器如何知道什么樣的信息轉(zhuǎn)發(fā)到什么樣的Action類呢?這就需要一些與動(dòng)作和請(qǐng)求信息相對(duì)應(yīng)的映射配置說(shuō)明。在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è)登陸的配置映射。
上面的配置表示:當(dāng)可以通過(guò)/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ù)牡胤?。如上面現(xiàn)實(shí),如果客戶登陸成功,則調(diào)用welcome forward,將成功信息返回到/welcome.jsp頁(yè)面。在你的execute()方法的結(jié)尾可以使用下面的實(shí)例代碼而返回welcome forward。當(dāng)然你的welcome forward必須在action元素屬性中定義,正如上面所聲明的那樣。
ActionForward對(duì)象是配置對(duì)象。這些配置對(duì)象擁有獨(dú)一無(wú)二的標(biāo)識(shí)以允許它們按照有意義的名稱如“success”,“failure”等來(lái)檢索。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(…)方法。下例舉例說(shuō)明了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。
在此稍稍說(shuō)一下有關(guān)global-forwards的概念。其在配置文件中描述了整個(gè)應(yīng)用系統(tǒng)可以使用的ActionForward,而不是僅僅是一個(gè)特定的Action。
Struts ActionForm Bean捕獲表單數(shù)據(jù)在上面講解ActionServlet,Action Classes和Action Mapping的時(shí)候,我們都提到了ActionForm Bean的概念。一個(gè)應(yīng)用系統(tǒng)的消息轉(zhuǎn)移(或者說(shuō)狀態(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ì)象,它用來(lái)表單填充;驗(yàn)證的結(jié)果應(yīng)該是一個(gè)ActionErrors對(duì)象,用org.apache.struts.taglib.html.ErrorsTag來(lái)顯示驗(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ì)在有效性過(guò)期后仍然存在。默認(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í)候用來(lái)儲(chǔ)存能夠被自定義標(biāo)簽改變的中間模型狀態(tài)。在視圖中標(biāo)簽用法避免結(jié)合Java代碼,因此要成一個(gè)好的任務(wù)劃分,web生產(chǎn)組主要處理標(biāo)志,而應(yīng)用開發(fā)組主要處理Java代碼。標(biāo)簽因素退出訪問(wèn)中間模型狀態(tài)的邏輯;當(dāng)訪問(wèn)嵌套的對(duì)象或當(dāng)通過(guò)聚集列舉時(shí)這個(gè)邏輯可能很復(fù)雜。 注意:在struts1.1中,ActionForm的校驗(yàn)功能,逐漸被剝離出來(lái)(當(dāng)然依然可以使用)。使用了validator framework對(duì)整個(gè)應(yīng)用系統(tǒng)的表單數(shù)據(jù)驗(yàn)證進(jìn)行統(tǒng)一管理。相信信息請(qǐng)參考:http://home./~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)求來(lái)說(shuō),是同一種類型的話,那么就重用。 (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等等。讓我們來(lái)看看兩個(gè)比較重要的組件:validationg framework和struts taglib。有關(guān)其他組件請(qǐng)參考Struts用戶手冊(cè)(http://jakarta./struts/userGuide)。
Validation Framework for Struts在struts1.1中,新增了validation framework。增加了對(duì)form數(shù)據(jù)提交的驗(yàn)證。將原本需要在ActionFrom Bean的validate()進(jìn)行的驗(yàn)證通過(guò)配置文件的描述進(jìn)行驗(yàn)證。 有關(guān)其詳細(xì)信息,請(qǐng)參考http://home./~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ù)難度??梢越梃bvalidation framework的Javascript Validator Tag。
Struts TagLibstruts提供了一組可擴(kuò)展的自定義標(biāo)簽庫(kù)(TagLib),可以簡(jiǎn)化創(chuàng)建用戶界面的過(guò)程。目前包括: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)定義和訪問(wèn)bean的屬性。有關(guān)詳細(xì)信息,請(qǐng)參考。 http://jakarta./commons/beanutils.html 如果各位對(duì)這方面有很興趣,可以參考一些有關(guān)java反射(Reflectio)方面的資料。 Collections這個(gè)組件主要是提供了一些集合或列表對(duì)象,在原有的java collections framework的基礎(chǔ)上進(jìn)行了擴(kuò)展。詳細(xì)資料請(qǐng)參考: http://jakarta./commons/collections.html 以及 http://cvs./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./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)镾truts Controller的主要類ActionServlet是繼承自HttpServlet,所以必須像配置一個(gè)Servlet那樣在部署描述符(Web.xml)中配置ActionServlet類及其訪問(wèn)映射。 當(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的行為由指定的配置文件來(lái)指導(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??紤]下面各種情況: ― 訪問(wèn)了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來(lái)響應(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來(lái)表示給定的標(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./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接著訪問(wèn)哪個(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舉例說(shuō)明了該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>元素中的其它屬性來(lái)處理的,并且是用戶輸入的結(jié)果或者是在different<action>元素中標(biāo)識(shí)的轉(zhuǎn)發(fā)的結(jié)果。 type 指定在發(fā)出請(qǐng)求時(shí)調(diào)用其執(zhí)行方法的操作類的全限定名。該類必須在類路徑中。 注:不指定要實(shí)例化的類,可以通過(guò)使用forward屬性來(lái)轉(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í)行方法使用完全相同 的字符串來(lái)配置返回至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>元素中的屬性來(lái)處理的,尤其是,在其path屬性標(biāo)識(shí)相同URL的<action>元素中。
有必要提一下的是,在struts1.1中,提出了對(duì)Multiple Application Support。在struts的早先版本中,只有一個(gè)struts配置文件,一般叫struts-config.xml。但是,對(duì)于越來(lái)越復(fù)雜的應(yīng)用系統(tǒng)的發(fā)展,只有一個(gè)地方存放這個(gè)一個(gè)文件,對(duì)大型項(xiàng)目來(lái)說(shuō),使用和修改這個(gè)配置文件,使其成為了一個(gè)應(yīng)用的瓶頸問(wèn)題。在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)單的問(wè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接收到來(lái)自HTML表單對(duì)“/register”的請(qǐng)求時(shí),ActionServlet將在接收用戶數(shù)據(jù)的表單bean中調(diào)用驗(yàn)證方法。此驗(yàn)證在ActionServlet訪問(wèn)操作類之前進(jìn)行。如果丟失了該方法,不會(huì)發(fā)生任何錯(cuò)誤,在該情況下,驗(yàn)證總是會(huì)成功。 l 如果發(fā)生了錯(cuò)誤,則表單bean的驗(yàn)證方法將舉例說(shuō)明錯(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 用來(lái)標(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í),最多可以包括要代入字符串中用來(lái)替代{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ò)誤的信息。通過(guò)使用相異屬性值,可以在相鄰的不同字段中顯示每條錯(cuò)誤消息而不是將所有錯(cuò)誤置于單個(gè)列表中。 使用異常處理聲明要定義應(yīng)用程序的邏輯流程,成熟的經(jīng)驗(yàn)是推薦在代碼之外,用配置的方法來(lái)實(shí)現(xiàn),而不是寫死在程序代碼中的。在J2EE中,這樣的例子比比皆是。從實(shí)現(xiàn)EJB的安全性和事務(wù)性行為到描述JMS消息和目的地之間的關(guān)系,很多運(yùn)行時(shí)的處理流程都是可以在程序之外定義的。 Struts 創(chuàng)建者從一開始就采用這種方法,通過(guò)配置Struts的配置文件來(lái)定制應(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ò)誤類來(lái)提醒用戶出現(xiàn)什么問(wè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è)該異常包含有嵌套異常,這些嵌套異常又包含了其他異常,因此我們必須覆蓋原來(lái)的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è)置。在本文中,最重要的屬性莫過(guò)于handler屬性, handler屬性的值就是自定義的繼承了ExceptionHandler類的子類的全名。假如該屬性沒有定義,Struts會(huì)采用自己的缺省值。當(dāng)然,其他的屬性也很重要,但如果想覆蓋缺省的異常處理的話,handler無(wú)疑是最重要的屬性。
最后必須指出的一點(diǎn)是,你可以有不同的異常處理類來(lái)處理不同的異常。在上面的例子中,CustomizedExceptionHandler用來(lái)處理任何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è)問(wèn)題,即為了更好的支持并行開發(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)用程序??梢詫⒔M成部分劃分成模塊比如catalog(商品目錄), customer(顧客), customer service(顧客服務(wù)), order(訂單)等。每個(gè)模塊可以分布到不同的目錄下,這樣各部分的資源很容易定位,有助于開發(fā)和部署。圖1 顯示了該應(yīng)用的目錄結(jié)構(gòu)。
一個(gè)典型的商店應(yīng)用程序的目錄結(jié)構(gòu)
注:如果你無(wú)需將項(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 來(lái)實(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)的訪問(wè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 被放置在不同的目錄下
這種方法的問(wèn)題是這些頁(yè)面文件容易被偷看到源代碼,或被直接調(diào)用。某些場(chǎng)合下這可能不是個(gè)大問(wèn)題,可是在特定情形中卻可能構(gòu)成安全隱患。用戶可以繞過(guò)Struts的controller直接調(diào)用JSP同樣也是個(gè)問(wèn)題。 為了減少風(fēng)險(xiǎn),可以把這些頁(yè)面文件移到WEB-INF 目錄下。基于Servlet的聲明,WEB-INF不作為Web應(yīng)用的公共文檔樹的一部分。因此,WEB-INF 目錄下的資源不是為客戶直接服務(wù)的。我們?nèi)匀豢梢允褂?span>WEB-INF目錄下的JSP頁(yè)面來(lái)提供視圖給客戶,客戶卻不能直接請(qǐng)求訪問(wèn)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)系起來(lái)。即使該Action只是一個(gè)很基本的很簡(jiǎn)單JSP,也總是要調(diào)用一個(gè)Action,再由它調(diào)用JSP。
最后要說(shuō)明的是,并不是所有的容器都能支持這個(gè)特性。WebLogic早期的版本不能解釋Servlet聲明,因此無(wú)法提供支持,據(jù)報(bào)道在新版本中已經(jīng)改進(jìn)了??傊褂弥跋葯z查一下你的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訪問(wèn)頁(yè)面的話,就可以使用ForwardAction,它可以使你免去創(chuàng)建許多空的Action類。運(yùn)用ForwardAction的好處是不必創(chuàng)建自己的Action類,你需要做的僅僅是在Struts配置文件中配置一個(gè)Action mapping。
舉個(gè)例子,假定你有一個(gè)JSP文件index.jsp ,而且不能直接調(diào)用該頁(yè)面,必須讓程序通過(guò)一個(gè)Action類調(diào)用,那么,你可以建立以下的Action mapping來(lái)實(shí)現(xiàn)這一點(diǎn): 正如你看到的,當(dāng) /home 被調(diào)用時(shí), 就會(huì)調(diào)用ForwardAction 并把請(qǐng)求轉(zhuǎn)發(fā)到 index.jsp 頁(yè)面. 再討論一下不通過(guò)一個(gè)Action類直接轉(zhuǎn)發(fā)到某個(gè)頁(yè)面的情況,必須注意我們?nèi)匀皇褂迷刂械?span>forward屬性來(lái)實(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ù)起來(lái)更容易。
要使用DispatchAction的功能,需要自己創(chuàng)建一個(gè)類,通過(guò)繼承抽象的DispatchAction得到。對(duì)每個(gè)要提供的業(yè)務(wù)方法必須有特定的方法signature。例如,我們想要提供一個(gè)方法來(lái)實(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ù)值。就是說(shuō),調(diào)用addItem()方法的 URL看起來(lái)可能類似于:
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提供了用來(lái)封裝邏輯的各種定制JSP標(biāo)記,因此頁(yè)面設(shè)計(jì)者可以將主要精力花在頁(yè)面的可視特征上,而不必主要考慮Java語(yǔ)法或其它JSP語(yǔ)法,在下列標(biāo)識(shí)庫(kù)描述符中引用了Struts標(biāo)記: Struts-bean.tld 使訪問(wèn)bean以及新bean的定義更容易,,為了實(shí)現(xiàn)國(guó)際化,應(yīng)使用不同的屬性文件 struts-html.tld 提供顯示HTML對(duì)象(例如,表單、按鈕和復(fù)選框)的簡(jiǎn)便方法 struts-logic.tld 支持邏輯構(gòu)造,以便可以有條件地顯示文本或者作為處理循環(huán)的結(jié)果來(lái)顯示文本 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è)引起來(lái)的字符串 文件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)建的資源束中的字符串: ― 屬性文件的名稱是用來(lái)調(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 可以采用各種方法來(lái)定制bean:message標(biāo)記,以便(例如)JSP在運(yùn)行時(shí)引用不同的屬性文件。標(biāo)記提供了一種方法來(lái)支持多種語(yǔ)言以及最多將四個(gè)替代值插入到字符串中來(lái)代替{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)記允許很方便地訪問(wèn)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ù)傳送是通過(guò)使用html:form 和html:text標(biāo)記來(lái)完成的。 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)記:用來(lái)在JSP頁(yè)中管理bean l 邏輯標(biāo)記:用來(lái)在JSP頁(yè)中控制流程 l HTML標(biāo)記:用來(lái)生成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、訪問(wèn)bean及其屬性的標(biāo)記。Struts框架提供了多種自定義標(biāo)記用來(lái)在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ái): l 定義新字符串常數(shù) l 將現(xiàn)有的bean復(fù)制到新定義的bean對(duì)象 l 復(fù)制現(xiàn)有bean的屬性來(lái)創(chuàng)建新的bean <bean:define>標(biāo)記屬性:
例如:定義一個(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)頭等等。屬性如下:
例如: <bean:cookie id=”myCookie” name=”userName”/> 腳本變量名稱是myCookie,用來(lái)創(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中,而不是寫入到輸出流。屬性如下:
例如: <bean:include id=”myInclude” page=”MyJsp?x=1”/> 腳本變量的名稱是myInclude,要檢索的響應(yīng)來(lái)自資源MyJsp?x=1。
<bean:resource>標(biāo)記將檢索web應(yīng)用中的資源,并引入一個(gè)腳本變量和InputStream或字符串類型的頁(yè)作用域?qū)傩浴H绻跈z索資源時(shí)發(fā)生問(wèn)題,就會(huì)產(chǎn)生一個(gè)請(qǐng)求時(shí)間異常。屬性如下:
例如: <bean:resource id=”myResource” name=”/WEB-INF/images/myResource.xml”/> 腳本變量的名稱是myResource,要檢索的資源的名稱是myResource.xml。
顯示Bean屬性標(biāo)記庫(kù)中定義了<bean:write>標(biāo)記,用來(lái)將bean的屬性輸送到封裝的JSP頁(yè)寫入器。這個(gè)標(biāo)記與<jsp:getProperty>類似,屬性如下:
例如: <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類來(lái)實(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ǔ)在基本資源文件所在的目錄中?;举Y源文件包含的是用默認(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ǔ)言顯示。 我們還可以使用特定的字符串來(lái)替換部分消息,就象用java.text.MessageFormat的方法一樣: error.invalid.number = The number {0} is valid 我們可以把字符串{0}替換成任何我們需要的數(shù)字。<bean:message>標(biāo)簽屬性如下:
例如:資源文件中定義了一個(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)記能夠用來(lái)處理外觀邏輯而不需要使用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ù)的大?。?/span> l cookie l 請(qǐng)求參數(shù) l bean或bean的參數(shù) l 請(qǐng)求標(biāo)頭 以下列出了這一類標(biāo)記:
這一類的所有標(biāo)記有相同的屬性
例如: <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)目。
例如: <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)容。換句話說(shuō),這些標(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)記主體。屬性如下:
例如: <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開始(也就是說(shuō)子字符串必須是”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á)式來(lái)返回一個(gè)屬性集合的集合 l 將集合定義為bean,并且使用name屬性指定存儲(chǔ)屬性的名稱。 l 使用name屬性定義一個(gè)bean,并且使用property屬性定義一個(gè)返回集合的bean屬性。 當(dāng)前元素的集合會(huì)被定義為一個(gè)頁(yè)作用域的bean。屬性如下,所有這些屬性都能使用運(yùn)行時(shí)表達(dá)式。
例如: <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類型的腳本變量來(lái)使用。也就是說(shuō),如果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”屬性,用來(lái)指定全局ActionForward的名稱,例如: <logic:forward name=”myGlobalForward”/> 重定向標(biāo)記 <logic:redirect>標(biāo)記是一個(gè)能夠執(zhí)行HTTP重定向的強(qiáng)大工具。根據(jù)指定的不同屬性,它能夠通過(guò)不同的方式實(shí)現(xiàn)重定向。它還允許開發(fā)人員指定重定向URL的查詢參數(shù)。屬性如下:
使用這個(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中移植過(guò)來(lái)的,當(dāng)表單被提交時(shí),請(qǐng)求參數(shù)將移植到ActionForm bean實(shí)例。 所有可以在<form>標(biāo)記中使用的用來(lái)顯示HTML輸入控件的內(nèi)嵌標(biāo)記都使用下列屬性來(lái)定義JavaScript事件處理器。
<form>元素中能夠被定義的其他一般屬性有:
表單標(biāo)記 <html:form>標(biāo)記用來(lái)顯示HTML標(biāo)記,可以指定AcitonForm bean的名稱和它的類名。如果沒有設(shè)置這些屬性,就需要有配置文件來(lái)指定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)記屬性如下:
例如: <html:form action=”validateEmploee.do” method=”post”> </html:form> 與表單相關(guān)的操作路徑是validateEmployee,而表單數(shù)據(jù)是通過(guò)POST傳遞的。對(duì)于這個(gè)表單來(lái)說(shuō),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è)取消按鈕。屬性如下:
復(fù)位和提交標(biāo)記 <html:reset>和<html:submit>標(biāo)記分別能夠顯示HTML復(fù)位按鈕和提交按鈕。 文本和文本區(qū)標(biāo)記 <html:text>和<html:textarea>標(biāo)記分別HTML文本框和文本區(qū),屬性如下:
<html:text>標(biāo)記還有以下屬性:
<html:textarea>標(biāo)記特有的屬性如下:
檢查框和復(fù)選框標(biāo)記 <html:checkbox>標(biāo)記能夠顯示檢查框控件。<html:multibox>標(biāo)記能夠顯示HTML復(fù)選框控件,請(qǐng)求對(duì)象在傳遞檢查框名稱時(shí)使用的getParameterValues()調(diào)用將返回一個(gè)字符串?dāng)?shù)組。屬性如下:
例如: <html:checkbox property=”married” value=”Y”/> 一個(gè)名為married的檢查框,在表單提交時(shí)會(huì)返回一個(gè)”Y”. 文件標(biāo)記 <html:file>標(biāo)記可以顯示HTML文件控件。屬性如下:
單選鈕標(biāo)記 <html:radio>標(biāo)記用來(lái)顯示HTML單選鈕控件,屬性如下:
隱藏標(biāo)記 <html:hidden>標(biāo)記能夠顯示HTML隱藏輸入元素,屬性如下:
密碼標(biāo)記 <html:password>標(biāo)記能夠顯示HTML密碼控件,屬性如下:
選擇標(biāo)記 <html:select>標(biāo)記能夠顯示HTML選擇控件,屬性如下:
選項(xiàng)標(biāo)記(這個(gè)元素需要嵌套在<html:select>標(biāo)記里) <html:option>標(biāo)記用來(lái)顯示HTML選項(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è)字符串集合,能夠用來(lái)寫入選項(xiàng)的值,而optionLabels代表一個(gè)存儲(chǔ)在某個(gè)作用域中的bean,它也是一個(gè)字符串集合,能夠用來(lái)寫入選項(xiàng)的標(biāo)志。 顯示錯(cuò)誤信息的標(biāo)記<html:errors>標(biāo)記能夠與ActionErrors結(jié)合在一起來(lái)顯示錯(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)的消息并且顯示出來(lái)。 通過(guò)定義property屬性能夠過(guò)濾要顯示的消息,這個(gè)屬性的值應(yīng)該與ActionErrors對(duì)象中存儲(chǔ)ActionError對(duì)象的關(guān)鍵字對(duì)應(yīng)。屬性如下:
例子: <html:errors/> 顯示集合中所有的錯(cuò)誤。 <html:errors property=”missing.name”/> 顯示存儲(chǔ)在missing.name關(guān)鍵字的錯(cuò)誤。 其他HTML標(biāo)記struts HTML標(biāo)記還定義了下列標(biāo)記來(lái)顯示其他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)記來(lái)實(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屬性,用來(lái)定義模板JSP頁(yè)。要插入到模板的頁(yè)是有多個(gè)<template:put>標(biāo)記來(lái)指定的,而這些標(biāo)記被定義為<template:insert>標(biāo)記的主體內(nèi)容。 放置標(biāo)記 <template:put>標(biāo)記是<template:insert>標(biāo)記內(nèi)部使用的,用來(lái)指定插入到模板的資源。屬性如下:
獲得標(biāo)記 在模板JSP頁(yè)中使用<template:get>標(biāo)記能夠檢索由<template:put>標(biāo)記插入到JSP頁(yè)的資源。屬性如下:
使用模板標(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)記來(lái)獲得由JSP頁(yè)使用<template:put>標(biāo)記提供的內(nèi)容,并且將內(nèi)容在一個(gè)HTML表格中顯示出來(lái)。這三個(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)記來(lái)定義模板,然后使用<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è),用來(lái)確認(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ó)際化過(guò)程來(lái)測(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路徑。
接下來(lái)我們需要第二個(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編譯你的類。由于我是初手,在這里遇見很多問(wèn)題,所以耽誤了很久,不過(guò)它讓你學(xué)到很多東東。比如:javax.servlet要用到servlet.jar包;javac后跟a.java, 而java后跟a;還有我遇見了很原文提到的問(wèn)題,很多都是由于自己編寫(沒有copy)而造成的馬虎。希望大家也能引起注意,到此除了ActionForm我們都已用到了。
編譯成功后,在你的classes目錄下會(huì)增加兩個(gè)文件:Book.class和BookAction.class. 重啟你的tomcat(每次改動(dòng)config文件你都需要重啟,改動(dòng)注冊(cè)表需要重啟機(jī)器)?,F(xiàn)在在你的瀏覽器里登陸CreateBook.jsp,如圖7:
當(dāng)你填寫后提交,另你失望的是什么也沒有得到。這是由于我們并沒有ActionForm bean. struts:介紹ActionForm這節(jié)我們繼續(xù)做ActionForm bean來(lái)完成我們的例子。我們將用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的方法來(lái)訪問(wèn)它。關(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去訪問(wèn)Book.java,而不用struts直接連接到Book.java。接下來(lái),我們要解決在這兩個(gè)類中重復(fù)輸入getXXX和setXXX。Struts允許我們直接訪問(wèn)實(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)你輸入的名了。 |
|
|