JSF請(qǐng)求處理生命周期的高度概述)_第1頁
JSF請(qǐng)求處理生命周期的高度概述)_第2頁
JSF請(qǐng)求處理生命周期的高度概述)_第3頁
JSF請(qǐng)求處理生命周期的高度概述)_第4頁
JSF請(qǐng)求處理生命周期的高度概述)_第5頁
已閱讀5頁,還剩15頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、前一章演示的簡(jiǎn)單JavaServer Faces應(yīng)用程序示例,介紹了 JSF的許多實(shí)用 方面。但是,在進(jìn)入更高級(jí)JSF開發(fā)時(shí),有一個(gè)JSF的關(guān)鍵部分非常重要:請(qǐng)求 處理生命周期。請(qǐng)求處理生命周期擔(dān)當(dāng)著使JavaServer Faces運(yùn)行起來的“幕 后”引擎的角色。本章研究 JavaServer Faces請(qǐng)求處理生命周期背后的關(guān)鍵概 念,并解釋如何用定義良好的基于事件的方式處理Web 青求。對(duì)請(qǐng)求處理生命周期的全面理解非常重要,因?yàn)樵诤罄m(xù)章節(jié)介紹高級(jí)JSF開發(fā)主題時(shí),會(huì)多次提到 請(qǐng)求處理生命周期的不同階段。3.1 JSF請(qǐng)求處理生命周期的高度概述從歷史上看,Web應(yīng)用程序必需的大部分開發(fā),主

2、要是處理We四戶端的HTTP請(qǐng)求。隨著 WebA傳統(tǒng)的靜態(tài)文檔傳送模型(在這種模型中,只請(qǐng)求靜態(tài) We b頁面,沒有參數(shù))轉(zhuǎn)變到動(dòng)態(tài)環(huán)境(要求WebS用程序處理大量進(jìn)入?yún)?shù)),對(duì)日益復(fù)雜的請(qǐng)求的處理需求,不可避免地增長(zhǎng)起來。這使WetS用程序開發(fā)變 得相當(dāng)煩瑣。例如,請(qǐng)看下面在 Java servlet 或JSP小程序中處理進(jìn)入請(qǐng)求參 數(shù) firstname 和 lastname 的代碼:String firstname = request.getParameter("firstname");String lastname = request.getParameter(&q

3、uot;lastname");/ Do something with firstname and lastname考慮到現(xiàn)在多數(shù)高級(jí) WetS用程序即使不處理幾千個(gè),也要處理上百個(gè)參數(shù), 就可以看出上面這種參數(shù)處理方法很容易就會(huì)變得很煩瑣。有經(jīng)驗(yàn)的WebFF發(fā)人員都知道,編寫處理進(jìn)入請(qǐng)求參數(shù)的代碼通常包含以下 步驟: 編寫對(duì)進(jìn)入數(shù)據(jù)執(zhí)行驗(yàn)證并把進(jìn)入數(shù)據(jù)轉(zhuǎn)換成服務(wù)器端數(shù)據(jù)類型的代碼,并在驗(yàn)證/轉(zhuǎn)換失敗時(shí)初始化錯(cuò)誤消息。 編寫用新數(shù)據(jù)更新服務(wù)器端數(shù)據(jù)的代碼。 編寫調(diào)用服務(wù)器端應(yīng)用程序、執(zhí)行數(shù)據(jù)庫查詢之類任務(wù)的代碼。 編寫把響應(yīng)渲染回客戶端的代碼。幸運(yùn)的是,請(qǐng)求處理生命周期可以用一種連貫的

4、、基于事件的方式處理這項(xiàng) 工作。專家組意見 在專家組討論的JavaServer Faces全部元素中,請(qǐng)求處理生命周期得到的貢獻(xiàn)最多,參與的成員最廣,而且 是從1.0規(guī)范開發(fā)之后,發(fā)展最多的元素。例如,最初要求把 view描述放在JSP頁面之外的獨(dú)立XML文件中。因?yàn)榘l(fā)明 了 ViewHandler 類所以撤銷了這個(gè)要求,ViewHandler 類就是在討論生命周期的過程中產(chǎn)生的。3.1.1 請(qǐng)求處理生命周期到底做什么簡(jiǎn)而言之,過去必須自行編寫代碼才能處理的必要的后端處理,現(xiàn)在全由請(qǐng) 求處理生命周期執(zhí)行。除了處理進(jìn)入的請(qǐng)求參數(shù),它還管理服務(wù)器端的用戶界面 組件集,并把它們與用戶在客戶端瀏覽器中

5、看到的組件同步。3.1.2 請(qǐng)求處理生命周期與其他Web技術(shù)的區(qū)別對(duì)比其他更傳統(tǒng)的 亞版術(shù)(從CGI、Java servlet 到Struts 這樣的框架), 請(qǐng)求處理生命周期用定義良好的基于事件的方式自動(dòng)執(zhí)行了大部分常見服務(wù)器 端WetFF發(fā)任務(wù)。使用Jakarta Struts 這樣的框架,用帶有表單bean和Struts動(dòng)作的代碼把 一些請(qǐng)求處理做得更正規(guī),但實(shí)際的數(shù)據(jù)處理仍在較低層次 (與JSF相比)上進(jìn) 行。Struts編程模型對(duì)servlet API提供的抽象比JSF提供的少。例如,在St ruts中,可以這樣定義代表提交表單屬性的表單 Bean:<form-bean nam

