0 序... 2
0.1猜想... 2
0.2 HTTP,HTML,User Agents. 2
0.3 HTTP 請求/響應周期... 2
0.4 Java語言和應用框架... 2
0.5 JavaBeans. 2
0.6屬性文件和資源綁定... 3
0.7 JavaServlet 3
1介紹... 5
1.1Struts的歷史... 5
1.2 MVC模式... 6
1.3 Struts控制流程... 7
2 創建模型組件... 8
2.1概述... 8
2.2 JavaBean和作用域... 8
2.3 ActionForm Bean. 9
2.4系統狀態Bean. 9
2.5商業邏輯Bean. 9
3 創建視圖組件... 9
3.1 概述... 9
3.2 國際化信息... 9
3.3Forms 和 FormBeans的交互... 11
3.4 其他表示層技術... 13
4 創建控制(Controller)組件... 15
4.1 概述... 15
4.2 ActionServlet 15
4.3 ActionForm類... 16
4.4 Action類... 19
4.5 異常處理器... 20
4.6 插件類... 20
4.7 ActionMapping的實現... 20
4.8 編寫Action Mappings. 21
4.9 在頁面中使用ActionMapping. 22
4.10 在ActionMapping中使用通配符... 22
4.11 公共的Log 接口... 23
5. 配置應用... 23
5.1 概述... 23
5.2 Struts配置文件... 23
5.3 為應用配置模塊... 25
5.4 WEB應用部署描述符... 25
0 序
0.1猜想
本手冊適合于有創建Java Web 應用經驗的Web 開發人員.在開始學習Struts之前你應該了解如下的技術:
1. HTTP,HTML,User Agents
2. HTTP 請求/響應生命周期
3. Java語言和應用框架
4. JavaBeans
5. 屬性文件和資源綁定
6. Java Servlets
7. Java Server Pages ,JSP Tag Librariy
8. XML
0.2 HTTP,HTML,User Agents
WWW是基于超文本傳輸協議和超文本標識語言建立的.
用戶代理,比如瀏覽器,他們使用HTTP去請求一個文檔然后格式化顯示.
0.3 HTTP 請求/響應周期
對于Web開發者來說,理解HTTP的請求和響應周期是很重要的.你要使用HTTP發送一個請求,然后服務器給你一個響應.當你創建WEB應用時,你需要返回一個響應對象來回應請求.
0.4 Java語言和應用框架
Struts是用JAVA編寫的.JAVA是面向對象的語言,而Struts充分利用了面向對象的技術.除此而外JAVA支持線程.如果你很好的掌握了JAVA,特別是面向對象編程和線程,這將會有益于最有效的使用Struts和這個手冊.
0.5 JavaBeans
象大多數JAVA應用一樣,大多數Struts對象都是JavaBean.遵循JavaBean設計模式使得Struts更容易被開發者和JAVA開發工具使用.盡管JavaBean的最初是用來開發可視元素的,但它對開發可重用組件也非常有益.
0.5.1反射和內省
反射是決定什么樣的函數或域存在某對象中的方法.內省是反射的特殊形式.
使用內省就可以知道哪些方法將會被其他對象使用(如getter,setter)
Struts框架使用內省來轉換HTTP參數到JAVABEAN的屬性中和把JAVABEAN中的屬性數據組裝到HTML的域.
0.5.2 MAP
JAVABEAN把數據存在屬性中.JAVABEAN雖然是靈活而功能強的對象,但它并不是編程者存儲數據的唯一對象.另一個熟為人知的對象是java.util.Map.Map它是一個名字/值對的數據集合,它經常用來存儲動態數據.
0.5.3 DynaBeans
DynaBeans集成了JAVABEAN 的擴展性和MAP的靈活性.編寫JAVABEAN要創建一個新類,并且要為每個屬性編寫方法.DynaBeans則將屬性放在XML中配置.
在Struts應用中,你可以使用DynaBeans來描述你的HTML Form,這個策略可以避免編寫普通的JAVABEAN來存儲很簡單的屬性.
0.6屬性文件和資源綁定
JAVA應用包括WEB應用的配置經常使用屬性文件來完成. Struts的消息資源都是通過資源綁定和屬性文件實現的.
JAVA資源綁定使用一個或多個屬性文件來實現應用的國際化.
0.7 JavaServlet
由于JAVA是面向對象的語言,因此JAVA平臺已經將HTTP轉換成對象的形式.這將會使JAVA 程序員關注于應用本身而不是HTTP.
HTTP提供了一個標準的機制來擴展服務器的功能,我們稱之為CGI. 服務器將請求發送到CGI程序,CGI程序則返回一個響應.同樣的任何JAVA服務器則會接收請求,然后轉發到Servlet.
Servelt 是javax.servlet.http.HttpServlet的子類,每個Servlet必須完成四個方法:
* public void init(ServletConfig config)
* public void doGet(HttpServletRequest request, HttpServletResponse response)
* public void doPost(HttpServletRequest request, HttpServletResponse response)
* public void destroy()
Struts提供了一個可用的Servlet--org.apache.struts.action.ActionServlet.
作為一個Struts開發者,你只需要編寫對象供ActionServlet調用就行了.但是,理解Servlet并熟悉他在JAVA WEB應用中扮演的角色那是最好不過了.
0.7.1 Servlets 和多線程
為了提高性能,Servlet設計程多線程.每個Servlet僅創建一個實例,每一個請求都傳遞到同一個對象.這將有利于Servlet容器充分的利用資源.因此doGet,doPos在編程時必須保證他是線程安全的.
0.7.2 Servlet Context
ServletContext(javax.servlet.ServletContext)定義了Web 應用中Servlet的視圖.在Servlet中通過getServletConfig()可以訪問得到,在JSP中則通過隱式對象application得到.ServletContext提供了幾個對于創建Struts應用來說非常有用的幾個方法:
1.訪問WEB應用資源 Servlet通過getResource(),getResourceAsStream()可以訪問WEB應用中的靜態資源文件.
2.Servlet Context屬性 Servlet上下文可以存儲JAVA對象到屬性中.這些屬性對整個WEB應用都可見.
0.7.3 Servlet請求
Servlet請求就是javax.servlet.http.HttpServletRequest,通過它可以訪問HTTP請求的所有信息:
1. Cookies 通過getCookies()可以得到當前請求的所有cookie
2. HTTP頭 HTTP請求的頭可以通過對應的名字來訪問.你當然可以通過枚舉來列出所有的頭.
3. 參數 你可以通過參數來訪問HTTP請求的URL的參數或表單中的內容.
4. 請求特性 HTTP請求表單的提交方式(GET/POST),用的是什么協議(HTTP/HTTPS)
5. 請求URI信息 通過getRequestURI()可以得到最初的請求URI,除此之外,我們還可以得到contextPath,servletPath,pathInfo
6. 用戶信息 如果你正使用容器來進行安全管理,你可以得到一個Principal對象來代表當前用戶,并確認該用戶是否擁有某叫角色的權限.
Servlet請求擁有請求級別的屬性,與前面提到的應用級別屬性類似.請求級別的屬性經常用來傳遞狀態信息到可視化組件(如JSP).
Servlet容器保證被Servlet處理的請求處于單線程內.因此你不必擔心在訪問request對象的屬性時會有多線程的問題.
0.7.4 Servlet響應
Servlet的功能就是接收請求,然后生成相應的響應. 這是通過調用javax.servlet.http.HttpServletResponse的方法實現的.
1.設置頭 你可以設置包含在響應中的頭.最重要的頭就是Content-Type,它用來告訴客戶端內容的格式,比如:text/html代表html,text/xml代表XML
2.設置Cookies 你可以加入cookie到當前的響應中
3.發送錯誤響應 你可以使用sendError()發送一個HTTP錯誤編號
4.重定向到其他資源 你可以使用sendRedirect()定向到另外一個URL
使用Response API的一個最重要的原則就是:操作Header,Cookie的任何方法必須在第一次輸出緩沖區滿且發送到客戶端前調用.
0.7.5過濾
如果你的Servlet容器是基于Servlet規范2.3或更高,那么你就可以使用javax.servlet.Filter來對請求和響應作些處理.許多filter聚合在一起,每一個filter都有機會來對請求和響應做處理.
Struts1.0,1.1,1.2只需要Servlet規范2.2,因此這些版本的Struts并不支持filter.
Struts從1.3開始就需要Servlet規范2.3的容器了.
0.7.6 Session
HTTP的一個關鍵特性就是無狀態,因此我們不知道某個請求是否是來自同一用戶的請求,這將會使跨請求的會話變得很艱難.
為了解決這個問題,Servelet實現了一個javax.servlet.http.HttpSession.Servlet容器將采用Cookie或URL Rewriting來保證接鄰近的請求包含session id來標識該請求是同一個session.因此保存在session中的屬性可以被多個請求共享.
為了不浪費資源,Session有一個可配置的超時時間設置.如果兩個請求間的時間差超過了超時時間間隔,那么session中的數據會失效.你可以定義一個默認的超時時間在WEB應用部署描述文件中,或者你也可以通過setMaxInactiveInterval()動態改變它.
與request不一樣的是,你必須關心session的屬性是線程安全的,(bean提供的方法,并不是session的getAttribute和setAttribute)
比較重要的一點需要考慮的是:因為session的屬性是占用內存的時間較長,因此在用戶量大時,要考慮session的屬性占用內存的大小.
0.7.7分發請求
1介紹
1.1Struts的歷史
Servlet剛出道時,很多Java開發者意識到它將會比CGI更快,更有效,更容易移植.
但是通過println()將HTML輸出到客戶端是很煩人和容易出錯的.于是人們在JSP中找到了答案,通過將JAVA代碼與HTML混合在一起.
JAVA WEB應用開發隨之也變得以JSP為中心點.這并不是壞事.關鍵的是它沒有給WEB應用的流程控制及其它問題提供更多的解決方法.
許多聰明的開發者意識到可以將Servlet,JSP同時部署到WEB應用中.Servlet來做控制流程,JSP來生成HTML頁面.一個新的名詞Model 2 由此而生.
Model 2 對于SUN來說并不是新奇的事物.許多人指出Model 2遵循從Smalltalk MVC框架抽象出來的MVC模式.從而人們開始把Model 2 與MVC關聯到一起.
1.2 MVC模式
在MVC模式中,流程由控制器(Controller)管理.控制器將請求委派到相應的處理器,處理器與Model連在一起,每個處理器在請求與Model之間充當一個適配的角色.Model封裝了商業邏輯或狀態.然后控制流程將會轉到View. 轉向動作可以由存儲在數據庫或文件中的轉向定義來決定.這會讓View和Model之間的關系松散,從而有利于應用的創建和維護.
1.2.1 Model(系統狀態和商業邏輯JavaBean)
基于MVC的系統可以的Model可分為兩部分:一個是系統的狀態,另一個是改變這些狀態的行為.
大多數系統將系統狀態存儲在JAVABEAN中.根據系統復雜度的不同,有些Beans是自包含的(也就是BEAN本身知道如何持久化數據),有些是通過其它方式取得數據(數據庫,搜索引擎,EJB,LDAP).
在大型系統中JAVABEAN可能有很多方法來維護狀態信息.
在小型系統中,這些JAVABEAN的方法極有可能放到Struts框架的Action類中.如果商業邏輯很簡單或者它不會在其它地方重復調用,這是可以的.
Struts提供了許多靈活的方式來訪問Model,但我們強烈建議你將商業邏輯和Action類分離開來.
1.2.2 視圖(View)-JSP和可視組件
Struts應用的視圖部分經常是基于JSP的.JSP可以包含HTML,XML,及標簽.
Struts擁有一個標簽庫可以讓你創建國際化的用戶界面以及很好的與ActionForm beans集成在一起. ActionForm 捕獲,校驗應用的輸入數據.
1.2.3控制器-ActionServlet,ActionMapping
控制器負責接受來自客戶端的請求,并且決定將執行哪個業務邏輯功能,然后再委托相應的View來顯示用戶界面.
在Struts中,主要的控制器組件就是ActionServlet,它有一組ActionMapping,每一個ActionMapping會有某個請求URL的路徑和該URL對應的Action 類.每一個Action都是org.apache.struts.action.Action的子類.Action去調用業務邏輯類,最終將控制權交給View組件.
1.3 Struts控制流程
Struts用幾個組件組成了MVC框架的控制層.它們由Controller servlet,開發者自定義的請求處理器(handler)和其它一些輔助類構成.
Struts的自定義標簽庫為View層提供直接的支持.有些標簽可以訪問Control層的對象,有些則是為了方便開發應用而寫的.其他的標簽庫如JSTL也可以與Struts一起使用.
Model層對不同的項目來說有很多不同.Struts讓model很容易被應用的后臺邏輯所使用.
讓我們來看看Controller,View,Model是如何融合在一起的.
當初始化時,Controller解釋struts-config.xml并且使用它部署一些控制層的對象,這些對象構成了Struts的基礎.這個基礎當然少不了ActionMapping[org.apache.struts.action.ActionMappings].
當Struts要將請求傳遞到框架的其他組件時它就得參考ActionMapping,請求將會轉移到一個JSP或者Action--org.apache.struts.action.Action.通常,一個請求先派發到Action,然后再到JSP.
一個ActionMapping通常包含如下的屬性:
1. 請求路徑(或者URI)
2. 響應請求的對象(Action 子類)
3. 其它所需要的屬性
Action對象可以處理請求和響應,或者將控制流轉向到其它地方.例如,如果登陸成功,將轉向到主頁面.
Action對象可以訪問應用的Controller servlet,當控制流發生改變時,他可以將JAVABEAN放在合適的上下文中供多個Servlet共享.
例如,一個Action對象創建了一個購物車Bean,并且往購物車中加入所夠物品,然后把這個BEAN放在session中,當轉向到其他URL時,就可以用到先前創建的購物車.
在Struts應用中,大多數的商業邏輯都放在JAVABEAN中,Action調用JAVABEAN的方法而不需要知道它是如何實現的.這樣一來就封裝了商業邏輯,而Action本身將集中到錯誤處理和轉向(Forward)的處理上.
JAVABEAN也可以用來管理輸入表單,設計WEB應用的一個關鍵問題是如何保持和校驗在兩個請求之間的用戶所輸入的數據.有了Struts,你就可以用org.apache.struts.action.ActionForm來存儲和校驗輸入表單.ActionForm被自動保存在合適的上下文中,因此它可以被其他的對象共享,如Action對象,JSP.
FormBean可以被JSP用來收集用戶數據,也可以由Action對象來校驗用戶所輸入的數據,還可由JSP把數據組裝到HTML的輸入域中.Struts擁有共享的拋出錯誤,顯示錯誤的機制.
另外一個Struts的培植元素就是ActionFormBeans --org.apache.struts.action.ActionFormBeans,它是一個描述性對象的集合,主要用于運行時動態創建ActionForm的實例.當一個URL映射需要ActionForm,Servlet就會通過名字去查找form-bean的描述對象,從而用它去創建ActionForm的實例.
下面是請求需要ActionForm時的事件序列:
1. Controller servlet檢索或者創建ActionForm
2. Controller servlet 將bean傳遞到ActionObject
3. 如果請求提交了一個輸入頁面,Action 對象可以檢查數據.
4. 如果請求將要創建一個輸入界面, Action 對象將會組裝數據到任何輸入頁面中.
2 創建模型組件
2.1概述
許多創建WEB應用的文檔都關注于View,然而我們應該在Model的角度清晰定義需求的處理邏輯或過程.總之,Model的開發者將會創建JAVABEAN來實現功能需求.一個應用的JAVABEAN需要什么樣的功能完全取決于需求,但它可以分為如下三類,在介紹他們之前,讓我們先看一下JAVABEAN的作用域
2.2 JavaBean和作用域
在WEB應用中,JAVABEAN存儲許多不同的屬性集合中。每一個不同的屬性集合都有不同的生命周期規則。該規則定義了生命周期和可見性我們稱之為作用域(Scope),JSP定義的作用域如下:
1. page Bean在當前請求的單個JSP頁面可見(相當于Servlet的service方法中的局部變量)
2. Request Bean不僅在單個頁面可見,也可以在被頁面包含(include)的頁面或servlet中可見,或者轉向(Forward)的頁面可見。
3. Session Bean在特殊用戶session的所有JSP或Servlet中可見。
4. Application Bean在WEB 應用中的所有JSP,或Servelt中可見。
必須記住的是JSP和Servlet在同一個WEB應用中共享同一組Bean。例如一個Bean在Servlet中存在request的屬性中:
MyCart mycart = new MyCart(...);
request.setAttribute("cart", mycart);
Mycart在該Servlet轉向的JSP頁面中馬上可見。你可以在JSP中如下聲明它:
<jsp:useBean id="cart" scope="request"
class="com.mycompany.MyApp.MyCart"/>
2.3 ActionForm Bean
注意:ActionForm Bean的屬性經常會對應Model中Bean的屬性。Form bean應該被看作是Controller的組件,同樣的,它能在Model和View兩層之間傳遞數據。
Struts假定你已經為應用的Form定義了ActionForm.ActionForm也通常成為form bean(表單bean)。一個bean可以服務于一個form,也可一服務于多個form或者整個應用,這完全取決于你在設計form bean時的粒度。
如果你定義了ActionForm Bean在Struts的配置文件中,那么Struts框架會在執行Action對象的方法之前為你自動執行如下服務:
1.檢查Bean是不是在適當的作用域
2.如果Bean不存在,則創建一個實例,并且加入到適當的作用域上下文中。
3.如果請求的參數的名字與Bean中的屬性名字一致,對應的setter方法就會被調用。
4.填滿數據的ActionForm Bean將會傳到org.apache.struts.Action的excute方法,因而系統狀態Bean和商業邏輯Bean就會有數據可用。
2.4系統狀態Bean
一個系統的狀態實際上是由許多JAVABEAN組成的。例如一個購物車系統對于用戶有個購物車的Bean,它里面有用戶當前購買的商品。系統里還有Bean來保存用戶的信息
2.5商業邏輯Bean
你需要封裝你的商業邏輯在JAVABEAN的方法中。這些方法可能放在系統狀態Bean中,但盡可能用一個單獨類來實現。如果是用單獨的類來實現,你可能需要將系統狀態Bean 作為參數傳到商業邏輯Bean的方法中。
3 創建視圖組件
3.1 概述
這章將集中在Sruts的視圖部分。很多應用依賴于JSP來創建展現層。Struts包含了支持國際化應用的標簽,也有提供輸入表單交互的標簽。
3.2 國際化信息
多年以前,應用開發者只需要支持自己國家的公民來使用軟件,他們可能使用一種語言或一種度量衡標準。隨著WEB應用在全世界快速增長,應用的國界也逐漸消失。因此應用需要國際化和本地化。
Struts在JAVA平臺的基礎上來支持國際化和本地化。回顧一下我們熟悉的概念:
1. Locale - JAVA中支持國際化的最基本的類,它代表一個國家和語言,同時也假定了數字或時間的格式。
2.ResourceBundle - JAVA中工具類用來支持不同國家的信息。
3.PropertyResourceBundle - ResourceBundle的一個實現,它允許你使用”name=value”的格式來初始化屬性文件。這對于準備WEB應用的信息是非常方便的,因為這些信息都是文本。
4.MessageFormat - java.text.MessageFormat允許你在運行時用參數替換信息字符串中的部分信息。當某些信息在運行時將會顯示不同的順序或不同的語言時,MessageFormat將會非常有用。占位符{0}將被第一個參數代替,{1}將被第二個參數代替,依此類推。
5.MessageResource - org.apache.struts.util.MessageResources類把所有的資源綁定當作一個數據庫來看待,允許你請求不同的Locale的信息字符串(通常與當前用戶相關),而不是服務器上的Locale。
必須注意的是:Struts框架支持國際化僅僅限于展現給用戶的文本和圖片,支持本地化的輸入方法(例如使用何種語言)則由客戶端的設備(通常是瀏覽器)實現。
讓我們來了解一下將屬性文件綁定到WEB應用的步驟,
假如你的代碼在com.mycompany.mypackage,為了實現資源綁定,你需要創建如下文件:
1.MyApplication.properties ? 默認語言的所有信息,如果默認語言是英語,在你的屬性文件中可能有如下入口prompt.hello=Hello
2.MyApplication_xx.properties - ISO語言代碼所對應語言的所有信息,如果語言是法語,屬性文件中可能有如下入口prompt.hello=Bonjour
當你在WEB應用的部署描述文件中定義Controller Servlet時,你可能需要把應用的資源綁定名稱作為初始化參數傳進去。
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>application</param-name>
<param-value>
com.mycompany.mypackage.MyResources
</param-value>
</init-param>
<!-- ... -->
</servlet>
最重要的是要保證資源綁定能在你的應用的CLASSPATH找得到。另外一個方法就是把MyResources.properties放在classes目錄,然后用MyResoureces來引用就行了。
3.3Forms 和 FormBeans的交互
很多WEB開發者使用HTML本身的功能來實現表單,比如Input。用戶期望交互應用能具備某些必備的功能,比如錯誤處理(當出現錯誤時,只需要修改導致錯誤出現的地方,而不要重新輸入頁面或表單中的信息)。
用標準的HTML和JSP來實現錯誤處理是麻煩而且很乏味。一個輸入用戶名的界面在JSP中如下表示:
<input type="text" name="username"
value="<%= loginBean.getUsername() >"/>
輸入如上的字符對于沒有編程理念的HTML編寫者來說是很容易出錯的。Struts在提供了一些自定義標簽來實現上述的功能:
<html:text property="username"/>;
上述表示法并不要很明顯的指定與JAVABEAN相關聯,它的處理完全由框架實現。
3.3.1索引和映射屬性
JSP頁面中的標簽屬性可以引用JAVABEAN中的屬性。大多數都是引用簡單類型或簡單對象。但Struts允許你利用Jakarta Commons Beanutils library提供的功能來引用Array,Conllection,Map的單個項。
3.3.2 輸入域的支持
Srust支持如下的輸入域:
1.Checkbox
2.Hidden field
3.Password
4.Radio
5.Reset
6.Select
7.Option
8.Options
9.Submit
10. Text
11. TextArea
在任何情況下,這些標簽必須嵌套在 form標簽中,只有這樣輸入域才知道它要使用那個Bean 。
3.3.3 一些有用的標簽
Iterate
Present
Nopresent
Link
Img
Parametr
3.3.4 自動表單校驗
Strust提供了校驗表單的功能,為了使用此功能,你需要重載ActionForm的如下方法:
validate(ActionMapping mapping,HttpServletRequest request);
當Bean的屬性的數據被填充后,在調用Action的excute方法之前,Controller Servlet來調用validate方法。Validate方法的執行有如下幾種情況:
1.執行校驗但沒有錯誤 返回NULL或0長度的ActionErrors實例,Controller Servlet將繼續執行Action的方法。
2.執行校驗但有錯誤 返回ActionErrors實例,每一個ActionError有對應的錯誤消息關鍵值。Controller Servlet將把錯誤消息數組保存到請求級別的上下文中供<html:errors>標簽使用。
3.3.5 Struts校驗器
為表單配置校驗器是很簡單的。
1.ActionForm須繼承ValidatorForm
2.表單所在的JSP頁面須包含<html:javascript>標簽用于客戶端的校驗
3.你需要定義校驗規則在XML文件中
<form-validation>
<formset>
<form name="logonForm">
<field property="username" depends="required">
<msg name="required" key="error.username"/>
</field>
</form>
</formset>
</form-validation>
4.最后,你必須在struts-config.xml文件中激活ValidatorPlugin
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property
property="pathnames"
value="/WEB-INF/validator-rules.xml,
/WEB-INF/validation.xml"/>
</plug-in>
3.4 其他表示層技術
盡管外觀可以用JSP或Struts的標簽來實現,但你仍然應該考慮融合其他技術來提高組件的重用,減少維護工作量,減少錯誤。
3.4.1 特定應用標簽
忽略
3.4.2使用包含組合頁面
將一個頁面放在一個JSP文件中是一個普遍的設計方法,但是許多應用需要將應用中的不同部分顯示在一個頁面中。例如一個門戶應用需要如下功能:
1. 訪問門戶的搜索引擎
2. 訪問門戶的討論區
3. 用戶感興趣的話題
4. 郵件等待指示器
將這些不同的功能交給不同的開發者開發,要完成這個門戶應用是比較容易的。然后你就可以使用包含( include)來
將它們組合到一個頁面中。有三種不同的包含方式,選擇哪種取決于你希望整個輸出在什么時候整合:
1. <%@ include file="xxxxx" %>
2. <jsp:include page="xxxxx" flush="true" />
3. bean:include
3.4.3 使用Tiles組合頁面
Tiles是一個功能很強的模板庫,它可以將很多tile組合成最終的視圖。以下是設置向導:
1.創建layout/layout.jsp,它包含標準外觀
<html>
<body>
<tiles:insert attribute="body"/>
</body>
</html>
2.創建你的主頁/index.jsp
<h1>This is my homepage</h1>
3.創建文件/WEB-INF/tiles-defs.xml
<tiles-definitions>
<definition
name="layout"
path="/layout/layout.jsp">
<put name="body" value=""/>
</definition>
<definition name="homepage" extends="layout">
<put
name="body"
value="/index.jsp"/>
</definition>
<tiles-definitions>
4.在文件struts-config.xml中設置TilesPlugin
<plug-in
className="org.apache.struts.tiles.TilesPlugin">
<set-property
property="definitions-config"
value="/WEB-INF/tiles-defs.xml"/>
</plug-in>
5.在struts-config.xml文件中設置一個Action指向你的主頁
<action path="/index" type="org.apache.struts.actions.ForwardAction" parameter="homepage"/>
3.4.4 圖片渲染組件
一些應用需要動態產生圖片,有兩種方法符合如下需求:
1. 產生一個執行Servlet請求的超鏈接 Servlet將使用圖形庫來產生圖片
2. 將JAVA Applet嵌入在HTML頁面中來產生圖片
3.4.5 文本輸出
一些應用需要動態的產生文本(如XML),因為整個頁面將通過PrinterWriter輸出,我們可以通過設置PrinterWriter的屬性來做到:
response.setContentType("text/plain"); // or text/xml
PrintWriter writer = response.getWriter();
// use writer to render text
return(null);
3.4.6 Struts EL 標簽庫
Struts基本的標簽都是依賴rtexprvalue(runtime scriptlet expression)來動態計算屬性
的值,例如,要根據資源關鍵值打印來自屬性文件中的信息
<bean:message key='<%= stringvar %>'/> 這樣寫是假定stringvar是JSP中的
腳本變量,如果使用Struts的EL標簽庫就會是如下形式:
<bean-el:message key="${stringvar}"/>
4 創建控制(Controller)組件
4.1 概述
我們已經知道如何去構建Model和View組件,現在我們將集中到Controller組件。Struts包含了一個映射請求URI到Action類的Servlet。因此你編寫WEB應用時在Controller組件這方面要做的工作如下:
1.編寫AtionForm作為Model和View的中介
2.編寫Action(繼承org.apache.struts.action.Action)來處理請求
3.為每一個邏輯請求在struts-config.xml.中編寫一個ActionMapping
4.2 ActionServlet
對于熟悉MVC架構的人來講,ActionServlet就代表著 C ? Controller。Controller的任務是:
1.處理用戶請求
2.根據用戶請求來決定用戶將要完成什么任務
3.將Model的數據傳到視圖(View)
4.選擇合適的視圖響應請求
Controller會將大部分工作放到Request Processor和Action 類中。
4.2.1 請求處理器(Request Processor)
RequestProcessor對每個請求做核心處理的地方,它要做的處理如下:
1. processPath - 確定請求的路徑,以備后面的處理檢索ActionMapping
2. processLocale ? 為請求選擇一個locale
3. processContent - 設置默認的內容(Content)類型.
4. processNoCache ? 設置響應頭:Pragma,Cache-Control,Expires
5. processPreprocess - RequestProcessor讓子類重載實現,默認返回真(True),如果子類重載此方法并返回真,則該請求將繼續處理流程,如果返回假,則意味著你處理了該請求,處理流程直接返回。
6. processMapping - 確定請求所對應路徑的ActionMapping
7. processRoles - 保證請求的用戶具備特定的角色
8. processActionForm - 實例化ActioForm并且把它放在適當的作用域中。
9. processPopulate - 用請求中的數據組裝ActionForm
10. processValidate - 校驗ActionForm中的數據
11. processForward - 如果映射是一個轉向( Forward)指令,就轉向到特定的路徑。
12. processInclude - 如果映射是一個包含(Include)指令,就將映射指定的路徑的輸出結果包含進來。
13. processActionCreate - 實例化映射指定的Action.
14. processActionPerform ? 執行Action的perform或excute方法。
15. processForwardConfig - 最后RequetProcessor使用Action類返回的ActionForward來選擇下一個資源。大多數的AtionForward將會導航到顯示頁面輸出響應。
4.3 ActionForm類
一個ActionForm代表著一個與用戶交互的HTML表單。ActionForm中的屬性來存儲表單中的狀態,并且有getter,setter方法來訪問他們。ActionForm可以存儲在session或request的作用域中(默認的是session).如果ActionForm放在session中記得要實現reset方法,以備每次使用ActionForm時都會初始化。Struts根據請求中的參數設置ActionForm的屬性并且把經過校驗后的ActionForm傳到Action的execute方法。
當你在編寫ActionForm時必須堅持如下原則:
1.ActionForm本身沒有任何特定的方法被實現。僅僅用來表示它是整個框架中一個特定的角色。ActinForm中只有getter,setter方法,并沒有任何商業邏輯。
2.AtionForm提供標準的校驗機制。如果你重載了ActionForm的validate方法,并且在資源屬性文件中提供了錯誤消息,那么Struts就會自動校驗表單中的數據。當然你也可以忽略ActionForm中的校驗,在Action類中來實現校驗。
3.為輸入表單中的每一個輸入定義屬性。輸入域的名稱和ActionForm中屬性的名稱必須符合JAVA規范。例如一個輸入域的名稱username將會導致ActionForm中的setUsername被調用。
4.也可以為Form中的按鈕或其他控件定義屬性。當提交表單時這將有利于你知道哪個控件被選中了。
5.把ActionForm當作HTTP和Action之間的防火墻。ActionForm的方法可以校驗所有必須的屬性已經存在了并且包含合理的值。如果校驗失敗請求將不會被Action類處理。
6.你可能會放一個Bean的實例在ActinForm中,這樣你就會用到嵌套屬性引用。例如,你可能有一個“customer”在ActionForm中,然后在頁面中用“customer.name”來引用屬性。
4.3.1 DynaActionForm
維護一個具體的ActionForm是要耗費時間的。特別是ActionForm越來越多并且都是校驗一些簡單的屬性時你可能會感覺到一股挫折感。
這個瓶頸通過DynaActionForm會有所減輕。通過在Struts的配置文件中列出屬性,類型和默認值來替代以前的定義一個新類,并且添加getter/setter方法。例如,在struts-config.xml中添加一個UserForm:
<form-bean
name="UserForm"
type="org.apache.struts.action.DynaActionForm">
<form-property
name="givenName"
type="java.lang.String"
initial="John"/>
<form-property
name="familyName"
type="java.lang.String"
initial="Smith"/>
</form-bean>
DynaActionForm支持的數據類型:
? java.lang.BigDecimal
? java.lang.BigInteger
? boolean and java.lang.Boolean
? byte and java.lang.Byte
? char and java.lang.Character
? java.lang.Class
? double and java.lang.Double
? float and java.lang.Float
? int and java.lang.Integer
? long and java.lang.Long
? short and java.lang.Short
? java.lang.String
? java.sql.Date
? java.sql.Time
? java.sql.Timestamp
你可以指定成這些類型的數組,也可以時MAP的具體實現類。
4.3.2 后端映射ActionForm
DynaActionForm根據配置文件中的屬性在初始化的時候來生成ActionForm。但有時候輸入表單是動態生成的。因此表單的AtionForm的屬性不能提前知道,所以需要一種新的方法。
Struts允許你將ActionForm屬性存儲在MAP中而不是JAVA的原子對象。
public FooForm extends ActionForm {
private final Map values = new HashMap();
public void setValue(String key, Object value) {
values.put(key, value);
}
public Object getValue(String key) {
return values.get(key);
}
}
在JSP頁面中你可以通過特殊的符號來引用:mapname(keyname)。圓括號在Bean的屬性中表明:
1.ActionForm的所有屬性使用Sring做索引
2.Struts將使用帶String參數的getter/setter方法來獲取,設置ActionForm的值。
看如下的例子:
<html:text property="value(foo)"/>
這樣你將會調用FooForm的getValue方法來得到鍵值為”foo”的值。為了創建一個包含動態輸入域的表單你會如下做:
<%
for (int i = 0; i < 10; i++) {
String name = "value(foo-" + i + ")";
%>
<html:text property="<%= name %>"/>
<br/>
<%
}
%>
除了后端映射屬性,你還可以創建后端列表屬性。
public FooForm extends ActionForm {
private final List values = new ArrayList();
public void setValue(int key, Object value) {
values.set(key, value);
}
public Object getValue(int key) {
return values.get(key);
}
}
在你的JSP頁面中,你需要用特殊的符號來引用值:listname[index]。
4.4 Action類
Ation有兩個根據Servlet環境不同而調用的方法.
The Action class defines two methods that could be executed depending on your servlet environment:
public ActionForward execute(ActionMapping mapping,
ActionForm form,
ServletRequest request,
ServletResponse response)
throws Exception;
public ActionForward execute(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception;
因為Struts主要用來創建WEB應用,所以大多數項目只用HttpServletRequest。Action主要用來處理請求并且返回對象ActionForward表明控制流將轉向哪里(JSP,Action, Tile定義,Velocity模板) 。在MVC/Model2的設計模式里,Action將完成一下邏輯。
1.校驗用戶Session的狀態(用戶是否登錄)。
2.校驗表單Bean的屬性。
3.執行該請求所需的邏輯處理。
4.修改Server端對象。以備下一個顯示頁面要用。
5.返回一個ActionForward對象來表明哪一個頁面將用來產生輸出。
4.4.1 Action類的設計方針
1.編寫多線程安全代碼 Controller Servlet只創建一個Action的實例來服務所有的請求,因此你必須編寫線程安全的Action 類。下面是寫Action類是的兩個基本的方針:
只使用局部變量 編寫線程安全的Action的最重要一點是不要使用實例變量而用局部變量。因為局部變量在每個線程的堆棧上創建,所以不需要考慮多線程的問題。
保存資源 當你分配有限的資源時可能會導致資源匱乏的問題。(比如分配JDBC 連接,這時就要盡可能采用鏈接池的方式)。
2.不要拋出異常,盡量Catch它
如果你的應用代碼會拋出異常請Catch住它,記錄他們到應用的Log中并且返回一個ActionFoward。
避免寫很長,很復雜的Action類是明智的。如果你寫很多的邏輯在Action類中,這將會使代碼很難理解,維護,重用。
4.5 異常處理器
當Action的execute方法拋出異常時,你可以定義一個異常處理器來執行相應的處理。首先你需要一個繼承org.apache.struts.action.ExceptionHandler的類并且重載execute方法。Execute方法將處理異常并且返回一個ActionForward來告訴struts下一步將去哪。然后在struts-config.xml中配置異常處理器:
<global-exceptions>
<exception
key="some.key"
type="java.io.IOException"
handler="com.yourcorp.ExceptionHandler"/>
</global-exceptions>
這個配置說明了當發生一個IOException時,com.yourcorp.ExceptionHandler.execute將會被調用。
...........
4.6 插件類
Plugin接口繼承了Ation。它定義了兩個接口init,destroy分別在應用啟動和停止時調用。Plugin的一般用法就是在應用啟動時來裝載應用的特定數據。
在運行時,任何被Plugin裝載的數據都可以被Action,或商業邏輯層的類所使用,不過Plugin并沒有提供訪問這些數據的方法。Plugin裝載的數據經常以預先定義好的名字放在應用的上下文中供其他組件使用。
4.7 ActionMapping的實現
Controller Servlet需要知道如何將某個URI映射到一個Action。ActionMapping中可以找到所需的信息:
Type(類型) - Action類的全名。
Name - Action使用的Form Bean的名字。
Path - 匹配此映射的請求URI.
Unknown - 如果設置為真,應用的所有請求將有此AtionMapping來處理。
Validate - 設置為真,Action類的validate方法將會被調用。
Forward - 當映射被調用時,控制流將會傳遞到那個URI。
4.8 編寫Action Mappings
Controller Servlet怎么知道ActionMapping要做什么呢?編寫一個小的JAVA類并且持有一個ActionMapping的實例,通過setter方法來設置屬性是可以做到的。不過Struts提供了通過Digester組件解釋XML的方式來實現。
開發者負責創建一個名字叫struts-config.xml的文件并且把它放在WEB-INF目錄下。
最外層的XML元素必須是<struts-config>,載它的里面有三個比較重要的元素來描述你的Action:
? <form-beans>
? <global-forwards>
? <action-mappings>
<form-beans>
這部分包含了表單Bean的定義。它將用于創建ActionForm。你將使用<form-bean>來定義每個ActionForm,它有如下屬性:
? name: Bean的唯一標識符.
? type: ActionForm的類名。
<global-forwards>
這部分包含了全局性的轉向定義。轉向定義實際上就是Action的execute方法返回的ActionForward。這些定義將映射邏輯名稱到某種資源(如JSP),當我們改變資源名稱時就不要改所有引用的地方。你使用<forward>來定義轉向,它有如下重要的屬性:
? name: 轉向的邏輯名稱。
? path: 資源的上下文路徑. 例如: /index.jsp or /index.do
? redirect: True 或 false (默認). ActionServlet 是不是用重定向(redirect)來取代 轉向( forward)?
<action-mappings>
這部分包含所有的Action映射。你應該使用<action>來定義每一個映射,它包含如下的屬性:
? path: Action所對應的上下文路徑.
? type: Action類.
? name: 與Action配套的<form-bean> 元素的名稱.
4.8.1 ActionMapping例子
<struts-config>
<form-beans>
<form-bean
name="logonForm"
type="org.apache.struts.webapp.example.LogonForm" />
</form-beans>
<global-forwards
type="org.apache.struts.action.ActionForward">
<forward
name="logon"
path="/logon.jsp"
redirect="false" />
</global-forwards>
<action-mappings>
<action
path="/logon"
type="org.apache.struts.webapp.example.LogonAction"
name="logonForm"
scope="request"
input="/logon.jsp"
unknown="false"
validate="true" />
</action-mappings>
</struts-config>
4.9 在頁面中使用ActionMapping
在頁面中配置AtionMapping是你無法通過其他方式設置時的一種方式,它的使用方法為:
<action path="/view" forward="/view.jsp"/>
4.10 在ActionMapping中使用通配符
隨著Struts應用的增大,ActionMapping也就越來越多。通配符則可以將幾個相似的AtionMapping組合成一個。
解釋通配符的最好方法是來看一個例子:
<action
path="/edit*"
type="org.apache.struts.webapp.example.Edit{1}Action"
name="{1}Form"
scope="request"
validate="false">
<forward
name="failure"
path="/mainMenu.jsp"/>
<forward
name="success"
path="/{1}.jsp"/>
</action>
在path屬性中的*號可以匹配請求URI/editSubscription,, editRegistration和其他任何以/edit開頭的URI,但/editSubscription/add將不會被匹配。被匹配的部分將會替換AtionMapping的屬性和轉向(Forward)中的{1}。
通配符可以包含如下特殊字符:
* 匹配零個或多個字符但不包括/
** 匹配零個或多個字符串并且包括/
\character 反斜杠字符串是轉義字符。
4.11 公共的Log 接口
Struts本身并沒有LOG配置,把它交給Commons-Logging是最好的。
5. 配置應用
5.1 概述
在你創建Struts應用之前,應該鋪設一個好的基礎。在你部署Struts應用之前,這里有幾個安裝任務你必須完成,它包括在Struts配置文件和WEB應用部署描述文件中定義相關的內容。
5.2 Struts配置文件
在創建控制組件一章中我們講到了Struts的<form-bean>,<action-mapping>,這些元素在Struts應用的開發中扮演著很重要的角色。其他的配置元素是靜態的:只需設置一次。
不變的配置元素是:
? <controller>
? <message-resources>
? <plug-in>
5.2.1 控制器的配置
<controller>允許你配置ActionServlet。
? bufferSize ? 文件上傳時的輸入緩沖區的字節數. [4096] (可選)
? className ? 配置Bean的類名. [org.apache.struts.config.ControllerConfig] (可選)
? contentType ? 響應輸出內容的類型.可能被the Action, JSP, 或其他資源 覆蓋. [text/html] (可選)
? forwardPattern - <forward>元素的path屬性如果以以斜杠開始時映射到上下文相關的路徑時的替換模式。它可以由如下元素組成:
o $M ? 替換成該模塊的前綴.
o $P ? 替換成<Forward>元素的path屬性.
o $$ - 生成$符號.
$x ? 保留字(x即不是上述字符的其他字符). [$M$P] (可選)
? inputForward - [false] (可選)
? locale - [true] (可選)
? maxFileSize ? 上傳文件的大小.可以以K,M,G為單位(分別代表千,兆,1024兆). [250M] (可選)
? multipartClass - multipart 請求處理類的名稱。 [org.apache.struts.upload.CommonsMultipartRequestHandler] (可選)
? nocache ? 設置HTTP頭來設置是否允許緩存. [false] (可選)
pagePattern -
? processorClass - RequestProcessor 子類的類名. [org.apache.struts.chain.ComposableRequestProcessor] (可選)
? tempDir ? 處理文件上傳時的臨時目錄.
5.2.2 消息資源配置
Struts本身支持應用的國際化,你可以定義一個或多個<message-resources>在你的配置文件中。
? className ? 配置Bean的類名. [org.apache.struts.config.MessageResourcesConfig] (可選)
? factory ? MessageResourcesFactory的類名. [org.apache.struts.util.PropertyMessageResourcesFactory] (可選)
? key - ServletContext 關鍵值來存儲此綁定. [org.apache.struts.action.MESSAGE] (可選)
? null ? 設置為false,將會使找不到相關資源的鍵值顯示 '???keyname???' 而不是null. [true] (可選)
? parameter ? 資源綁定的名稱. (必須)
5.2.3 插件配置
在Struts的配置文件中使用<plug-in>元素來配置插件。<plug-in>只有一個className的屬性。它是完成了org.apache.struts.action.PlugIn interface接口的類的類名。插件需要配置它自身,所以可用<set-property>來做。
<plug-in className="org.apache.struts.tiles.TilesPlugin">
<set-property
property="definitions-config"
value="/WEB-INF/tiles-defs.xml"/>
</plug-in>
5.3 為應用配置模塊
略
5.3.1 模塊配置文件
略
5.3.2 通知控制器
略
5.3.3 切換模塊
略
5.4 WEB應用部署描述符
安裝應用的最后一步是在web.xml包含Struts組件。
5.4.1 配置ActionServlet實例
配置ActionServlet并加上適當的初始化參數
<servlet>
<servlet-name>action</servlet-name>
<servlet-class>
org.apache.struts.action.ActionServlet
</servlet-class>
<init-param>
<param-name>config</param-name>
<param-value>
/WEB-INF/struts-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
5.4.2 配置ActionServlet映射
有兩種方法可以定義URL請求將會被Controller Servlet處理:前綴匹配和后綴匹配。
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>/do/*</url-pattern>
</servlet-mapping>
按如上定義,下面就是前綴匹配
http://www.mycompany.com/myapplication/do/logon <servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
按如上定義,下面就是后綴匹配
http://www.mycompany.com/myapplication/logon.do5.4.3 配置Struts標簽庫
<taglib>
<taglib-uri>
http://struts.apache.org/tags-bean </taglib-uri>
<taglib-location>
/WEB-INF/struts-bean.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
http://struts.apache.org/tags-html </taglib-uri>
<taglib-location>
/WEB-INF/struts-html.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
http://struts.apache.org/tags-logic </taglib-uri>
<taglib-location>
/WEB-INF/struts-logic.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
http://struts.apache.org/tags-tiles </taglib-uri>
<taglib-location>
/WEB-INF/struts-tiles.tld
</taglib-location>
</taglib>
<taglib>
<taglib-uri>
http://struts.apache.org/tags-nested </taglib-uri>
<taglib-location>
/WEB-INF/struts-nested.tld
</taglib-location>
</taglib>
posted on 2005-10-24 22:12
zjw_albert 閱讀(621)
評論(1) 編輯 收藏