Struts
控制器組件負(fù)責(zé)接受用戶請(qǐng)求、更新模型,以及選擇合適的視圖組件返回給用戶。控制器組件有助于將模型層和視圖層分離,有了這種分離,就可以在同一個(gè)模型的基礎(chǔ)上得心應(yīng)手地開發(fā)多種類型的視圖。
Struts
控制器組建主要包括:
?
·
ActionServlet
組件:充當(dāng)
Struts
框架的中央控制器。
·
RequestProcessor
組件:充當(dāng)每個(gè)子應(yīng)用模塊的請(qǐng)求處理器。
·
Action
組件:負(fù)責(zé)處理一項(xiàng)具體的業(yè)務(wù)。
?
Struts
框架采用控制器組件來(lái)預(yù)處理所有的客戶請(qǐng)求,這種集中控制方式可以滿足
MVC
設(shè)計(jì)模式的兩大需求:
?
·首先,控制器在用戶輸入數(shù)據(jù)和模型之間充當(dāng)媒介
/
翻譯者的角色,提供一些通用功能,如安全、登入和其他針對(duì)具體用戶請(qǐng)求的重要服務(wù),當(dāng)系統(tǒng)的這些通用功能出現(xiàn)需求變更時(shí),部需要修改整個(gè)應(yīng)用,只需要修改局部的控制器組件即可。
·其次,由于所有的請(qǐng)求都經(jīng)過(guò)控制器過(guò)濾,因此可以降低視圖組件之間,以及視圖組件和模型組件之間的相互依賴關(guān)系,提高每個(gè)組件的相對(duì)獨(dú)立性。由控制器組件來(lái)決定把合適的視圖組件返回給用用戶,這可以減少視圖組件之間直接的,錯(cuò)綜復(fù)雜的連接關(guān)系,使應(yīng)用更加靈活,便于維護(hù)。
?
Struts
框架采用
ActionServlet
和
RequestProcessor
組件進(jìn)行集中控制,并采用
Action
組件來(lái)處理單項(xiàng)業(yè)務(wù)。
?
?
一
控制器組件的控制機(jī)制
?
Struts
的控制器組件主要完成以下任務(wù):
·接受用戶請(qǐng)求
·根據(jù)用戶請(qǐng)求,調(diào)用合適的模型組件來(lái)執(zhí)行相應(yīng)的業(yè)務(wù)邏輯。
·獲取業(yè)務(wù)邏輯執(zhí)行結(jié)果。
·根據(jù)當(dāng)前狀態(tài)以及業(yè)務(wù)邏輯執(zhí)行結(jié)果,選擇合適的視圖組件返回給用戶。
?
1 Action
類
?
?org.apache.struts.action.ActionServlet
類是
Struts
框架的核心控制器組件,所有的用戶請(qǐng)求都先有
ActionServlet
來(lái)處理,然后再由
ActionServlet
把請(qǐng)求轉(zhuǎn)發(fā)給其他組件。
Struts
框架只允許在一個(gè)應(yīng)用中配置一個(gè)
ActionServlet
類,在應(yīng)用的生命周期中,僅創(chuàng)建
ActionServlet
類的一個(gè)實(shí)例,這個(gè)
ActionServlet
實(shí)例可以同時(shí)響應(yīng)多個(gè)用戶請(qǐng)求。
?
<!--[if !supportLists]-->(a)???<!--[endif]-->Struts框架初始化過(guò)程
<!--[if !supportLists]-->(1)???<!--[endif]-->調(diào)用initInternal()方法,初始化Struts框架內(nèi)在的消息資源,如與系統(tǒng)日志相關(guān)的同志、警告和錯(cuò)誤消息。
<!--[if !supportLists]-->(2)???<!--[endif]-->調(diào)用initOther()方法,從web.xml文件中加載ActionServlet的初始化參數(shù),如config參數(shù)。
<!--[if !supportLists]-->(3)???<!--[endif]-->調(diào)用initServlet()方法,從web.xml文件中加載ActionServlet的URL映射信息。此外還會(huì)注冊(cè)web.xml和Struts配置文件所使用的DTD文件,這些DTD文件用來(lái)驗(yàn)證web.xml和Struts配置文件的語(yǔ)法。
<!--[if !supportLists]-->(4)???<!--[endif]-->調(diào)用initModuleConfig()方法,加載并解析子應(yīng)用模塊的Struts配置文件;創(chuàng)建ModuleConfig對(duì)象,把它存儲(chǔ)在ServletContext中。
<!--[if !supportLists]-->(5)???<!--[endif]-->調(diào)用initModuleMessageResources()方法,加載并初始化默認(rèn)子應(yīng)用模塊的消息資源:創(chuàng)建MessageResources對(duì)象,把它存儲(chǔ)在ServletContext中。
<!--[if !supportLists]-->(6)???<!--[endif]-->調(diào)用initModuleDataSources()方法,加載并初始化默認(rèn)子應(yīng)用模塊的數(shù)據(jù)源。如果在Struts配置文件中沒有定義<data-sources>元素,就忽略這一流程。
<!--[if !supportLists]-->(7)???<!--[endif]-->調(diào)用InitModulePlugins()方法,加載并初始化默認(rèn)子應(yīng)用模塊的所有插件。
<!--[if !supportLists]-->(8)???<!--[endif]-->當(dāng)默認(rèn)子應(yīng)用模塊被成功地初始化后,如果還包括其他子應(yīng)用模塊,將重復(fù)流程(4)~(7),分別對(duì)其他子應(yīng)用模塊進(jìn)行初始化。
?
<!--[if !supportLists]-->(b)???<!--[endif]-->ActionServlet的process()方法
當(dāng)
ActionServlet
實(shí)例接受到
HTTP
請(qǐng)求之后,在
doGet()
或
doPost()
方法都會(huì)調(diào)用
process()
方法來(lái)處理請(qǐng)求。一下是
ActionServlet
的
process()
方法的源代碼:
?
protected voidprocess (HttpServletRequest request, HttpServletResponse response)
throwIOException, ServletException {
?
ModuleUtils.getInstance().selectModule(request,getServletContext());
getRequestProcessor(getModuleConfig(request)).process(request,response);
}
?
在
process()
方法中,首先調(diào)用
org.apache.struts.util.ModuleUtils
類的
selectModule()
方法,這個(gè)方法選擇負(fù)責(zé)處理當(dāng)前請(qǐng)求的子應(yīng)用模塊,然后把與子應(yīng)用模塊相關(guān)的
ModuleConfig
和
MessageResources
對(duì)象存儲(chǔ)倒
request
范圍中,這使得框架的其余組件可以方便地從
request
范圍中讀取這些對(duì)象,從而獲取應(yīng)用配置信息和消息資源。
process()
方法的第二步操作為獲得
RequestProcessor
類的實(shí)例,然后調(diào)用
RequestProcessor
類的
process()
方法,來(lái)完成十幾的預(yù)處理請(qǐng)求操作。
?
?
<!--[if !supportLists]-->(c)???<!--[endif]-->擴(kuò)展ActionServlet類
在
Sturts 1.1
之前的版本中,
ActionServlet
類本身包含了很多處理請(qǐng)求的代碼。從
Struts 1.1
開始,多數(shù)功能被移到
org.apache.struts.action.RequestProcessor
類中,以便減輕
ActionServlet
類的控制負(fù)擔(dān)。
?
盡管新版本的
Struts
框架允許在應(yīng)用中創(chuàng)建礦展
ActionServlet
類的子類,但是這在多數(shù)情況下沒有必要,因?yàn)榭刂破鞯亩鄶?shù)控制功能位于
RequestProcessor
類中。
?
如果實(shí)際應(yīng)用確實(shí)需要?jiǎng)?chuàng)建自己的
ActionServlet
類,則可以創(chuàng)建一個(gè)
ActionServlet
的子類,然后在
web.xml
文件中配置這個(gè)客戶化
ActionServlet
類。
?
如果覆蓋了
init()
方法,應(yīng)該確保首先調(diào)用
super.init()
,它保證
ActionServlet
的默認(rèn)初始化操作被執(zhí)行。除了覆蓋
init()
方法外,事實(shí)上,還可以根據(jù)十幾需要覆蓋
ActionServlet
的任何其他方法。
?
?
2 RequestProcessor
類
?
?
對(duì)于多應(yīng)用模塊的
Struts
應(yīng)用,每個(gè)子應(yīng)用模塊都有各自的
RequestProcessor
實(shí)例。在
ActionServlet
的
process()
方法中,一旦選擇了正確的子應(yīng)用模塊,就會(huì)調(diào)用子應(yīng)用模塊的
RequestProcessor
實(shí)例的
process()
方法來(lái)處理請(qǐng)求。在
ActionServlet
調(diào)用這個(gè)方法時(shí),會(huì)把當(dāng)前的
request
和
response
對(duì)象傳給它。
Struts
框架只允許應(yīng)用中存在一個(gè)
ActionServlet
類,但是可以存在多個(gè)客戶化的
RequestProcessor
類,每個(gè)子應(yīng)用模塊都可以擁有單獨(dú)的
RequestProcessor
類。如果想修改
RequestProcessor
類的一些默認(rèn)功能,可以覆蓋
RequestProcessor
基類中的相關(guān)方法。
?
<!--[if !supportLists]-->(a)???<!--[endif]-->RequestProcessor類的process()方法
RequestProcessor
類的
process()
方法負(fù)責(zé)實(shí)際的預(yù)處理請(qǐng)求操作。
RequestProcessor
類的
process()
方法一次執(zhí)行一下流程:
(1)
調(diào)用
processMultipart()
方法。如果
HTTP
請(qǐng)求方式為
POST
,并且請(qǐng)求的
contentType
屬性以“
multipart/form-data
”開頭,標(biāo)準(zhǔn)的
HttpServletRequest
對(duì)象將被重新包裝,以方便處理“
multipart
”類型的
HTTP
請(qǐng)求。如果請(qǐng)求方式為
GET
,或者
contentType
屬性不是“
multipart
”,就直接返回原始的
HttpServletRequest
對(duì)象。
(2)
調(diào)用
processPath()
方法,獲得請(qǐng)求
URI
的路徑,這一信息可用于選擇合適的
Struts Action
組件。
(3)
調(diào)用
processLocale()
方法,當(dāng)
ControllerConfig
對(duì)象的
locale
屬性為
true
,將讀取用戶請(qǐng)求中包含的
Locale
信息,然后把
Locale
實(shí)例保存在
session
范圍內(nèi)。
(4)
調(diào)用
processContent()
方法,讀取
ControllerConfig
對(duì)象的
contentType
屬性,然后調(diào)用
response.setContentType(contentType)
方法,設(shè)置響應(yīng)結(jié)果的文檔類型和字符編碼。
(5)
調(diào)用
processNoCache()
方法,讀取
ControllerConfig
對(duì)象的
nocache
屬性,如果
nocache
屬性為
true
,在響應(yīng)結(jié)果中將加入特定的頭參數(shù):
Pragma
、
Cache-Control
和
Expires
,防止頁(yè)面被存儲(chǔ)在客戶瀏覽器的緩存中。
(6)
調(diào)用
processPreprocess()
方法。該方法不執(zhí)行任何操作,直接返回
true
。子類可以覆蓋這個(gè)方法,執(zhí)行客戶化的預(yù)處理請(qǐng)求操作。
(7)
調(diào)用
processMapping()
方法,尋找和用戶請(qǐng)求的
URI
匹配的
ActionMapping
。如果不存在這樣的
ActionMapping
,則向用戶返回恰當(dāng)?shù)腻e(cuò)誤消息。
(8)
調(diào)用
processRoles()
方法,先判斷是否為
Action
配置了安全角色,如果配置了安全角色,就調(diào)用
isUserRole()
方法判斷當(dāng)前用戶是否具備必需的角色;如果不具備,就結(jié)束請(qǐng)求處理流程,向用戶返回恰當(dāng)?shù)腻e(cuò)誤消息。
(9)
調(diào)用
processActionForm()
方法,先判斷是否為
ActionMapping
配置了
ActionForm
,如果配置了
ActionForm
,就先從
ActionForm
的存在范圍內(nèi)尋找該
ActionForm
實(shí)例;如果不存在,就創(chuàng)建一個(gè)實(shí)例。接下來(lái)把它保存在合適的范圍中,保存時(shí)使用的屬性
key
為
ActionMapping
的
name
屬性。
(10)
調(diào)用
processActionForm()
方法。如果為
ActionMapping
配置了
ActionForm
,就先調(diào)用
ActionForm
的
reset()
方法,再把請(qǐng)求中的表單數(shù)據(jù)組裝到
ActionForm
中。
(11)
調(diào)用
processValidate()
方法,如果為
ActionMapping
配置了
ActionForm
,并且
ActionMapping
的
validate
屬性為
true
,就調(diào)用
ActionForm
的
validate()
方法。如果
validate()
方法返回的
ActionErrors
對(duì)象中包含
ActionMessage
對(duì)象,說(shuō)明表單驗(yàn)證失敗,就把
ActionErrors
對(duì)象存儲(chǔ)在
request
范圍內(nèi),再把請(qǐng)求轉(zhuǎn)發(fā)到
ActionMapping
的
input
屬性指定的
Web
組件。如果
ActionForm
的
validate()
方法執(zhí)行表單驗(yàn)證成功,就繼續(xù)執(zhí)行下一步請(qǐng)求處理流程。
(12)
調(diào)用
processForward()
方法,判斷是否在
ActionMapping
中配置了
forward
屬性。如果配置了這個(gè)屬性,就調(diào)用
RequestDispatcher
的
forward()
方法,請(qǐng)求處理流程結(jié)束,否則繼續(xù)下一步。
(13)
調(diào)用
processInclude()
方法,判斷是否在
ActionMapping
中配置了
include
屬性。如果配置了這個(gè)屬性,就調(diào)用
RequestDispatcher
的
include()
方法,請(qǐng)求處理流程結(jié)束,否則繼續(xù)下一步。
(14)
調(diào)用
processActionCreate()
方法,先判斷是否在
Action
緩存中存在這個(gè)
Action
實(shí)例,如果不存在,就創(chuàng)建一個(gè)
Action
實(shí)例,把它保存在
Action
緩存中。
(15)
調(diào)用
processActionPerform()
方法,該方法再調(diào)用
Action
實(shí)例的
execute()
方法。
execute()
方法位于
try/catch
代碼中,以便捕獲異常。
(16)
調(diào)用
processActionForward()
方法,把
Action
的
execute()
方法返回的
ActionForward
對(duì)象作為參數(shù)傳給它。
processActionForward()
根據(jù)
ActionForward
對(duì)象包含的請(qǐng)求轉(zhuǎn)發(fā)信息來(lái)執(zhí)行請(qǐng)求轉(zhuǎn)發(fā)或重定向。
?
<!--[if !supportLists]-->(b)???<!--[endif]-->擴(kuò)展RequestProcessor類
開發(fā)人員可以很方便地創(chuàng)建客戶化的
RequestProcessor
類。
在
Struts
配置文件中,
<controller>
元素的
processorClass
屬性
RequestProcessor
類。
?
?
3 Action
類
Action
類是用戶請(qǐng)求和業(yè)務(wù)邏輯之間的橋梁。每個(gè)
Action
充當(dāng)客戶的一項(xiàng)業(yè)務(wù)代理。在
RequestProcessor
類預(yù)處理請(qǐng)求時(shí),在創(chuàng)建了
Action
的實(shí)例后,就調(diào)用自身的
processActionPerform()
方法,該方法再調(diào)用
Action
類的
execute()
方法。
Action
的
execute()
方法調(diào)用模型的業(yè)務(wù)方法,完成用戶請(qǐng)求的業(yè)務(wù)邏輯,然后根據(jù)執(zhí)行結(jié)果把請(qǐng)求轉(zhuǎn)發(fā)給其他合適的
Web
組件。
?
<!--[if !supportLists]-->(a)???<!--[endif]-->Action類緩存
為了確保線程安全
(thread-safe)
,在一個(gè)應(yīng)用的生命周期中,
Struts
框架只會(huì)為每個(gè)
Action
類創(chuàng)建一個(gè)
Action
實(shí)例。所有的客戶請(qǐng)求共享一個(gè)
Action
實(shí)例,并且所有請(qǐng)求線程可以同時(shí)執(zhí)行它的
execute()
方法。
RequestProcessor
類包含一個(gè)
HashMap
,作為存放所有
Action
實(shí)例的緩存,每個(gè)
Action
實(shí)例在緩存中存放的屬性
key
為
Action
類名。在
RequestProcessor
類的
processActionCreate()
方法中,首先檢查在
HashMap
中是否存在
Action
實(shí)例,如果存在,就返回這個(gè)實(shí)例;否則,就創(chuàng)建一個(gè)新的
Action
實(shí)例。創(chuàng)建
Action
實(shí)例的代碼位于同步代碼塊中,以保證只有一個(gè)線程創(chuàng)建
Action
實(shí)例。一旦線程創(chuàng)建了
Action
實(shí)例并把它存放到
HashMap
中,以后所有的線程就會(huì)直接使用這個(gè)緩存中的實(shí)例。
?
<!--[if !supportLists]-->(b)???<!--[endif]-->ActionForward類
Action
類的
execute()
方法返回一個(gè)
ActionForward
對(duì)象。
ActionForward
對(duì)象代表了
Web
資源的邏輯抽象,這里的
Web
資源可以是
JSP
頁(yè)、
Java Servlet
或
Action
。從
execute()
方法中返回
ActionForward
對(duì)象有兩種方法:
·
在
execute()
方法中動(dòng)態(tài)創(chuàng)建一個(gè)
ActionForward
實(shí)例
·
在
Struts
配置文件中配置
<forward>
元素。
???
???
配置了
<forward>
元素后,在
Struts
框架初始化時(shí)就會(huì)創(chuàng)建存放
<forward>
元素;
??
在
execute()
方法中只需調(diào)用
ActionMapping
實(shí)例的
findForward()
方法,來(lái)獲取特定的
ActionForward
實(shí)例。
findForward()
方法先調(diào)用
findForwardConfig()
方法,在
Action
級(jí)別(即
<action>
元素內(nèi)的
<forward>
子元素)尋找匹配的
ActionForward
對(duì)象。如果沒有,再在全局級(jí)別(即
<global-forwards>
元素內(nèi)的
<forward>
子元素)中尋找匹配的
ActionForward
對(duì)象。如果找到,就返回該
ActionForward
對(duì)象。如果
findForward()
方法沒有找到匹配的
ActionForward
對(duì)象,它不會(huì)拋出異常,而是返回
null
。在瀏覽器端,用戶將收到一個(gè)空白頁(yè)。
采用第二種方式,無(wú)需在程序中硬編碼來(lái)指定轉(zhuǎn)發(fā)資源的無(wú)力路徑,而是在配置文件中配置轉(zhuǎn)發(fā)資源,程序中秩序引用轉(zhuǎn)發(fā)資源的邏輯名即可,這提高了應(yīng)用的靈活性和可維護(hù)性。
?
<!--[if !supportLists]-->(c)???<!--[endif]-->創(chuàng)建支持多線程的Action類
在
Struts
應(yīng)用的生命周期中,只會(huì)為每個(gè)
Action
類創(chuàng)建一個(gè)實(shí)例,所有的客戶請(qǐng)求共享這個(gè)實(shí)例。因此,必需保證在多線程環(huán)境中,
Action
也能正常工作。保證線程安全的重要元素是在
Action
類中僅僅使用局部變量,謹(jǐn)慎地使用實(shí)例變量。
如果在
Action
的
execute()
方法中定義了局部變量,對(duì)于每個(gè)調(diào)用
execute()
方法的線程,
Java
虛擬機(jī)會(huì)在每個(gè)線程的堆棧中創(chuàng)建局部變量,因此每個(gè)線程擁有獨(dú)立的局部變量,不會(huì)被其他線程共享。當(dāng)線程執(zhí)行完
execute()
方法時(shí),它的局部變量就會(huì)被銷毀。
如果在
Action
類中定義了實(shí)例變量,那么在
Action
實(shí)例的整個(gè)生命周期中,這個(gè)實(shí)例變量被所有的請(qǐng)求線程共享。因此不能在
Action
類中定義代表特定客戶狀態(tài)的實(shí)例變量。
在
Action
類中定義的實(shí)例變量代表了可以被所有請(qǐng)求線程訪問(wèn)的共享資源。為了避免共享資源的競(jìng)爭(zhēng),在必要的情況下,需要采用
Java
同步機(jī)制對(duì)訪問(wèn)共享資源的代碼塊進(jìn)行同步。
?
(d)Action
類的安全
在某些情況下,如果
Action
類執(zhí)行的功能非常重要,則只允許具有特定權(quán)限的用戶才能訪問(wèn)該
Action
。為了防止未授權(quán)的用戶來(lái)訪問(wèn)
Action
,可以在配置
Action
時(shí)指定安全角色。
<action>
元素的
roles
屬性指定訪問(wèn)這個(gè)
Action
的用戶必須具備的安全角色,多個(gè)角色之間以逗號(hào)隔開。
RequestProcessor
類在預(yù)處理請(qǐng)求時(shí)會(huì)調(diào)用自身的
processRoles()
方法,該方法先檢查在配置文件中是否未
Action
配置了安全角色,如果配置了安全角色,就調(diào)用
HttpServletRequest
的
isUserInRole()
方法,來(lái)判斷用戶是否具備了必要的安全角色。如果不具備,就直接向客戶端返回錯(cuò)誤。
?
?
?
二
使用內(nèi)置的
StrutsAction
類
?
Struts
提供了一些現(xiàn)成的
Action
類,在
Struts
應(yīng)用中直接使用這些
Action
類可以大大節(jié)省開發(fā)時(shí)間。
?
1 org.apache.struts.actions.ForwardAction
類
?
在
JSP
網(wǎng)頁(yè)中,盡管可以直接通過(guò)
<jsp:forward>
標(biāo)簽把請(qǐng)求轉(zhuǎn)發(fā)給其他
Web
組件,但是
Struts
框架提倡先把請(qǐng)求轉(zhuǎn)發(fā)給控制器,再由控制器來(lái)負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)。
?
?
有控制器來(lái)負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā)有以下一些優(yōu)點(diǎn):
·控制器具有預(yù)處理請(qǐng)求功能,它能夠選擇正確的子應(yīng)用模塊來(lái)處理請(qǐng)求,并且把子應(yīng)用模塊的
ModuleConfig
和
MessageResources
對(duì)象存放在
request
范圍內(nèi)。這樣,請(qǐng)求轉(zhuǎn)發(fā)的目標(biāo)
Web
組件就可以正常地訪問(wèn)
ModuleConfig
和
MessageResources
對(duì)象。
·如果
JSP
頁(yè)面中包含
HTML
表單,那么控制器能夠創(chuàng)建和這個(gè)表單對(duì)應(yīng)的
ActionForm
對(duì)象,把用戶輸入表單數(shù)據(jù)組裝到
ActionForm
中。如果
<action>
元素的
validate
屬性為
true
,那么還會(huì)調(diào)用
ActionForm
的表單驗(yàn)證方法。控制器把
ActionForm
對(duì)象存放在
request
或
session
范圍內(nèi),這樣請(qǐng)求轉(zhuǎn)發(fā)的目標(biāo)
Web
組件也可以訪問(wèn)
ActionForm
。
·
JSP
網(wǎng)頁(yè)之間直接相互轉(zhuǎn)發(fā)違背了
MVC
的分層原則,按照
MVC
設(shè)計(jì)思想,控制器負(fù)責(zé)處理所有請(qǐng)求,然后選擇適當(dāng)?shù)囊晥D組件返回給用戶,如果直接讓
JSP
相互調(diào)用,控制器就失去了流程控制作用。
?
?
對(duì)于用戶自定義的
Action
類,既可以負(fù)責(zé)請(qǐng)求轉(zhuǎn)發(fā),還可以充當(dāng)客戶端的業(yè)務(wù)代理,如果僅僅需要
Action
類提供請(qǐng)求轉(zhuǎn)發(fā)功能,則可以使用
org.apache.struts.actions.ForwardAction
類。
ForwardAction
類專門用于轉(zhuǎn)發(fā)請(qǐng)求,不執(zhí)行任何其他業(yè)務(wù)操作。
? ActionServlet
把請(qǐng)求轉(zhuǎn)發(fā)給
ForwardAction
,
ForwardAction
再把請(qǐng)求轉(zhuǎn)發(fā)給
<action>
元素中
parameter
屬性指定的
Web
組件。總之,在
Web
組件之間通過(guò)
ForwardAction
類來(lái)進(jìn)行請(qǐng)求轉(zhuǎn)發(fā),可以充分利用
Struts
控制器的預(yù)處理請(qǐng)求功能。此外,也可以通過(guò)
<action>
元素的
forward
屬性來(lái)實(shí)現(xiàn)請(qǐng)求轉(zhuǎn)發(fā)。
?
2 org.apache.struts.actions.IncludeAction
類
?
在
JSP
網(wǎng)頁(yè)中,盡管可以直接通過(guò)
<include>
指令包含另一個(gè)
Web
組件,但是
Struts
框架提倡先把請(qǐng)求轉(zhuǎn)發(fā)給控制器,再由控制器來(lái)負(fù)責(zé)包含其他
Web
組件。
IncludeAction
類提供了包含其他
Web
組件的功能。與
ForwardAction
一樣,
Web
組件通過(guò)
IncludeAction
類來(lái)包含另一個(gè)
Web
組件,可以充分利用
Struts
控制器的預(yù)處理功能。
<action>
的
paramter
屬性指定需要包含的
Web
組件。此外,也可以通過(guò)
<action>
元素的
include
屬性來(lái)包含
Web
組件。
?
3 org.apache.struts.actions.DispatchAction
類
?
通常,在一個(gè)
Action
類中,只能完成一種業(yè)務(wù)操作,如果希望在同一個(gè)
Action
類中完成一組相關(guān)的業(yè)務(wù)操作,可以使用
DispatchAction
類。
?
創(chuàng)建一個(gè)擴(kuò)展
DispatchAction
類的子類,不必覆蓋
execute()
方法,而是創(chuàng)建一些實(shí)現(xiàn)實(shí)際業(yè)務(wù)操作的方法,這些業(yè)務(wù)方法都應(yīng)該和
execute()
方法具有同樣的方法簽名,即他們的參數(shù)和返回類型都應(yīng)該相同,此外也應(yīng)該聲明拋出
Exception
。
?
在配置
DispatchAction
類時(shí),需要把
parameter
屬性設(shè)置為“
method
”。設(shè)置之后,當(dāng)用戶請(qǐng)求訪問(wèn)
DispatchAction
時(shí),應(yīng)該提供
method
請(qǐng)求參數(shù)。
?
4 org.apache.struts.actions.LookupDispatchAction
類
LookupDispatchAction
類是
DispatchAction
的子類,在
LookupDispatchAction
類中也可以定義多個(gè)業(yè)務(wù)方法。通常
LookupDispatchAction
主要應(yīng)用于在一個(gè)表單中有多個(gè)提交按鈕,而這些按鈕又有一個(gè)共同的名字的場(chǎng)合,這些按鈕的名字和具體的
ActionMapping
的
parameter
屬性值相對(duì)應(yīng)。
在
Struts
配置文件中配置
LookUpDispatchAction
:
在
<action>
元素中,設(shè)置
parameter
屬性時(shí),需要使它和
<html:submit>
標(biāo)簽的
property
屬性保持一致。
?
5 org.apache.struts.actions.SwitchAction
類
SwitchAction
類用于子應(yīng)用模塊之間的切換。對(duì)于請(qǐng)求訪問(wèn)
SwitchAction
的
URL
,需要提供兩個(gè)參數(shù):
·
prefix
:指定子應(yīng)用模塊的前綴,以“
/
”開頭,默認(rèn)子應(yīng)用模塊的前綴為空字符串“”。
·
page
:指定被請(qǐng)求
Web
組件的
URI
,只需指定相對(duì)于被切換后的子應(yīng)用模塊的相對(duì)路徑。
?
?
三
利用
Token
解決重復(fù)提交
?
?
在某些情況下,如果用戶對(duì)同一個(gè)
HTML
表單多次提交,
Web
應(yīng)用必需能夠判斷用戶的重復(fù)提交行為,以作出相應(yīng)的處理。
?
可以利用同步令牌(
Token
)機(jī)制來(lái)解決
Web
應(yīng)用中重復(fù)提交的問(wèn)題,
Struts
也給出了一個(gè)參考實(shí)現(xiàn)。
org.apache.struuts.action.Action
類中提供了一系列和
Token
相關(guān)的方法:
?
·
protected boolean isTokenValid(javax.servlet.http.HttpServletRequestrequest)
判斷存儲(chǔ)在當(dāng)前用戶會(huì)話中的令牌值和請(qǐng)求參數(shù)中的令牌值是否匹配。如果匹配,就返回
true
,否則返回
false
。只要符合一下情況之一,就返回
false
:
·不能存在
HttpSession
對(duì)象。
·在
session
范圍內(nèi)沒有保存令牌值。
·在請(qǐng)求參數(shù)中沒有令牌值
·存儲(chǔ)在當(dāng)前用戶
session
范圍內(nèi)的令牌值和請(qǐng)求參數(shù)中的令牌值不匹配。
?
·
protected voidresetToken(javax.servlet.http.HttpServletRequest request)
從當(dāng)前
session
范圍內(nèi)刪除令牌屬性。
?
·
protected voidsaveToken(javax.servlet.http.HttpServletRequest request)
創(chuàng)建一個(gè)新的令牌,并把它保存在當(dāng)前
session
范圍內(nèi)。如果
HttpSession
對(duì)象不存在,就首先創(chuàng)建一個(gè)
HttpSession
對(duì)象。
?
?
具體的
Token
處理邏輯由
org.apache.struts.util.TokenProcessor
類來(lái)完成,它的
generateToken(request)
方法根據(jù)用戶會(huì)話
ID
和當(dāng)前系統(tǒng)時(shí)間來(lái)生成一個(gè)唯一的令牌。
?
?
四
實(shí)用類
?
?
在創(chuàng)建
Web
應(yīng)用時(shí),有許多檢索和處理
HTTP
請(qǐng)求的操作時(shí)重復(fù)的。為了提高應(yīng)用代碼的可重用性,減少冗余,
Struts
框架提供了一組提供這些通用功能的實(shí)用類,它們可以被所有的
Struts
應(yīng)用共享。
?
1 RequestUtils
類
org.apache.struts.util.RequestUtils
為
Struts
控制框架提供了一些處理請(qǐng)求的通用方法。
RequestUtils
類中的所有方法都是線程安全的,在這個(gè)類中沒有定義任何實(shí)例變量,所有的方法都被聲明為
static
類型。因此,不必創(chuàng)建
RequestUtils
類的實(shí)例,可以直接通過(guò)類名來(lái)訪問(wèn)這些方法。
RequestUtils
類的常用方法
方法
|
描述
|
absoluteURL(HttpServletRequest request,String utl)
|
創(chuàng)建并返回絕對(duì)
URL
路徑,參數(shù)
path
指定相對(duì)于上下文(
context-relative
)的相對(duì)路徑
|
createActionForm(HttpServletRequest request, ActionMapping mapping, ModuleConfig moduleConfig, ActionServlet servlet)
|
先從
request
或
session
范圍內(nèi)查找該
ActionForm
,如果存在,就直接將它返回,否則先創(chuàng)建它的實(shí)例,把它保存在
request
或
session
范圍內(nèi),再把它返回。
mapping
參數(shù)包含了
<action>
元素的配置信息,例如它的
scope
屬性指定
ActionForm
的范圍
|
populate(Object bean, HttpServletRequest request)
|
把
HTTP
請(qǐng)求中的參數(shù)值組裝到指定的
JavaBean
中,請(qǐng)求的參數(shù)名和
JavaBean
的屬性名匹配。當(dāng)
ActionServlet
把用戶輸入的表單數(shù)據(jù)組裝到
ActionForm
中時(shí),就調(diào)用此方法
|
?
2 TagUtils
類
org.apache.struts.taglib.TagUtil
類為
JSP
標(biāo)簽處理類提供了許多實(shí)例方法,如果要使用
TagUtils
類,首先應(yīng)調(diào)用
TagUtils.getInstance()
方法,獲得
TagUtils
類的實(shí)例,
getInstance()
方法為靜態(tài)方法。
TagUtils
類的常用方法
方法
|
描述
|
getInstance()
|
返回一個(gè)
TagUtils
的實(shí)例。該方法為靜態(tài)的,如果要在程序中獲得
TagUtils
的實(shí)例,可以調(diào)用
TagUtils.getInstance()
方法
|
getActionMessages(PageContext pageContext, String paramName)
|
調(diào)用
pageContext.findAttribute(paramName)
方法,從
page, request, session
和
application
范圍內(nèi)減縮并返回
ActionMessages
對(duì)象,參數(shù)
paramName
指定檢索
ActionMessages
對(duì)象的屬性
key
|
getModuleConfig(PageContext pageContext)
|
返回
ModuleConfig
對(duì)象,如果不存在,就返回
null
|
lookup(PageContext pageContext, String name, String scope)
|
返回特定范圍內(nèi)的
JavaBean
。參數(shù)
scope
指定
JavaBean
的所在范圍,
name
參數(shù)指定
JavaBean
在特定范圍內(nèi)的名字
|
message(PageContext pageContext, String bundle, String locale, String key)
|
從指定的
Resource Bundle
中返回一條消息文本,參數(shù)
locale
指定
Locale
,參數(shù)
key
指定消息
key
|
write(PageContext pageContext, String text)
|
向網(wǎng)頁(yè)上輸入特定的文本,參數(shù)
text
用于指定文本內(nèi)容
|
?
3 ModuleUtils
類
org.apache.struts.taglib.ModuleUtils
類提供了處理子應(yīng)用模塊的實(shí)用方法,如果要使用
ModuleUtils
類,首先應(yīng)該調(diào)用
ModuleUtils.getInstance()
方法,獲得
ModuleUtils
類的實(shí)例,
getInstance()
方法為靜態(tài)方法。
ModuleUtils
類的常用方法
方法
|
描述
|
getInstance()
|
返回一個(gè)
ModuleUtils
的實(shí)例。該方法為靜態(tài)的,如果要在程序中獲得
ModuleUtils
的實(shí)例,可以調(diào)用
ModuleUtils.getInstance()
方法。
|
getModuleConfig(javax.servlet.http.HttpervletRequest request)
|
從
request
范圍內(nèi)檢索并返回
ModuleConfig
對(duì)象
|
getModuleConfig(java.lang.String prefix, javax.servlet.ServletContext context)
|
從
application
范圍內(nèi)檢索并返回
ModuleConfig
對(duì)象,參數(shù)
prefix
指定子應(yīng)用模塊名的前綴
|
getModuleName(javax.servlet.http.HttpServletRequest request, javax.servlet.ServletContext context)
|
返回請(qǐng)求訪問(wèn)的子應(yīng)用模塊的名字
|
selectModule(javax.servlet.http.HttpServletRequest request, javax.servlet.ServletContext context)
|
選擇請(qǐng)求訪問(wèn)的子應(yīng)用模塊,把和子應(yīng)用模塊相關(guān)的
ModuleConfig
和
MessageResources
對(duì)象存儲(chǔ)到
request
范圍中
|
?
4 Globals
類
org.apache.struts.Globals
類提供一組公共類型的靜態(tài)常量,被用作在特定范圍內(nèi)存放
JavaBean
的屬性
key
。
Globals
類中定義的常量
方法
|
描述
|
ACTION_SERVLET_KEY
|
代表在
application
范圍內(nèi)存放
ActionServlet
實(shí)例的屬性
key
|
DATA_SOURCE_KEY
|
代表在
application
范圍內(nèi)存放默認(rèn)的
DataSource
實(shí)例的屬性
key
|
ERROR_KEY
|
代表在
request
范圍內(nèi)存放
ActionErrors
實(shí)例的屬性
key
|
LOCALE_KEY
|
代表在
session
范圍內(nèi)存放
Locale
實(shí)例的屬性
key
|
MAPPING_KEY
|
代表在
request
范圍內(nèi)存放
ActionMapping
實(shí)例的屬性
key
|
MESSAGE_KEY
|
代表在
request
范圍內(nèi)存放
ActionMessages
實(shí)例的屬性
key
|
MESSAGES_KEY
|
代表在
application
范圍內(nèi)存放各個(gè)子應(yīng)用模塊的
MessageResources
實(shí)例的屬性
key
的前綴
|
MODULE_KEY
|
代表在
application
范圍內(nèi)存放各個(gè)子應(yīng)用模塊的
ModuleConfig
實(shí)例的屬性
key
的前綴
|
REQUEST_PROCESSOR_KEY
|
代表在
application
范圍內(nèi)存放各個(gè)子應(yīng)用模塊的
RequestProcessor
實(shí)例的屬性
key
的前綴
|
閱讀材料:《精通Struts:基于MVC的Java Web設(shè)計(jì)與開發(fā)》
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=372708