6、e="loginbean" type="org.apache.struts.action.DynaActionForm">vform-property name="userid" type="java.lang.String"/>vform-property name="password" type="java.lang.String"/></form-bean>定義之后,可以像下面這樣在應(yīng)用程序中訪問字段值:String userid = (S

7、tring)(DynaActionForm)form).get("userid");這很像能用JSF所做的事情,但在使用Struts時(shí),沒有把字段屬性直接 綁定 到Java類屬性并讓屬性的值在表單提交時(shí)自動(dòng)同步的能力。3.1.3 自動(dòng)服務(wù)器端視圖管理和同步如圖3-1所示,JSF請(qǐng)求處理生命周期能把服務(wù)器端 Java Bean屬性自動(dòng)同 步到有層次的組件集(根據(jù)呈現(xiàn)給客戶端用戶的用戶界面) 的能力,是它與其他 WebJJ術(shù)相比的主要優(yōu)勢(shì)。由于Web天生是無狀態(tài)的,即客戶端與服務(wù)器之間的一個(gè)事務(wù)對(duì)前一個(gè)事務(wù) 沒有記憶,所以JavaServer Faces通過自動(dòng)維護(hù)代表客戶端當(dāng)

8、前狀態(tài)的服務(wù)器 端視圖(view)而解決了這個(gè)問題。這允許JSF開發(fā)人員把精力集中在服務(wù)器端 組件,由請(qǐng)求處理生命周期或“銜接”(plumbing)負(fù)責(zé)服務(wù)器端視圖的同步和在客戶端瀏覽器上顯示什么。編寫代碼處理每個(gè)請(qǐng)求值或者修改用戶界面狀態(tài)的 煩瑣工作,都通過一組階段(phase)(每個(gè)階段中,都用連貫的方式執(zhí)行具體 的數(shù)據(jù)處理任務(wù))由JavaServer Faces請(qǐng)求處理生命周期自動(dòng)處理JSt'AppLi圖3-1客戶端用戶界面的服務(wù)器端表示3.1.4 請(qǐng)求處理生命周期階段是什么處理進(jìn)入的請(qǐng)求數(shù)據(jù),通常需要不同類型的工作,包括檢查進(jìn)入的數(shù)據(jù)是否 有效、觸發(fā)服務(wù)器端的應(yīng)用程序邏輯以完成

9、請(qǐng)求,以及最后把響應(yīng)渲染給客戶端。 JSF請(qǐng)求處理生命周期用前后連貫的順序執(zhí)行這些任務(wù),而且在一組定義良好的階段的控制之下。這種方式允許每個(gè)階段清晰地描述執(zhí)行本階段之前需要存在的 前提條件,以及本階段執(zhí)行之后會(huì)存在的后置條件。下面是生命周期的各個(gè)階段。 恢復(fù)視圖:在內(nèi)存中恢復(fù)或創(chuàng)建代表客戶端用戶界面信息的服務(wù)器端組件樹(視圖)。 應(yīng)用請(qǐng)求值:用來自客戶端的最新數(shù)據(jù)更新這些服務(wù)器端組件。 處理驗(yàn)證:對(duì)新數(shù)據(jù)執(zhí)行驗(yàn)證和數(shù)據(jù)類型轉(zhuǎn)換。 更新模型值:用新數(shù)據(jù)更新服務(wù)器端模型對(duì)象。 調(diào)用應(yīng)用程序:調(diào)用滿足請(qǐng)求所需要的應(yīng)用程序邏輯,然后如果有需要,再導(dǎo)航到新頁 面。 渲染響應(yīng):把響應(yīng)渲染給請(qǐng)求客戶端。圖3

10、-2顯示了這些階段合在一起構(gòu)成的請(qǐng)求處理生命周期的高級(jí)視圖??梢载灤┍菊潞涂吹剑鼒?zhí)行了 Wete用程序中的對(duì)進(jìn)入數(shù)據(jù)進(jìn)行處理的全部任務(wù)。本書的其余部分,將介紹這個(gè)圖中的不同事件和階段。FkbisW求現(xiàn)在來深入研究每個(gè)生命周期處理階段中到底發(fā)生了什么。姓附 H件響以宛畋事件圖3-2 JavaServer Faces請(qǐng)求處理生命周期1 .恢復(fù)視圖前面提到過,F(xiàn)aces視圖是用戶界面組件的服務(wù)器端樹,它提供了在客戶端 顯示的用戶界面的鏡像表示(請(qǐng)參見圖 3-3)。恢復(fù)視圖階段的任務(wù)是根據(jù)前一 個(gè)事務(wù)恢復(fù)現(xiàn)有視圖,或者根據(jù)新請(qǐng)求創(chuàng)建新視圖。如果是新請(qǐng)求(“沒有回傳”), 就創(chuàng)建新視圖,并保存在父容器

