Struts框架
struts框架具有組件的模塊化,靈活性和重用性的優點,同時簡化了基於MVC的web應用程序的開發。
本章詳細討論struts架構。我們將看到struts是如何清晰地區分控制,事務邏輯和外觀,從而簡化了開發應用程序過程的。我們還將介紹struts提供的類如何使得開發工作更加簡單,這些類包括:
l 控制程序流程的類
l 實現和執行程序事務邏輯的類
l 自定義的標記庫使得創建和驗證HTML表單更加容易
1. Struts壓縮包內容
文件夾jakarta-struts-
文件
|
描述
|
jdbc2_0-stdext.jar
|
包含JDBC2.0 Optional Package API類。如果我們要使用struts提供的數據資源,就需要將這個文件拷貝到WEB-INF/lib下
|
Struts.jar
|
包含struts中所有的java類。同樣也需要拷貝到WEB-INF/lib下
|
*.tld
|
標記庫描述器文件,描述了多個struts標記庫中的自定義標記。同樣要拷貝到WEB-INF/lib下
|
在webapps目錄下有如下文件:
Web應用程序
|
描述
|
Struts-blank.war
|
一個簡單的web應用程序
|
Struts-documentation.war
|
包含struts站點上所有struts文檔
|
Struts-example.war
|
Struts很多特性的示範
|
Struts-exercisetaglib.war
|
主要用於對自定義標籤庫進行增加而使用的測試頁,但也可以示範如何使用struts標記
|
Struts-template.war
|
包含struts模板標記的介紹和範例
|
Struts-upload.war
|
一個簡單的例子,示範如何使用struts框架上傳文件
|
2.Struts體系結構
讓我們從MVC角度觀察struts框架中的組件
框架中三個部分:模型,視窗和控制器。
模型
在struts框架中,模型分爲兩個部分:
l 系統的內部狀態
l 可以改變狀態的操作(事務邏輯)
內部狀態通常由一組ActinForm JavaBean表示。根據設計或應用程序複雜度的不同,這些Bean可以是自包含的並具有持續的狀態,或只在需要時才獲得數據(從某個數據庫)。
大型應用程序通常在方法內部封裝事務邏輯(操作),這些方法可以被擁有狀態信息的bean調用。比如購物車bean,它擁有用戶購買商品的信息,可能還有checkOut()方法用來檢查用戶的信用卡,並向倉庫發定貨信息。
小型程序中,操作可能會被內嵌在Action類,它是struts框架中控制器角色的一部分。當邏輯簡單時這個方法很適合。
建議用戶將事務邏輯(要做什麼)與Action類所扮演的角色(決定做什麼)分開。
視窗
由JSP建立,struts包含擴展自定義標籤庫,可以簡化創建完全國際化用戶界面的過程。
控制器
struts中,基本的控制器組件是ActionServlet類中的實例servelt,實際使用的servlet在配置文件中由一組映射(由ActionMapping類進行描述)進行定義。
3.Struts框架中的組件
(由於ROSE工具還未能下載,只能找來這幅圖,它說明了一定問題,特別是ActionErrors,但它並沒有將ActionMapping,JSP和Tag Library包含進來,有時間作完替換)
框架中所使用的組件:
ActionServlet
|
控制器
|
ActionClass
|
包含事務邏輯
|
ActionForm
|
顯示模塊數據
|
ActionMapping
|
幫助控制器將請求映射到操作
|
ActionForward
|
用來指示操作轉移的對象
|
ActionError
|
用來存儲和回收錯誤
|
Struts標記庫
|
可以減輕開發顯示層次的工作
|
下面我們看看各自在框架中所扮演的角色和責任。
3.1 Struts配置文件
這是將struts組件結合在一起的東東:struts-config.xml。默認值
/WEB-INF/struts-config.xml。配置文件可以定義:
l 全局轉發
l ActionMapping類 幫助控制器將請求映射到操作
l ActionForm bean 顯示模塊數據
l JDBC數據源
配置全局轉發
全局轉發用來在JSP頁之間創建邏輯名稱映射。轉發都可以通過對調用操作映射的實例來獲得,例如:
actionMappingInstace.findForward(“logicalName”);
全局轉發的例子:(所有的例子我沒有進行解釋,一是結合表可以理解,二是例子大部分來自系列四的示例,你應該在作完實驗後,再來看一便)
<global-forwards>
<forward name="bookCreated" path="/BookView.jsp"/>
</global-forwards>
屬性
|
描述
|
Name
|
全局轉發的名字
|
Path
|
與目標URL的相對路徑
|
配置ActionMapping
ActionMapping對象幫助進行框架內部的流程控制,它們可將請求URI映射到Action類,並且將Action類與ActionForm bean相關聯。ActionServlet在內部使用這些映射,並將控制轉移到特定Action類的實例。所有Action類使用perform()方法實現特定應用程序代碼,返回一個ActionForward對象,其中包括響應轉發的目標資源名稱。例如:
<action-mappings>
<action path="/createBook"
type="BookAction"
name="bookForm"
scope="request"
input="/CreateBook.jsp">
</action>
<forward name=”failure” path=”/CreateBook.jsp”/>
<forward name=”cancel” path=”/index.jsp”/>
</action-mappings>
屬性
|
描述
|
Path
|
Action類的相對路徑
|
Name
|
與本操作關聯的Action bean的名稱
|
Type
|
連接到本映射的Action類的全稱(可有包名)
|
Scope
|
ActionForm bean的作用域(請求或會話)
|
Prefix
|
用來匹配請求參數與bean屬性的前綴
|
Suffix
|
用來匹配請求參數與bean屬性的後綴
|
attribute
|
作用域名稱。
|
className
|
ActionMapping對象的類的完全限定名默認的類是org.apache.struts.action.ActionMapping
|
input
|
輸入表單的路徑,指向bean發生輸入錯誤必須返回的控制
|
unknown
|
設爲true,操作將被作爲所有沒有定義的ActionMapping的URI的默認操作
|
validate
|
設置爲true,則在調用Action對象上的perform()方法前,ActionServlet將調用ActionForm bean的validate()方法來進行輸入檢查
|
通過<forward>元素,可以定義資源的邏輯名稱,該資源是Action類的響應要轉發的目標。
屬性
|
描述
|
Id
|
ID
|
ClassName
|
ActionForward類的完全限定名,默認是org.apache.struts.action.ActionForward
|
Name
|
操作類訪問ActionForward時所用的邏輯名
|
Path
|
響應轉發的目標資源的路徑
|
redirect
|
若設置爲true,則ActionServlet使用sendRedirect()方法來轉發資源
|
配置ActionForm Bean
ActionServlet使用ActionForm來保存請求的參數,這些bean的屬性名稱與HTTP請求參數中的名稱相對應,控制器將請求參數傳遞到ActionForm bean的實例,然後將這個實例傳送到Action類。例子:
<form-beans>
<form-bean name="bookForm" type="BookForm"/>
</form-beans>
屬性
|
描述
|
Id
|
ID
|
className
|
ActionForm bean的完全限定名,默認值是org.apache.struts.action.ActionFormBean
|
Name
|
表單bean在相關作用域的名稱,這個屬性用來將bean與ActionMapping進行關聯
|
Type
|
類的完全限定名
|
配置JDBC數據源
用<data-sources>元素可以定義多個數據源。
屬性
|
描述
|
Id
|
ID
|
Key
|
Action類使用這個名稱來尋找連接
|
Type
|
實現JDBC接口的類的名稱
|
下面屬性需要<set-property>元素定義,在框架1.1版本中已不在使用,但你可用<data-source>元素。例子:
<data-sources>
<data-source id=”DS
key=”conPool”
type=”org.apache.struts.util.GenericDataSource”
<set-property id=”SP
autoCommit="true"
description="Example Data Source Configuration"
driverClass="org.test.mm.mysql.Driver"
maxCount="4"
minCount="2"
url="jdbc:mysql://localhost/test"
user="struts"
password="wrox" />
<data-source/>
</data-sources>
屬性
|
描述
|
desciption
|
數據源的描述
|
autoCommit
|
數據源創建的連接所使用的默認自動更新數據庫模式
|
driverClass
|
數據源所使用的類,用來顯示JDBC驅動程序接口
|
loginTimeout
|
數據庫登陸時間的限制,以秒爲單位
|
maxCount
|
最多能建立的連接數目
|
minCount
|
要創建的最少連接數目
|
password
|
數據庫訪問的密碼
|
readOnly
|
創建只讀的連接
|
User
|
訪問數據庫的用戶名
|
url
|
JDBC的URL
|
通過指定關鍵字名稱,Action類可以訪問數據源,比如:
javax.sql.DataSource ds = servlet.findDataSource(“conPool”);
javax.sql.Connection con = ds.getConnection();
3.2 ActionServlet類
框架中的控制器組件是有org.apache.struts.action.ActionServlet類實現的,這個類是javax.servlet.http.HttpServlet類的擴展。
Struts controller基本功能是:
1. 截獲用戶的Http請求
2. 把這個請求映射到相應的Action類,如果這是此類收到的第一個請求,將初始化實例並
緩寸。
3. 創建或發現一個ActionForm bean實例(看配置文件是否定義),然後將請求過程移植到
bean.
4. 調用Action實例的perform()方法並將ActioForm bean,Action Mapping對象,request
和response對象傳給它。
如:public ActionForword perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
5.perform返回一個ActionForword對象,此對象連接到相應的jsp頁面.
ActionServlet配置
我們需要在web.xml中聲明ActionServlet,並且將它配置成啓動時進行加載。以下爲可以配置的初始化參數:
參數
|
默認值
|
描述
|
application
|
null
|
應用程序的資源集合的類
|
bufferSize
|
4096
|
文件上傳的緩衝區大小
|
config
|
/WEB-INF/struts-config.xml
|
配置文件的位置和名稱
|
content
|
Text/html
|
默認的內容類型
|
debug
|
0
|
程序調試的級別
|
detail
|
0
|
程序調試細節的級別
|
factory
|
null
|
消息資源工廠,用於國際化中解釋消息資源
|
formBean
|
org.apache.struts.action.ActionFormBean
|
封裝ActionForm bean信息的類的名稱
|
forward
|
org.apache.struts.action.ActionForward
|
封裝ActionForward對象信息的類的名稱
|
locale
|
true
|
爲true,將在用戶會話中存儲一個本地對象
|
mapping
|
org.apache.struts.action.ActionForward
|
封裝ActionMapping信息的類的名稱
|
maxFileSize
|
|
上傳文件的最大尺寸
|
multipartClass
|
org.apache.struts.action.ActionForward
|
處理多部分請求的類的名稱
|
noCache
|
False
|
HTTP標頭是否要設置爲禁止緩寸
|
Null
|
True
|
設置爲true,對於無效的信息關鍵字將返回null
|
tempDir
|
作爲一個servlet參數提供給程序的工作目錄
|
處理下載文件是使用的臨時工作目錄
|
validate
|
True
|
是否使用新格式的配置文件
|
vallidating
|
True
|
是否對配置文件進行有效性分析
|
大多數情況下,標準的servlet就能夠滿足用戶需要。
第一次收到特定請求的URI時,ActionServlet將適當的Action類進行實例化,然後ActionServlet在Action類實例中以servlet爲變量名存儲一個引用。當被實例化後,Action類會被暫存以備再用。
ActionServlet也提供一些方法,由Action類用來訪問數據源和轉發目標之類的資源。
ActionServlet方法
ActinServlet提供了一組能夠被Action對象使用的方法。
Struts API的全部信息在struts-documentation.war中可以找到。動態的添加或刪除,這些方法隻影響應用程序當前的實例:
public void addFormBean(ActionFormBean formBean)
public void removeFormBean(ActionFormBean formBean)
public void addForward(ActionForward actionForward)
public void removeForward(ActionForward actionForward)
public void addMapping(ActionMapping actionMapping)
public void removeMapping(ActionMapping actionMapping)
根據名稱查找對象:
public ActionFormBean findFormBean(String name)
public ActionForward findForward(String name)
public ActionMapping findMapping(String name)
用來處理數據源:
public void addDataSource(String key , DataSource ds)
public DataSource findDataSource(String key)
我們還可以:
l 使用destroy()方法結束ActionServlet
l 使用reload()方法從struts配置文件將信息重新加載。
3.3 ActionMapping類
將特定請求映射到特定Action的相關信息存儲在ActionMapping中,ActionServelt將ActionMapping傳送到Action類的perform()方法,Action將使用ActionMapping的findForward()方法,此方法返回一個指定名稱的ActionForward,這樣Action就完成了本地轉發。若沒有找到具體的ActionForward,就返回一個null.
public ActionForward findForward(String name)
可在映射中動態添加ActionForward:
public void addForward(ActionForward forward)
可返回與映射關聯的表單bean:
public String getName()
可返回映射的屬性域(會話或請求)
public String getScope()
3.4 Action類
Action類真正實現應用程序的事務邏輯,它們負責處理請求。在收到請求後,ActionServlet會:
l 爲這個請求選擇適當的Action
l 如果需要,創建Action的一個實例
l 調用Action的perform()方法
如果ActionServlet不能找到有效的映射,它會調用默認的Action類(在配置文件中定義)。如果找到了ActionServlet將適當的ActionMapping類轉發給Action,這個Action使用ActionMapping找到本地轉發,然後獲得並設置ActionMapping屬性。根據servlet的環境和被覆蓋的perform()方法的簽名,ActionServlet也會傳送ServletRequest對象或HttpServletRequest對象。
所有Action類都擴展org.apache.struts.action.Action類,並且覆蓋類中定義的某一個perform()方法。有兩個perform()方法:
處理非HTTP(一般的)請求:
public ActionForward perform(ActionMapping action,
AcionForm form,
ServletRequest request,
ServletResponse response)
throws IOException,ServletException
處理HTTP請求:
public ActionForward perform(ActionMapping action,
AcionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException,ServletException
Action類必須以“線程安全”的方式進行編程,因爲控制器會令多個同時發生的請求共享同一個實例,相應的,在設計Action類時就需要注意以下幾點:
l 不能使用實例或靜態變量存儲特定請求的狀態信息,它們會在同一個操作中共享跨越請求的全局資源
l 如果要訪問的資源(如JavaBean和會話變量)在並行訪問時需要進行保護,那麼訪問就要進行同步
Action類的方法
除了perform()方法外,還有以下方法:
可以獲得或設置與請求相關聯的區域:
public Locale getLocale(HttpServletRequest request)
public void setLocale(HttpServletRequest request,Locale locale)
爲應用程序獲得消息資源:
public MessageResources getResources()
檢查用戶是否點擊表單上的“取消”鍵,如果是,將返回true:
public Boolean isCancelled(HttpServletRequest request)
當應用程序發生錯誤時,Action類能夠使用下面方法存儲錯誤信息:
public void saveErrors(HttpServletRequest request,ActionErrors errors)
ActionError實例被用來存儲錯誤信息,這個方法在錯誤關鍵字下的請求屬性列表中存儲ActionError對象。通過使用在struts標記庫中定義的自定義標記,JSP頁能夠顯示這些錯誤信息,稍後我們就介紹。
3.5 ActionForm類
框架假設用戶在應用程序中爲每個表單都創建了一個ActionForm bean,對於每個在struts-config.xml文件中定義的bean,框架在調用Action類的perform()方法之前會進行以下操作:
l 在相關聯的關鍵字下,它檢查用於適當類的bean實例的用戶會話,如果在會話中沒有可用的bean,它就會自動創建一個新的bean並添加到用戶的會話中。
l 對於請求中每個與bean屬性名稱對應的參數,Action調用相應的設置方法。
l 當Action perform()被調用時,最新的ActionForm bean傳送給它,參數值就可以立即使用了。
ActionForm類擴展org.apache.struts.action.ActionForm類,程序開發人員創建的bean能夠包含額外的屬性,而且ActionServlet可能使用反射(允許從已加載的對象中回收信息)訪問它。
ActionForm類提供了另一種處理錯誤的手段,提供兩個方法:
Public ActionErrors validate(ActionMappin mapping,
ServletRequest request)
Public ActionErrors validate(ActionMappin mapping,
HttpServletRequest request)
你應該在自己的bean裏覆蓋validate()方法,並在配置文件裏設置<action>元素的validate爲true。在ActionServlet調用Action類前,它會調用validate(),如果返回的ActionErrors不是null,則ActinForm會根據錯誤關鍵字將ActionErrors存儲在請求屬性列表中。
如果返回的不是null,而且長度大於0,則根據錯誤關鍵字將實例存儲在請求的屬性列表中,然後ActionServlet將響應轉發到配置文件<action>元素的input屬性所指向的目標。
如果需要執行特定的數據有效性檢查,最好在Action類中進行這個操作,而不是在ActionForm類中進行。
方法reset()可將bean的屬性恢復到默認值:
public void reset(ActionMapping mapping,HttpServletRequest request)
public void reset(ActionMapping mapping,ServletRequest request)
典型的ActionFrom bean只有屬性的設置與讀取方法(getXXX),而沒有實現事務邏輯的方法。只有簡單的輸入檢查邏輯,使用的目的是爲了存儲用戶在相關表單中輸入的最新數據,以便可以將同一網頁進行再生,同時提供一組錯誤信息,這樣就可以讓用戶修改不正確的輸入數據。而真正對數據有效性進行檢查的是Action類或適當的事務邏輯bean。
3.6 ActionForward類
目的是控制器將Action類的處理結果轉發至目的地。
Action類獲得ActionForward實例的句柄,然後可用三種方法返回到ActionServlet,所以我們可以這樣使用findForward():
l ActionServlet根據名稱獲取一個全局轉發
l ActionMappin實例被傳送到perform()方法,並根據名稱找到一個本地轉發
另一種是調用下面的一個構造器來創建它們自己的一個實例:
public ActionForward()
public ActionForward(String path)
public ActionForward(String path,Boolean redirect)
3.7 錯誤處理
struts提供了兩個類來處理錯誤:ActionErrors和ActionError,它們都擴展org.apache.struts.action。ActionErrors保存着ActionError對象的集合,其中每一個代表了獨立的錯誤信息。每個ActionError都包含了關鍵字,能夠映射到資源文件中存儲的錯誤信息,而這個資源文件是在ActionServlet初始化參數中指定的。
ActionError類
ActionError類定義了一組重載的構造器來創建錯誤信息,第一個構造器方法使用一個字符串作爲參數,例如:
ActionError error = new ActionError(“error.Invalid”);
實例error映射到應用程序資源文件中的一個錯誤消息:
error.invalid=<b>Invalid Number</b>
如果在JSP頁使用<html:error>,用戶就會看見加粗的Invalid Number。
另一種使用了java.text.MessageFormat類,可在消息中指定替換字符串,例如:
error.invalid=<b>Invalid Number{0}</b>
創建一個錯誤消息:
ActionError error = new ActionError(‘error.invalid’,new Double(-1));
JSP頁顯示:Invalild Number –1
還有獲得特定消息的錯誤關鍵字:
public String getKey()
還有獲得替換字符串數組:
public String[] getValues()
ActionError類
ActionError類從不獨立進行錯誤處理,它們總是被存儲在ActionErrors對象中。ActionErrors對象保存ActionError類的集合以及它們特定的屬性值,我們可以使用自己定義的屬性值,或是使用ActionErrors.GLOBAL_ERROR.
下面是典型Action類的perform()中錯誤處理情況:
MyForm form = (MyForm) form;
if (number == -1) {
ActionErrors errors = new ActionErrors();
ActionError error = new ActionError(“error.Invalid”,new Double(-1));
errors.add(ActionErrors.GLOBAL_ERROR,error);
saveErrors(req,errors);
String input = mapping.getInput();
Return new ActionForward(input);
}
ActionErrors有如下有用方法:
方法
|
描述
|
clear()
|
清除所有錯誤信息
|
empty()
|
如果ActionErrors對象是空的,它返回true
|
get()
|
返回錯誤信息。若無參數,所有信息將作爲一個Iterator對象返回
|
properties()
|
返回包含屬性名稱的Iterator,這些屬性至少有一個錯誤
|
size()
|
返回錯誤的數目(整型數)
|
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=545120