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