11、對(duì)象 FacesContext內(nèi)。FacesContext充當(dāng)與當(dāng) 前請(qǐng)求有關(guān)的數(shù)據(jù)在通過整個(gè)請(qǐng)求處理生命周期過程中的存儲(chǔ)。We»F發(fā)人員不必?fù)?dān)心多個(gè)用戶請(qǐng)求會(huì)把 FacesContext中的應(yīng)用程序數(shù)據(jù)混淆,因?yàn)閟ervlet API保證請(qǐng)求操作是線程安全的,即所有對(duì) FacesContext的操作,都保證是在 一個(gè)獨(dú)立線程上針對(duì)每個(gè)用戶請(qǐng)求進(jìn)行的。";H-詞rHa. j ,rr i ”if,ir ljHtm 曬putRx*utPe時(shí)L 4innBnpuxTe-KL卜匚修叱兩制4盟展;理 IpLrni廊e氤噂1世而nN證癡;唾I l II 也We即got圖3-3服務(wù)器端用

12、戶界面組件樹(又稱作視圖”)2 .應(yīng)用請(qǐng)求值恢復(fù)了視圖之后的下一階段一一 應(yīng)用請(qǐng)求值階段一一做的是對(duì)進(jìn)入的請(qǐng)求值或信息名稱-值對(duì)進(jìn)行處理。視圖層次結(jié)構(gòu)中的每個(gè)用戶界面組件節(jié)點(diǎn),現(xiàn)在都 能得到客戶端發(fā)送來的更新值,如圖 3-4所示JKF 1皿kiraliuti App/n |t(WTr 4rrdLdllT .&力 i-4 r»HMd&eb cl-One-fta & 口W5e*rlHb iiF£el«L-3reMerAj|jmi Hki氤ItiTdli lulTtWLiLTeil用 LiFitlri 網(wǎng)ilrtgTrntJI V.dVjRn,

13、:圖3-4應(yīng)用請(qǐng)求值在幕后,JSF運(yùn)行時(shí)在用戶界面組件樹的視圖(或 UIViewRoot)上調(diào)用高級(jí) 方法(processDecodes(),把請(qǐng)求值應(yīng)用到用戶界面組件。這導(dǎo)致所有子組 件都遞歸地調(diào)用它們的processDecodes()方法。在第10章將會(huì)看到,用戶界 面組件的processDecodes()方法或者更具體的decode()方法,允許組件對(duì) 進(jìn)入的請(qǐng)求名稱-值對(duì)進(jìn)行“解碼”,并把匹配的新進(jìn)入值應(yīng)用到用戶界面組件 的value屬性。應(yīng)當(dāng)指出,只有能夠容納值的用戶界面組件(例如輸入字段)才有新值應(yīng)用 到它們。一般來說,有兩類組件:一類是有值的組件,例如文本字段、復(fù)選框和 標(biāo)簽;另

14、一類是引起動(dòng)作的組件,例如按鈕和鏈接。所有具有value屬性的組件 都實(shí)現(xiàn)ValueHolder接口。所有表單元素類型的組件,如果它的值可以由用戶編 輯,那么就都實(shí)現(xiàn)EditableValueHolder 接口。所有引起動(dòng)作的組件(按鈕或鏈 接)都實(shí)現(xiàn) ActionSource 接口。JSF1.2 提示 對(duì)于 JSF 1.2,動(dòng)作組件實(shí)現(xiàn)的是 ActionSource2 接口,而不是 ActionSource。ActionSource2 擴(kuò)展自 JSF 1.1 的ActionSource ,它允許使用1.2中新的統(tǒng)一 EL。關(guān)于1.2中統(tǒng)一 EL的細(xì)節(jié),將在第4章提供。例如,按鈕(UIComm

15、andE其他實(shí)現(xiàn)ActionSource的組件)在表單提交期間, 不用新值更新;它只需記錄自己是否被單擊。如果單擊了,就引起稱為動(dòng)作事件 (ActionEvent )的事件進(jìn)入隊(duì)列。稍后就會(huì)看到動(dòng)作事件到底是什么,以及它 如何允許與按鈕或鏈接單擊相對(duì)應(yīng)的定制代碼的執(zhí)行。雖然請(qǐng)求處理生命周期用連貫的方式處理不同階段,但階段的執(zhí)行順序可以 為特殊情況而變化。例如,可能想向表單添加一個(gè)Cancel按鈕。在單擊時(shí),它會(huì)跳過所有驗(yàn)證,不處理表單的值,直接導(dǎo)航到另一個(gè)頁面。要改變請(qǐng)求處理生 命周期的處理順序,只需設(shè)置組件的immediate屬性。本章后面將會(huì)介紹,在不 同的組件上設(shè)置immediate屬性

16、會(huì)有不同的效果。3 .處理驗(yàn)證應(yīng)用請(qǐng)求值階段完成之后,就要執(zhí)行對(duì)進(jìn)入數(shù)據(jù)進(jìn)行轉(zhuǎn)換和驗(yàn)證的處理驗(yàn)證階段(第7章將詳細(xì)解釋數(shù)據(jù)類型轉(zhuǎn)換和驗(yàn)證)。JSF運(yùn)行時(shí)調(diào)用主processValidators( )方法(在 UIViewRoot 實(shí)例上),啟動(dòng)這個(gè)階段。processValidat ors()與processDecodes()方法類似,也是遞歸地進(jìn)入組件樹,調(diào)用每個(gè)組 件的 processValidators( )方法。在調(diào)用每個(gè)組件的 processValidators( ) 方法時(shí),與組件相關(guān)的轉(zhuǎn)換器或驗(yàn)證器就會(huì)被調(diào)用。 注意 數(shù)據(jù)類型轉(zhuǎn)換實(shí)際是發(fā)生在驗(yàn)證之前,但是在同一處理驗(yàn)證階段內(nèi)開始

17、。這是必需的,因?yàn)橐獔?zhí)行驗(yàn)證,數(shù)據(jù)首先 必須轉(zhuǎn)換成服務(wù)器端數(shù)據(jù)類型。在第2章的JSFReg示例中看到過,驗(yàn)證器和轉(zhuǎn)換器可以用若干種方式與用戶 界面組件關(guān)聯(lián)。在示例中,驗(yàn)證請(qǐng)求可以通過設(shè)置組件本身的屬性(例如把 inp utText組件的required屬性設(shè)置為“ true ”)與組件關(guān)聯(lián),也可以通過注冊(cè)定制驗(yàn)證代碼(例如通過設(shè)置組件的validator 屬性,向組件附加電子郵件驗(yàn)證方 法)與組件關(guān)聯(lián)。第2章的示例也有一個(gè)轉(zhuǎn)換器,通過插入 convertDateTime 轉(zhuǎn)換器標(biāo)簽作為輸入組件的子組件,與“出生日期" ( dob) inputText (UIInp ut)組件關(guān)聯(lián)。驗(yàn)

