JSF中請求過程的生命周期
前面我們講了JSF中包含的:組件、事件、監(jiān)聽器以及很多好用的組件,這些功能都使得JSF的開發(fā)變得更簡單。那么這些部分的執(zhí)行過程是什么樣的呢?為了更容易理解,我們講分析JSF框架的底層Servlet API,這對于你更好的理解JSF的執(zhí)行過程是有好處的。了解了這些內(nèi)容也有助于你開發(fā)出更好的應(yīng)用程序,因?yàn)槟忝靼椎讓拥降资侨绾芜\(yùn)行的。當(dāng)然如果你是一個(gè)WEB界面開發(fā)人員,你完全可以跳過這個(gè)部分。
在這一節(jié)中我們講討論JSF是如何對請求作出響應(yīng)的。或者說,由包含JSF組件的頁面發(fā)出的請求是如何被JSF處理的。
圖2.4是一個(gè)狀態(tài)圖,它顯示了當(dāng)接收到來自客戶端發(fā)出的請求后JSF是如何處理的,即JSF的請求處理過程。這個(gè)過程開始于JSFservlet接收到一個(gè)來自客戶端的請求(記住JSF是建立在Servlet基礎(chǔ)之上的) 
 
圖2.4
列表2.2對以上每一個(gè)狀態(tài)進(jìn)行了注釋,其中主要有六個(gè)狀態(tài),每一個(gè)狀態(tài)之后多會有相應(yīng)的時(shí)間產(chǎn)生。JSF將這些事件交給相應(yīng)的監(jiān)聽器進(jìn)行處理,不管監(jiān)聽器是處理某些業(yè)務(wù)邏輯還是組件,都能夠繼續(xù)跳轉(zhuǎn)到最終的狀態(tài),顯示響應(yīng)結(jié)果。監(jiān)視器也可以跳過最終的狀態(tài)直接顯示一個(gè)響應(yīng)結(jié)果,比如它可以返回一個(gè)二進(jìn)制內(nèi)容,執(zhí)行一個(gè)頁面跳轉(zhuǎn)或者返回其他與JSF有關(guān)的內(nèi)容比如XML文檔或者是一個(gè)HTML。
以上六個(gè)步驟中有四個(gè)可以產(chǎn)生消息,它們分別是:接收請求值(Apply Request Values),執(zhí)行驗(yàn)證(Process Validations),更新模型值(Update Model Vlaues),和提交應(yīng)用程序(Invoke Application)。不管是否帶有消息,這些狀態(tài)都能夠向用戶反饋響應(yīng),除非監(jiān)聽器、裝飾器或者組件自身直接返回響應(yīng)。這些狀態(tài)之后是一個(gè)依據(jù)時(shí)間主線提交應(yīng)用程序的過程。一系列的組件、校驗(yàn)過程、支持Bean和模型對象將被更新。簡單的講,JSF為你完成了大部分工作:它捕獲了請求的詳細(xì)信息并把它們傳輸給包含組件和時(shí)間的高層視圖,而且還更新了相關(guān)對象的屬性。
表2.2 JSF 各個(gè)狀態(tài)的請求響應(yīng)過程
| 狀態(tài) | 描述 | 觸發(fā)的事件 | 
| 還原頁面(Restore View) | 為選擇的頁面查找或創(chuàng)建一個(gè)組件樹。一些組件,比如HtmlCommandButton組件在此狀態(tài)下將產(chǎn)生動作事件(或者其他事件) | 狀態(tài)事件 | 
| 接收請求值(Apply Request Values) | 比較請求傳輸?shù)闹挡⒏孪鄳?yīng)組件的值,也可以使用轉(zhuǎn)換器。如果出現(xiàn)異常將拋出一個(gè)異常消息。同時(shí)會產(chǎn)生來自請求參數(shù)的事件。 | 狀態(tài)事件 數(shù)據(jù)模型事件 動作事件 | 
| 處理驗(yàn)證(Process Validations) | 對每個(gè)組件執(zhí)行驗(yàn)證??赡軙a(chǎn)生驗(yàn)證消息。 | 狀態(tài)事件 數(shù)據(jù)模型事件 值變化事件 | 
| 更新模型值(Update Model Values) | 更新與組件相關(guān)的所有模型對象和支持Bean的值??赡軙a(chǎn)生異常消息。 | 狀態(tài)事件 數(shù)據(jù)模型事件 | 
| 提交應(yīng)用程序(Invoke Application) | 調(diào)用注冊的監(jiān)聽器。缺省的監(jiān)聽器將執(zhí)行命令組件(比如HtmlCommandButton)的事件方法或者選擇下一個(gè)要顯示的視圖。 | 狀態(tài)事件 動作事件 | 
| 返回相應(yīng)(Render Response) | 顯示當(dāng)前邏輯指定的下一個(gè)響應(yīng)頁面。 | 狀態(tài)事件 | 
為了讓你對此有一個(gè)更清晰的了解。我們將通過一個(gè)hello world的例子展示JSF處理請求過程的整個(gè)生命周期。這個(gè)例子來自于我們前面章節(jié)講述的hello.jsp。列表2.1顯示了實(shí)際上Http的處理過程。
| 列表2.1 Http 的請求過程 | 
| POST /jia-hello-world/faces/hello.jsp HTTP/2.1 (1)接收來自URL的請求 Host: deadlock:8080 User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:2.2.1) Gecko/20021130 Accept: text/xml,application/xml,application/xhtml+xml,text/html; q=0.9,text/plain;q=0.8,video/x-mng,image/png, image/jpeg,image/gif;q=0.2,text/css,*/*;q=0.1 Accept-Language: en-us, en;q=0.50 Accept-Encoding: gzip, deflate, compress;q=0.9 Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66 Keep-Alive: 300 Connection: keep-alive Referer: http://deadlock:8080/jia-hello-world/faces/hello.jsp (2)同樣是接收來自URL的請求 Cookie: JSESSIONID=58324750039276F39E61932ABDE319DF (3)會話標(biāo)記 Content-Type: application/x-www-form-urlencoded Content-Length: 92 welcomeForm%3AhelloInput=64& (4)組件值 welcomeForm%3AredisplayCommand=Redisplay& welcomeForm=welcomeForm | 
(1)請求數(shù)據(jù)來源于/jia-hello-world/faces/hello.jsp 這個(gè)連接的POST數(shù)據(jù)。
(2)這里的referer(引用)是由請求頁面產(chǎn)生的,他與/jia-hello-world/faces/hello.jsp是相同的頁面。
(3)這里的Cookies將被Servlet容器使用,它用于將請求數(shù)據(jù)映射到一個(gè)指定的會話中。在這個(gè)例中JSF使用Servlet會話來存儲當(dāng)前的視圖(頁面也可以保存在由客戶端控制的一個(gè)值對象中,比如隱藏字段中)。
(4)這是非常重要的一個(gè)部分,這里包含了JSF傳輸?shù)膶?shí)際參數(shù)值(&用于分隔不同的參數(shù),%3A將被解析為“:”冒號)。首先是一個(gè)名為 welcomeForm:helloInput的參數(shù),并且它的值是64,這個(gè)值是通過瀏覽器頁面輸入的,第二個(gè)參數(shù)名為welcomeForm: redisplayCommand,他的值是“Redisplay”,最后一個(gè)參數(shù)是welcomeForm,它的值也是welcomeForm。在下面 的講解中我們將逐步介紹這些值是如何處理的。
一旦JSF接收到請求,它就會創(chuàng)建并實(shí)例化一個(gè)javax.faces.context.FacesContext對象。這個(gè)對象代表當(dāng)前的請求狀態(tài),并且負(fù)責(zé)處理底層Servlet request對象的各個(gè)部分,事件監(jiān)聽器可以通過它獲得當(dāng)前頁面的操作句柄,以此來進(jìn)行增加消息、記錄事件等等操作。在JSF中它代表了請求處理生命周期的整個(gè)過程。我們將在下面的講解中依次討論每一個(gè)狀態(tài)。

 
                         
                                
 
                                





 
                        
