Struts framework
的工作原理和組件
對于
Struts
如何控制、處理客戶請求,讓我們通過對
struts
的四個(gè)核心組件介紹來具體說明。這幾個(gè)組件就是:
ActionServlet
。
Action Classes
,
Action Mapping
(此處包括
ActionForward
),
ActionFrom Bean
。
Struts ActionServlet
控制器對象
??????
ActionServlet
繼承自
javax.servlet.http.HttpServlet
類
,
其在
Struts framework
中扮演的角色是中心控制器。
它提供一個(gè)中心位置來處理全部的終端請求。
控制器
ActionServlet
主要負(fù)責(zé)將
HTTP
的客戶請求信息組裝后,根據(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>
全部的請求
URI
以
*.do
的模式存在并映射到這個(gè)
servlet
,
其配置如下
:
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
一個(gè)該模式的請求
URI
符合如下格式:
????????????? http://www.my_site_name.com/mycontext/actionName.do
?
中心控制器為所有的表示層請求提供了一個(gè)集中的訪問點(diǎn)。這個(gè)控制器提供的抽象概念減輕了開發(fā)者建立公共應(yīng)用系統(tǒng)服務(wù)的困難,如管理視圖、會(huì)話及表單數(shù)據(jù)。它也提供一個(gè)通用機(jī)制如錯(cuò)誤及異常處理,導(dǎo)航,國際化,數(shù)據(jù)驗(yàn)證,數(shù)據(jù)轉(zhuǎn)換等。
?
當(dāng)用戶向服務(wù)器端提交請求的時(shí)候,實(shí)際上信息是首先發(fā)送到控制器
ActionServlet
,一旦控制器獲得了請求,其就會(huì)將請求信息傳交給一些輔助類(
help classes
)處理。這些輔助類知道如何去處理與請求信息所對應(yīng)的業(yè)務(wù)操作。在
Struts
中,這個(gè)輔助類就是
org.apache.struts.action.Action
。通常開發(fā)者需要自己繼承
Aciton
類,從而實(shí)現(xiàn)自己的
Action
實(shí)例。
Struts Action Classes
??????
ActionServlet
把
全部提交的請求都被控制器委托到
RequestProcessor
對象。
RequestProcessor
使用
struts-config.xml
文件檢查請求
URI
找到動(dòng)作
Action
標(biāo)示符。
一個(gè)
Action
類的角色,就像客戶請求動(dòng)作和業(yè)務(wù)邏輯處理之間的一個(gè)適配器(
Adaptor
),其功能就是將請求與業(yè)務(wù)邏輯分開。這樣的分離,使得客戶請求和
Action
類之間可以有多個(gè)點(diǎn)對點(diǎn)的映射。而且
Action
類通常還提供了其它的輔助功能,比如:認(rèn)證(
authorization
)、日志(
logging
)和數(shù)據(jù)驗(yàn)證(
validation
)。
public ActionForward execute(ActionMapping
?
mapping,
???????????????????????????? ActionForm
?
form,
?????
???????????????????????javax.servlet.ServletRequest
?
request,
???????????????????????????? javax.servlet.ServletResponse
?
response)
????????????????????? throws java.io.IOException,javax.servlet.ServletException
?
?????? Action
最為常用的是
execute
()方法。(注意,以前的
perform
方法在
struts1.1
中已經(jīng)不再支持),還有一個(gè)
execute
()方法,請參考
apidoc
,在此不在說明。
??????
當(dāng)
Controller
收到客戶的請求的時(shí)候,在將請求轉(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
()方法如何被訪問:
Action
實(shí)例的
execute()
方法
??????
注意,客戶自己繼承的
Action
子類,必須重寫
execute
()方法,因?yàn)?/span>
Action
類在默認(rèn)情況下是返回
null
的。
Struts Action Mapping
上面講到了一個(gè)客戶請求是如何被控制器轉(zhuǎn)發(fā)和處理的,但是,控制器如何知道什么樣的信息轉(zhuǎn)發(fā)到什么樣的
Action
類呢?這就需要一些與動(dòng)作和請求信息相對應(yīng)的映射配置說明。在
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í)例對應(yīng)。下表就顯示了一個(gè)登陸的配置映射。
<action-mappings>
? <action? path="/logonAction"
?????????? type="com.test.LogonAction"
?????????? name="LogonForm"
?????????? scope="request"
?????????? input="logoncheck.jsp"
validate="false">
<forward name="welcome" path="/welcome.jsp"/>
<forward name="failure" path="/logon_failure.jsp "/>
</action>
</action-mappings>
?
?
<form-beans>
? <form-bean? name="LoginForm"
type="com.test.LoginForm"/>
</form-beans>
上面的配置表示:當(dāng)可以通過
/logonAction.do
(此處假設(shè)配置的控制器映射為
*.do
)提交請求信息的時(shí)候,控制器將信息委托
com.test.LogonAction
處理。調(diào)用
LogonAction
實(shí)例的
execute()
方法。同時(shí)將
Mapping
實(shí)例和所對應(yīng)的
LogonForm Bean
信息傳入。其中
name=LogonForm
,使用的
form-bean
元素所聲明的
ActionForm Bean
。有關(guān)
form-bean
的申明如下顯示。
使用
ActionForward
導(dǎo)航
元素
<forward>
則表示了當(dāng)
Action
實(shí)例的
execute()
方法運(yùn)行完畢或,控制器根據(jù)
Mapping
可將響應(yīng)信息轉(zhuǎn)到適當(dāng)?shù)牡胤健H缟厦娆F(xiàn)實(shí),如果客戶登陸成功,則調(diào)用
welcome forward
,將成功信息返回到
/welcome.jsp
頁面。在你的
execute()
方法的結(jié)尾可以使用下面的實(shí)例代碼而返回
welcome forward
。當(dāng)然你的
welcome forward
必須在
action
元素屬性中定義,正如上面所聲明的那樣。
return (mapping.findForward("welcome"));
?
??????
ActionForward
對象是配置對象。這些配置對象擁有獨(dú)一無二的標(biāo)識(shí)以允許它們按照有意義的名稱如
“success”
,
“failure”
等來檢索。
ActionForward
對象封裝了向前進(jìn)的
URL
路徑且被請求處理器用于識(shí)別目標(biāo)視圖。
ActionForward
對象建立自
<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í)行請求處理器的
execute(…)
方法的結(jié)果,當(dāng)傳遞一個(gè)值匹配指定于
<forward>
元素中
name
屬性的值的時(shí)候,下一個(gè)視圖可以在
execute(…)
方法中被開發(fā)者用方便的方法
org.apache.struts.action.ActionMapping.findForward(…)
選擇。
ActionMapping.findForward(…)
方法既從它的本地范圍又從全局范圍提供一個(gè)
ActionForward
對象,該對象返回至
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(…)
方法。下例舉例說明了
redirect
屬性的用法:
??????
? <forward name="success" path="/Catalog.jsp" redirect="true"/>
如果
redirect=true, URL
建立如
/contextPath/path
因?yàn)?/span>
HttpServletResponse.sendRedirect(…)
中解釋
URL
采用
”/”
開頭相對于
servlet
容器根目錄。
如果
redirect=false, URI
建立如
/path
因?yàn)?/span>
ServletContext.getRequestDisptacher(…)
采用虛擬目錄相關(guān)
URL
。
?
在此稍稍說一下有關(guān)
global-forwards
的概念。其在配置文件中描述了整個(gè)應(yīng)用系統(tǒng)可以使用的
ActionForward
,而不是僅僅是一個(gè)特定的
Action
。
?
?<global-forwards>
??? <forward name="logout" path="/logout.do"/>
<forward name="error"? path="/error.jsp"/>
? </global-forwards>
?
Struts ActionForm Bean
捕獲表單數(shù)據(jù)
在上面講解
ActionServlet
,
Action Classes
和
Action Mapping
的時(shí)候,我們都提到了
ActionForm Bean
的概念。一個(gè)應(yīng)用系統(tǒng)的消息轉(zhuǎn)移(或者說狀態(tài)轉(zhuǎn)移)的非持久性數(shù)據(jù)存儲(chǔ),是由
ActionForm Bean
的負(fù)責(zé)保持的。
?????? ActionForm
派生的對象用于保存請求對象的參數(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
對象的表單
bean
。該
ActionForm
對象在指定的活動(dòng)范圍內(nèi)被用
<action>
元素的
name
屬性找到;
RequestProcessor
將隨后重新安排表單屬性,用請求時(shí)參數(shù)填充表單,隨即調(diào)用表單對象的
validate(…)
方法以履行服務(wù)器端用戶輸入驗(yàn)證。僅當(dāng)
ActionMapping
對象中
validate
屬性被設(shè)為
true
時(shí),
validate(…)
方法被調(diào)用;這就是默認(rèn)的行為。
request.getParameterValues(parameterName)
被用于得到一個(gè)
String[]
對象,它用來表單填充;驗(yàn)證的結(jié)果應(yīng)該是一個(gè)
ActionErrors
對象,用
org.apache.struts.taglib.html.ErrorsTag
來顯示驗(yàn)證錯(cuò)誤給用戶。
ActionForm
也可以被用于為當(dāng)前用戶保存即將被一個(gè)視圖引用的中間模型狀態(tài)。
當(dāng)一個(gè)表單對象被
RequestProcessor
找到,它被傳遞到請求處理器的
execute(…)
方法。一個(gè)
ActionForm
對象也可以被請求處理器建立。表單對象建立目的是提供中間模型狀態(tài)給使用請求范圍
JSP
;這將確保對象不會(huì)在有效性過期后仍然存在。默認(rèn)的,所有的表單都被保存為會(huì)話范圍。會(huì)話中表單對象脫離有效性的存在可能導(dǎo)致浪費(fèi)內(nèi)存,同樣的,請求處理器必須跟蹤保存在會(huì)話中的表單對象的生命周期。一個(gè)好的捕獲表單數(shù)據(jù)的實(shí)踐是為橫跨多用戶交互的相關(guān)表單用一個(gè)單獨(dú)的表單
bean
。表單
bean
也可以在反饋的時(shí)候用來儲(chǔ)存能夠被自定義標(biāo)簽改變的中間模型狀態(tài)。在視圖中標(biāo)簽用法避免結(jié)合
Java
代碼,因此要成一個(gè)好的任務(wù)劃分,
web
生產(chǎn)組主要處理標(biāo)志,而應(yīng)用開發(fā)組主要處理
Java
代碼。標(biāo)簽因素退出訪問中間模型狀態(tài)的邏輯;當(dāng)訪問嵌套的對象或當(dāng)通過聚集列舉時(shí)這個(gè)邏輯可能很復(fù)雜。
注意:在
struts1.1
中,
ActionForm
的校驗(yàn)功能,逐漸被剝離出來(當(dāng)然依然可以使用)。使用了
validator framework
對整個(gè)應(yīng)用系統(tǒng)的表單數(shù)據(jù)驗(yàn)證進(jìn)行統(tǒng)一管理。相信信息請參考:
http://home.earthlink.net/~dwinterfeldt
在
ActionForm
的使用中,
Struts
提倡使用到值對象(
Value Object
)。這樣將客戶或開發(fā)人員,對數(shù)據(jù)狀態(tài)與對象狀態(tài)能夠更加清晰的理解和使用。
對于每一個(gè)客戶請求,
Struts framework
在處理
ActionForm
的時(shí)候,一般需要經(jīng)歷如下幾個(gè)步驟:
(1)檢查
Action
的映射,確定
Action
中已經(jīng)配置了對
ActionForm
的映射
??????
(2)根據(jù)
name
屬性,查找
form bean
的配置信息
??????
(3)檢查
Action
的
formbean
的使用范圍,確定在此范圍下,是否已經(jīng)有此
form bean
的實(shí)例。
??????
(4)假如當(dāng)前范圍下,已經(jīng)存在了此
form bean
的實(shí)例,而是對當(dāng)前請求來說,是同一種類型的話,那么就重用。
??????
(5)否則,就重新構(gòu)建一個(gè)
form bean
的實(shí)例
??????
(6)
form bean
的
reset()
方法備調(diào)用
??????
(7)調(diào)用對應(yīng)的
setter
方法,對狀態(tài)屬性賦值
??????
(8)如果
validatede
的屬性北設(shè)置為
true
,那么就調(diào)用
form bean
的
validate()
方法。
(
9
)如果
validate
()方法沒有返回任何錯(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
等等。讓我們來看看兩個(gè)比較重要的組件:
validationg framework
和
struts taglib
。有關(guān)其他組件請參考
Struts
用戶手冊(
http://jakarta.apache.org/struts/userGuide
)。
??????
Validation Framework for Struts
在
struts1.1
中,新增了
validation framework
。增加了對
form
數(shù)據(jù)提交的驗(yàn)證。將原本需要在
ActionFrom Bean
的
validate
()進(jìn)行的驗(yàn)證通過配置文件的描述進(jìn)行驗(yàn)證。
有關(guān)其詳細(xì)信息,請參考
http://home.earthlink.net/~dwinterfeldt
。個(gè)人建議對于小型應(yīng)用系統(tǒng)可以采用這種配置方式,但是對于應(yīng)用系統(tǒng)中有大量
web
層表單應(yīng)用的系統(tǒng),并且業(yè)務(wù)需求變動(dòng)比較大的,使用
validation framework
可能會(huì)加重開發(fā)難度、系統(tǒng)維護(hù)難度。可以借鑒
validation framework
的
Javascript Validator Tag
。
?
Struts TagLib
?????? struts
提供了一組可擴(kuò)展的自定義標(biāo)簽庫(
TagLib
),可以簡化創(chuàng)建用戶界面的過程。目前包括:
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ì)資料,請參考
BeanUtils
??????
這個(gè)組件的全稱是
Bean Introspection Utilites
。是屬于
Jakarta Commons
項(xiàng)目組的。主要是幫助構(gòu)建
javabean
的屬性操作的(
getter,setter
),已經(jīng)提供一種動(dòng)態(tài)定義和訪問
bean
的屬性。有關(guān)詳細(xì)信息,請參考。
http://jakarta.apache.org/commons/beanutils.html
??????
如果各位對這方面有很興趣,可以參考一些有關(guān)
java
反射(
Reflectio
)方面的資料。
Collections
??????
這個(gè)組件主要是提供了一些集合或列表對象
,
在原有的
java collections framework
的基礎(chǔ)上進(jìn)行了擴(kuò)展。詳細(xì)資料請參考:
http://jakarta.apache.org/commons/collections.html
以及
http://cvs.apache.org/viewcvs/~checkout~/jakarta-commons/collections/STATUS.html?rev=1.13
Digester
??????
這個(gè)組件翻譯成中文的意思是
“
匯編
”
。其主要功能是根據(jù)
xml
配置文件,初始化系統(tǒng)的一些
java
類對象。
Digester
幫助你指定
XML
與
java
對象之間映射模型,而且允許客戶話定制映射規(guī)則(
rules
)。詳細(xì)資料請參考
http://jakarta.apache.org/commons/digester.html
?
?
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=323752