18、證(或轉(zhuǎn)換)失敗的組件的 valid屬性會(huì)設(shè)置成“false ",并把FacesM essage消息放進(jìn)FacesContext隊(duì)列,如圖3-5所示。然后,當(dāng)響應(yīng)被渲染回用 戶(在渲染響應(yīng) 階段)時(shí),可以用Faces的Message或Messages組件顯示消息, 以便用戶糾正錯(cuò)誤或重新提交。JSKm沁it &叩LtflMfitVjilnua Ms#-i 。皿“2 i JdaiMli LllKIEEF2iri'-d M D* Mln左 MdJtn <c fCcmtd Frii" AJi-iisJl. ka/dad 印望 小知"U SefflC

19、r Unt OaMt * E 圖3-5處理驗(yàn)證階段中遇到驗(yàn)證和轉(zhuǎn)換錯(cuò)誤4 .更新模型值假設(shè)進(jìn)入的數(shù)據(jù)已經(jīng)通過驗(yàn)證和轉(zhuǎn)換,現(xiàn)在要把數(shù)據(jù)分配給值綁定到用戶界面組件的模型對(duì)象?;貞浺幌碌?2章的示例。在這個(gè)示例中,我們創(chuàng)建了一個(gè) J ava類UserBean,把它注冊(cè)成托管bean,并用JSF表達(dá)式語言把屬性綁定到貢 面上的不同用戶界面組件。正是在 更新模型值階段,實(shí)際的托管bean或模型對(duì) 象的屬性,被它們綁定的用戶界面組件的新值更新。這個(gè)操作背后實(shí)際的機(jī)制與其他階段相似:在 UIViewRoot實(shí)例上調(diào)用proc essUpdates()方法,初始化processUpdates()組件方法的逐級(jí)

20、調(diào)用,proc essUpdates()方法又對(duì)每個(gè)類型為UIInput或者從它擴(kuò)展的組件調(diào)用updateM odel()方法。這么做是合理的,因?yàn)閁IInput類型的組件(例如輸入字段、選 擇菜單)是能夠把用戶輸入值傳遞給模型屬性的唯一組件類型。如圖 3-6所示, 在這個(gè)階段末尾,模型對(duì)象(托管 bean)的值綁定屬性都被來自組件的新值更 新。這個(gè)階段揭示了 JavaServer Faces的一部分秘密:只要把JavaBean屬性綁 定到一組JSF用戶界面組件,不需要手動(dòng)編碼,它們就能自動(dòng)更新。glSalectlta司Html3««4CT(fWR«llCHtin

21、lMrtHWwirntn汽竹SeanUwUewi,U*iMAn,Q nCtLfrrt I 卜用 eW*f|,rug* 加惻 kbUuv&Mn 4MMMf)<User6eana«ma l|WWIi圖3-6在更新模型值階段更新模型對(duì)象屬性KtfTiCcrwTwwiadrMj5 .調(diào)用應(yīng)用程序現(xiàn)在,已經(jīng)看到了 JSF請(qǐng)求處理生命周期如何執(zhí)行從 Web請(qǐng)求獲得進(jìn)入數(shù)據(jù)、 驗(yàn)證數(shù)據(jù)/把數(shù)據(jù)轉(zhuǎn)換成合適的服務(wù)器端數(shù)據(jù)類型,以及把數(shù)據(jù)分配給模型對(duì)象 等工作。對(duì)Webff發(fā)人員來說,這只是Wetg用程序編寫工作的一半。另一半是: 取得進(jìn)入數(shù)據(jù),真正對(duì)數(shù)據(jù)進(jìn)行操作,例如調(diào)用處理數(shù)據(jù)的外部方

22、法。這正是調(diào)用應(yīng)用程序階段的作用?;貞洷菊虑懊嫠觯脩艚缑娼M件既可以容納值(實(shí)現(xiàn) EditableValueHold er)也可以是ActionEvent來源(實(shí)現(xiàn)ActionSource )(例如在單擊按鈕(UI Command時(shí))。定制動(dòng)作代碼,又稱為 動(dòng)作方法或動(dòng)作偵聽器方法就是在調(diào)用 應(yīng)用程序階段調(diào)用的。幕后,在調(diào)用應(yīng)用程序階段中,UIViewRoot的processApplication( )方 法被調(diào)用,它又把隊(duì)列中這個(gè)階段的事件廣播到每個(gè)實(shí)現(xiàn)ActionSource (對(duì)JSF 1.2 是 ActionSource2 )的 UIComponent組件。這是通過調(diào)用每個(gè) UICo

23、mpone nt的broadcast)方法做到的,實(shí)際上就是“觸發(fā)了” 動(dòng)作事件,接著就由動(dòng)作偵聽器處理這些動(dòng)作事件??梢杂媚J(rèn)動(dòng)作偵聽器編寫定制動(dòng)作方法或動(dòng)作偵 聽器方法并把它們綁定到 UIComponent (實(shí)現(xiàn)ActionSource 的UIComponent), 處理動(dòng)作事件。編寫定制動(dòng)作方 法或動(dòng)作偵聽器方法,并把它們綁定到實(shí)現(xiàn)ActionSource的UlComponent,為開發(fā)人員提供了參與請(qǐng)求處理生命周期的鉤子(hook),通過鉤子,開發(fā)人員就能調(diào)用任何定制邏輯。圖 3-7演示了這一點(diǎn)。UlVlewRwtami 叫rI| / I| 1一、> nyBMMddCDnfir

24、nwciJiBrjI圖3-7在調(diào)用應(yīng)用程序階段調(diào)用定制應(yīng)用程序邏輯第8章將重新研究JSF事件模型到底如何工作,并提供關(guān)于 Faces事件處理 確切順序的更多細(xì)節(jié)。還應(yīng)當(dāng)指出,導(dǎo)航到不同頁面,也發(fā)生在調(diào)用應(yīng)用程序階段。第5章將介紹一個(gè)基本的登錄應(yīng)用程序,研究導(dǎo)航到底是怎么發(fā)生的。登錄應(yīng)用程序使用了一 個(gè)綁定到login (UICommanc技鈕的簡(jiǎn)單動(dòng)作。當(dāng)用戶單擊按鈕時(shí),觸發(fā)動(dòng)作事 件,動(dòng)作事件又在調(diào)用應(yīng)用程序階段調(diào)用定制動(dòng)作方法,處理登錄憑據(jù)。請(qǐng)記住,這個(gè)代碼只有在進(jìn)入的數(shù)據(jù)已經(jīng)通過前面階段(轉(zhuǎn)換和驗(yàn)證已經(jīng)完成)之后才會(huì)執(zhí)行。登錄成功時(shí),會(huì)導(dǎo)航到新頁面。6.渲染響應(yīng)現(xiàn)在到了 JSF請(qǐng)求處理生

25、命周期的最后階段,在這個(gè)階段渲染響應(yīng)。為把整 個(gè)響應(yīng)渲染回客戶端,又一次逐級(jí)對(duì)每個(gè)組件調(diào)用encodeXX()方法。在第10章將學(xué)習(xí)到,編碼方法是用戶界面組件(或者更具體點(diǎn),組件的渲染器)向客戶 端渲染組件的方法。渲染的標(biāo)記語言可以是任何語言,例如HTML WMLXM導(dǎo)除了把響應(yīng)渲染給客戶端,渲染響應(yīng)階段還保存視圖的當(dāng)前狀態(tài),以便可以 在后續(xù)Web青求中訪問和恢復(fù)狀態(tài)。圖3-8演示了如何用客戶端標(biāo)記渲染響應(yīng)。 這時(shí),視圖的當(dāng)前狀態(tài)被保存下來,供未來請(qǐng)求之用。另外,實(shí)際還有更多精細(xì)的幕后細(xì)節(jié)與渲染響應(yīng)階段有關(guān),但本章介紹的范 圍之內(nèi)。其中包括:處理靜態(tài)內(nèi)容(又稱為“模板”源)與組件的動(dòng)態(tài)內(nèi)容交織

26、 的情況;處理各種動(dòng)態(tài)輸出源;在保持順序正確的同時(shí)把它們協(xié)調(diào)成一個(gè)可視的 響應(yīng)。一般來說,使用JSF時(shí)不需要處理這些細(xì)節(jié)。圖3-8在渲染響應(yīng)階段渲染響應(yīng)并保存狀態(tài)JSF1.2提示 渲染響應(yīng)階段在JSF 1.2中被顯著地重新設(shè)計(jì)了,以解決由于 HTML、JSP定制標(biāo)簽和JSF組件在一個(gè)頁面 中混雜而引起的一些棘手問題。這些問題的主要誘因,是為了渲染而執(zhí)行JSP頁面,而且在執(zhí)行頁面的同時(shí)構(gòu)建組件樹”這一要求。這要求JSP和JSF都要寫入同一輸出流,有時(shí)會(huì)造成渲染輸出以意外順序出現(xiàn)。JSF 1.2中的新方法是:只為構(gòu)建樹這個(gè)唯一目標(biāo)執(zhí)行頁面,而不為渲染頁面執(zhí)行它。頁面中的原始HTML/標(biāo)記和JSP定

27、制標(biāo)簽輸出被轉(zhuǎn)化成瞬態(tài) UlOutput組件(不在頁面狀態(tài)中保存)。這樣,頁面執(zhí)行之后,頁面的整個(gè)內(nèi)容 就表示在視圖層次結(jié)構(gòu)中,視圖又被遞歸遍歷,就像其他生命周期階段一樣3.2 實(shí)際觀察請(qǐng)求處理生命周期看過每個(gè)請(qǐng)求處理生命周期階段背后的理論之后,是時(shí)候看看生命周期的實(shí)際作用了?;仡櫟?章所示的JSF注冊(cè)(JSFRe。應(yīng)用程序(如圖3-9所示)。 我們要作為與應(yīng)用程序交互并提交注冊(cè)表單 (register.jsp )的用戶,經(jīng)歷全部 生命周期階段。(1)查看register.jsp 頁面的初始請(qǐng)求:為了第一時(shí)間看到注冊(cè)表單頁面, 用戶需要直接發(fā)送對(duì)注冊(cè)頁面URL的請(qǐng)求,用精簡(jiǎn)方式觸發(fā)請(qǐng)求處理生命

28、周期的 一次運(yùn)行。請(qǐng)求首先由Faces控制器servlet處理,控制器為這個(gè)請(qǐng)求創(chuàng)建一個(gè) FacesContext實(shí)例,并初始化對(duì)生命周期的調(diào)用。由于這是查看注冊(cè)頁面的初 始請(qǐng)求(也叫做“無回傳”請(qǐng)求),恢復(fù)視圖階段創(chuàng)建一個(gè)空視圖( UIViewRoo t)組件樹,并把它保存在 FacesContext實(shí)例中。J. 'fei-: p irrnl nn 1. pp nn<l'K3ri >Inlvrnri M k,.她城 01KB NJSF RegiiilTfltiDn Afip1111mliI mnLmHeGMfO 福ik 0 FigDiiroCBrlAi:m 刎EE

29、mi 圻 iirwr*Ifj,1 ,LK4 m«Mfi圖3-9 register.jsp: JSFReg應(yīng)用程序的注冊(cè)頁面視圖創(chuàng)建之后,因?yàn)樵谡?qǐng)求中沒有進(jìn)入字段數(shù)據(jù)需要驗(yàn)證或處理(也叫做“無回傳”請(qǐng)求),生命周期立即前進(jìn)到渲染響應(yīng)階段。在這個(gè)階段,空視圖組件樹 由注冊(cè)頁面源代碼中引用的組件(顯示輸入字段和提交按鈕)填充。樹填充之后, 組件就把自己渲染到客戶端。同時(shí),保存視圖組件樹的狀態(tài),供后續(xù)請(qǐng)求使用。用戶現(xiàn)在看到在瀏覽器中渲染的注冊(cè)頁面。(2)用戶在注冊(cè)頁面中輸入無效數(shù)據(jù):假設(shè)用戶忘記輸入了自己的姓,還輸入了格式錯(cuò)誤的日期,就單擊了 Register按鈕(如圖3-10所示)。曰 A

30、 EkTipM JngHrr Fz出 Fte怖£rr-itER 阡141Gt 0門 - Ml即6;而 k-鬲: “ 衿 £» F.rgw 訴看 咋*審:-j.i -> ITtp:r-V«:*¥M> »MQ>rwrteW.fe®¥; Qtid :=iMSiSgiiiiiSgSgiSgigSiMSggggiiiwSBSSiiBSBSSiSBiia>iiSSii 二一一 .'JSK KpgislrativH AppH ¥ glralis FirmFfdtFflfiK sQan工詡

31、部郵任VrtdoftDn &n»r VSx ii rtqjnrciQtadsf- Miiv O FwiMr3uflkrh -"呻"i網(wǎng)、110出閨澳 c w加1KqmdEFTwd 學(xué)如l畫gBE 上玨!電.5k和由I電嗎西 '心油1 融 Cww*l« d *力 ww*圖3-10在注冊(cè)頁面輸入錯(cuò)誤數(shù)據(jù)當(dāng)JSF運(yùn)行時(shí)接收到請(qǐng)求時(shí),進(jìn)入初始的恢復(fù)/創(chuàng)建視圖階段,這次它恢復(fù)剛 才在用戶前一個(gè)請(qǐng)求之后保存的視圖組件樹。這通常叫做“回傳”,因?yàn)檫@個(gè)請(qǐng) 求的HTT叨法是POST(因?yàn)橐皞魉汀毙卤韱螖?shù)據(jù))。然后進(jìn)入應(yīng)用請(qǐng)求值階 段,即使請(qǐng)求中的進(jìn)入值不

32、完全有效,也用請(qǐng)求中的進(jìn)入值更新組件。在這個(gè)階段沒有錯(cuò)誤發(fā)生,因?yàn)槊總€(gè)用戶界面組件只是把請(qǐng)求參數(shù)的提交值保存為Strin g值,還不是轉(zhuǎn)換后的(服務(wù)器端數(shù)據(jù)類型)值或驗(yàn)證過的值。用戶界面組件把 這個(gè)值保存在一個(gè)特殊的經(jīng)過預(yù)轉(zhuǎn)換/預(yù)驗(yàn)證的submittedValue JavaBean屬性 中,它只是原樣保存請(qǐng)求參數(shù)的String值。應(yīng)用請(qǐng)求值階段完成后,啟動(dòng)處理驗(yàn)證階段。這時(shí),由于進(jìn)入的日期數(shù)據(jù)格 式無效,無法轉(zhuǎn)變成java.util.Date數(shù)據(jù)類型(對(duì)應(yīng)著托管 bean UserBean的“dob”屬性),發(fā)生轉(zhuǎn)換錯(cuò)誤。一條消息被放入隊(duì)列,組件被標(biāo)記為無效,處 理繼續(xù)進(jìn)行。余下的有效字段值被

33、應(yīng)用到對(duì)應(yīng)的用戶界面組件。在每個(gè)用戶界面組件調(diào)用它的驗(yàn)證方法時(shí),要容納 lastName值的組件遇到 驗(yàn)證錯(cuò)誤,因?yàn)樵诨貍髡?qǐng)求中沒有為它提供值。還記得前面姓氏輸入字段的 equired ”屬性設(shè)置為“ true ”。作為驗(yàn)證錯(cuò)誤的結(jié)果,生命周期把UIInput組件lname (last name )的屬性設(shè)置為無效,并把對(duì)應(yīng)的表示這個(gè)字段必須有值 的Faces消息放入隊(duì)列。這時(shí),處理驗(yàn)證階段完成。因?yàn)橛序?yàn)證和轉(zhuǎn)換錯(cuò)誤,所以生命周期直接跳到渲染響應(yīng)階段,然后渲染同 一個(gè)注冊(cè)頁面(register.jsp ),把對(duì)應(yīng)的錯(cuò)誤消息放在last name字段和日期 字段旁邊。回想一下,每個(gè)消息組件到每個(gè)

34、輸入字段組件的分配,是通過分配它們的ID實(shí)現(xiàn)的,如下所示:<h:inputText value="#UserBean.lastName" required="true" id="lname"/><h:message for="lname"/>除了把響應(yīng)渲染給客戶端,渲染響應(yīng)階段也保存視圖組件樹,供后續(xù)請(qǐng)求使 用。(3)用戶糾正驗(yàn)證錯(cuò)誤,重新提交表單:在響應(yīng)中看到錯(cuò)誤消息后,用戶對(duì) 表單進(jìn)行糾正,提供姓氏并輸入格式正確的日期值,然后重新提交。這次,在處 理請(qǐng)求時(shí),恢復(fù)視圖階段恢復(fù)保存的視圖樹,

35、并前進(jìn)到應(yīng)用請(qǐng)求值階段,在這個(gè) 階段把新值應(yīng)用到視圖組件樹。階段轉(zhuǎn)移到處理驗(yàn)證階段,這次在這個(gè)階段沒遇 到驗(yàn)證或轉(zhuǎn)換錯(cuò)誤。然后觸發(fā)更新模型值階段。這時(shí),托管 bean (UserBean) 的屬性被表單中提交的新值更新,如圖 3-11所示。JSf igistriti.oD Ap pR *tii« Hi id FmuECljffw 丁油yrrUri'.CMlRCCCLMarAtEn0|UISh vl|內(nèi)同用苴M外刮F欣電圖3-11用驗(yàn)證后的值更新UserBean模型對(duì)象更新模型值階段完成之后,觸發(fā)的下一階段是調(diào)用應(yīng)用程序階段。還記得調(diào)用應(yīng)用程序階段為JSF開發(fā)人員提供了調(diào)用定制

36、邏輯的途徑。 例如,應(yīng)用程序可能需要執(zhí)行查詢數(shù)據(jù)庫的代碼。執(zhí)行定制邏輯是通過動(dòng)作方法實(shí)現(xiàn)的,動(dòng)作方法在調(diào)用應(yīng)用程序階段被調(diào)用,但只有在隊(duì)列中有動(dòng)作事件時(shí)(例如單擊了按鈕或鏈接)才調(diào)用。在JSFRe亦例中,在單擊Register按鈕時(shí),一個(gè)動(dòng)作事件被放 入隊(duì)列,1是由于Register按鈕(UICommandE件)的action屬性硬編碼成文 字值“register ",所以沒有調(diào)用定制動(dòng)作方法,調(diào)用應(yīng)用程序階段完成。這時(shí), 導(dǎo)航處理程序處理動(dòng)作事件,出現(xiàn)一個(gè)導(dǎo)航。然后在最終的渲染響應(yīng)事件中顯示 導(dǎo)航事件的結(jié)果?,F(xiàn)在再來看一遍:注冊(cè)頁面成功通過驗(yàn)證、UserBean托管bean用表單提

37、交的值更新之后,生命周期到了渲染響應(yīng)階段,這時(shí)需要把格式化的響應(yīng)發(fā)送回用 戶。這時(shí),必須確定要發(fā)送回客戶端的響應(yīng)。正如在第5章中會(huì)更全面介紹的那樣,導(dǎo)航處理程序負(fù)責(zé)確定是否只是用同一頁面進(jìn)行響應(yīng),還是導(dǎo)航到新頁面。還記得JSFRe亦例有一個(gè)action屬性硬編碼成“register ”,由于它與faces -config.xml文件中定義的導(dǎo)航規(guī)則對(duì)應(yīng),所以渲染的響應(yīng)是要導(dǎo)航到新頁面(c onfirm.jsp )。請(qǐng)記住,如果沒有設(shè)置導(dǎo)航按鈕的action屬性,或者沒有對(duì)應(yīng)的導(dǎo)航規(guī)則,那么渲染的響應(yīng)就會(huì)是同一頁面,不會(huì)出現(xiàn)導(dǎo)航。圖 3-12顯示了 NavigationHandler 如何利用f

38、aces-con巾g.xml中定義的規(guī)則確定是否需要導(dǎo)航。 注意 關(guān)于Faces導(dǎo)航模型的詳細(xì)說明,將在第 5章提供。中nHaftd好r尚博支好心叱tM 4興圖3-12在調(diào)用應(yīng)用程序階段,根據(jù)動(dòng)作的結(jié)果渲染響應(yīng)3.3 與請(qǐng)求處理生命周期有關(guān)的高級(jí)主題看過JSF請(qǐng)求處理生命周期在默認(rèn)情況下對(duì)基本表單的處理方式,現(xiàn)在來看 些稍微復(fù)雜的示例。3.3.1 使用 immediate 屬性這一節(jié)介紹Faces的一項(xiàng)極為重要的特性:immediate屬性,它允許更靈活 的生命周期執(zhí)行方式。立即處理動(dòng)作事件假設(shè)想在注冊(cè)頁面上添加一個(gè)Cancel按鈕,單擊這個(gè)按鈕時(shí),不論表單上輸入了什么,都會(huì)立即把用戶路由回m

39、ain.jsp頁面。要實(shí)現(xiàn)這個(gè)功能,必須添加一個(gè)返回主頁面的導(dǎo)航規(guī)則,還要在頁面上添加一個(gè)按鈕或鏈接組件,組件的動(dòng)作設(shè)置為導(dǎo)航規(guī)貝U " cancel” 的from-outcome。 下面是 faces-config.xml 中的 新導(dǎo)航規(guī)則:<navigation-rule><from-view-id>/register.jsp</from-view-id><navigation-case><from-outcome>cancel</from-outcome><to-view-id>/main.js

40、p</to-view-id></navigation-case></navigation-rule>下面是新添加到Register頁面的Cancel按鈕,它的action硬編碼設(shè)置成“c ancel ” :<h:commandButton value="Cancel" action="cancel" />但是,如果就此停止,那么很快就會(huì)遇到問題!如圖3-13所示,如果想再次 運(yùn)行應(yīng)用程序,但是立即單擊Cancel按鈕,就會(huì)卡在那里。出現(xiàn)這個(gè)問題是因?yàn)榧词箘偛庞每毡韱螁螕?Cancel按鈕,仍然把它當(dāng)作“回傳

41、”請(qǐng)求進(jìn)行處理, 這意味著JSF生命周期開始進(jìn)行處理,而且假定從表單傳來了進(jìn)入的名稱-值對(duì)。 但是由于表單實(shí)際是空的,所以在導(dǎo)航處理程序能處理“cancel”動(dòng)作事件并把 同一頁面響應(yīng)渲染回客戶端之前,先遇到了驗(yàn)證錯(cuò)誤。顯然,需要有一個(gè)在正常JSF在它的immediate屬性中提供生命周期處理流程之中允許異常的解決方案 的就是這個(gè)功能。JSFAppm 加廿 4 irrnedu % T rm圖3-13因?yàn)轵?yàn)證錯(cuò)誤而卡在頁面上如果給Cancel按鈕(或任何 UICommandK件)添加了 immediate屬性,并 把它的值設(shè)置成“ true ”,就能允許生命周期立即跳過驗(yàn)證,導(dǎo)航回 main.jsp 頁面。一般來說,在UICommandK件上把immediate屬性設(shè)置為“ true ”,會(huì)引 起動(dòng)作事件在處理驗(yàn)證階段之前,在應(yīng)用請(qǐng)求值階段就立即觸發(fā),這樣就不會(huì)遇 到驗(yàn)證錯(cuò)誤。這樣就有了把生命周期“短路”的效果,可以避免驗(yàn)證,取消更新 任何模型的值。3.3.2 立即處理驗(yàn)證和轉(zhuǎn)換實(shí)現(xiàn)EditableValueHolder 接口的組件(像輸入字段)帶有選項(xiàng),可以根據(jù) i

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論