前面我們講了JSF中包含的:組件、事件、監聽(tīng)器以及很多好用的組件,這些功能都使得JSF的開(kāi)發(fā)變得更簡(jiǎn)單。那么這些部分的執行過(guò)程是什么樣的呢?為了更容易理解,我們講分析JSF框架的底層Servlet API,這對于你更好的理解JSF的執行過(guò)程是有好處的。了解了這些內容也有助于你開(kāi)發(fā)出更好的應用程序,因為你明白底層到底是如何運行的。當然如果你是一個(gè)WEB界面開(kāi)發(fā)人員,你完全可以跳過(guò)這個(gè)部分。
在這一節中我們講討論JSF是如何對請求作出響應的?;蛘哒f(shuō),由包含JSF組件的頁(yè)面發(fā)出的請求是如何被JSF處理的。
圖2.4是一個(gè)狀態(tài)圖,它顯示了當接收到來(lái)自客戶(hù)端發(fā)出的請求后JSF是如何處理的,即JSF的請求處理過(guò)程。這個(gè)過(guò)程開(kāi)始于JSFservlet接收到一個(gè)來(lái)自客戶(hù)端的請求(記住JSF是建立在Servlet基礎之上的)
圖2.4
列表2.2對以上每一個(gè)狀態(tài)進(jìn)行了注釋?zhuān)渲兄饕辛鶄€(gè)狀態(tài),每一個(gè)狀態(tài)之后多會(huì )有相應的時(shí)間產(chǎn)生。JSF將這些事件交給相應的監聽(tīng)器進(jìn)行處理,不管監聽(tīng)器是處理某些業(yè)務(wù)邏輯還是組件,都能夠繼續跳轉到最終的狀態(tài),顯示響應結果。監視器也可以跳過(guò)最終的狀態(tài)直接顯示一個(gè)響應結果,比如它可以返回一個(gè)二進(jìn)制內容,執行一個(gè)頁(yè)面跳轉或者返回其他與JSF有關(guān)的內容比如XML文檔或者是一個(gè)HTML。
以上六個(gè)步驟中有四個(gè)可以產(chǎn)生消息,它們分別是:接收請求值(Apply Request Values),執行驗證(Process Validations),更新模型值(Update Model Vlaues),和提交應用程序(Invoke Application)。不管是否帶有消息,這些狀態(tài)都能夠向用戶(hù)反饋?lái)憫?,除非監聽(tīng)器、裝飾器或者組件自身直接返回響應。這些狀態(tài)之后是一個(gè)依據時(shí)間主線(xiàn)提交應用程序的過(guò)程。一系列的組件、校驗過(guò)程、支持Bean和模型對象將被更新。簡(jiǎn)單的講,JSF為你完成了大部分工作:它捕獲了請求的詳細信息并把它們傳輸給包含組件和時(shí)間的高層視圖,而且還更新了相關(guān)對象的屬性。
表2.2 JSF 各個(gè)狀態(tài)的請求響應過(guò)程
狀態(tài)
描述
觸發(fā)的事件
還原頁(yè)面(Restore View)
為選擇的頁(yè)面查找或創(chuàng )建一個(gè)組件樹(shù)。一些組件,比如HtmlCommandButton組件在此狀態(tài)下將產(chǎn)生動(dòng)作事件(或者其他事件)
狀態(tài)事件
接收請求值(Apply Request Values)
比較請求傳輸的值并更新相應組件的值,也可以使用轉換器。如果出現異常將拋出一個(gè)異常消息。同時(shí)會(huì )產(chǎn)生來(lái)自請求參數的事件。
狀態(tài)事件
數據模型事件
動(dòng)作事件
處理驗證(Process Validations)
對每個(gè)組件執行驗證??赡軙?huì )產(chǎn)生驗證消息。
狀態(tài)事件
數據模型事件
值變化事件
更新模型值(Update Model Values)
更新與組件相關(guān)的所有模型對象和支持Bean的值??赡軙?huì )產(chǎn)生異常消息。
狀態(tài)事件
數據模型事件
提交應用程序(Invoke Application)
調用注冊的監聽(tīng)器。缺省的監聽(tīng)器將執行命令組件(比如HtmlCommandButton)的事件方法或者選擇下一個(gè)要顯示的視圖。
狀態(tài)事件
動(dòng)作事件
返回相應(Render Response)
顯示當前邏輯指定的下一個(gè)響應頁(yè)面。
狀態(tài)事件
為了讓你對此有一個(gè)更清晰的了解。我們將通過(guò)一個(gè)hello world的例子展示JSF處理請求過(guò)程的整個(gè)生命周期。這個(gè)例子來(lái)自于我們前面章節講述的hello.jsp。列表2.1顯示了實(shí)際上Http的處理過(guò)程。
列表2.1 Http 的請求過(guò)程
POST /jia-hello-world/faces/hello.jsp HTTP/2.1 (1)接收來(lái)自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)同樣是接收來(lái)自URL的請求
Cookie: JSESSIONID=58324750039276F39E61932ABDE319DF (3)會(huì )話(huà)標記
Content-Type: application/x-www-form-urlencoded
Content-Length: 92
welcomeForm%3AhelloInput=64& (4)組件值
welcomeForm%3AredisplayCommand=Redisplay&
welcomeForm=welcomeForm
我們并不打算討論Http處理的詳細過(guò)程,不過(guò)上表其中幾行與我們的討論是有關(guān)的:
(1)請求數據來(lái)源于/jia-hello-world/faces/hello.jsp 這個(gè)連接的POST數據。
(2)這里的referer(引用)是由請求頁(yè)面產(chǎn)生的,他與/jia-hello-world/faces/hello.jsp是相同的頁(yè)面。
(3)這里的Cookies將被Servlet容器使用,它用于將請求數據映射到一個(gè)指定的會(huì )話(huà)中。在這個(gè)例中JSF使用Servlet會(huì )話(huà)來(lái)存儲當前的視圖(頁(yè)面也可以保存在由客戶(hù)端控制的一個(gè)值對象中,比如隱藏字段中)。
(4)這是非常重要的一個(gè)部分,這里包含了JSF傳輸的實(shí)際參數值(&用于分隔不同的參數,%3A將被解析為“:”冒號)。首先是一個(gè)名為 welcomeForm:helloInput的參數,并且它的值是64,這個(gè)值是通過(guò)瀏覽器頁(yè)面輸入的,第二個(gè)參數名為welcomeForm: redisplayCommand,他的值是“Redisplay”,最后一個(gè)參數是welcomeForm,它的值也是welcomeForm。在下面 的講解中我們將逐步介紹這些值是如何處理的。
一旦JSF接收到請求,它就會(huì )創(chuàng )建并實(shí)例化一個(gè)javax.faces.context.FacesContext對象。這個(gè)對象代表當前的請求狀態(tài),并且負責處理底層Servlet request對象的各個(gè)部分,事件監聽(tīng)器可以通過(guò)它獲得當前頁(yè)面的操作句柄,以此來(lái)進(jìn)行增加消息、記錄事件等等操作。在JSF中它代表了請求處理生命周期的整個(gè)過(guò)程。我們將在下面的講解中依次討論每一個(gè)狀態(tài)。
posted by Blogjava at
3:15 AM0 comments Thursday, August 24, 2006
JSF中的導航功能
之前我們講述的概念中所有操作都是在一個(gè)單獨的頁(yè)面上。在實(shí)際的Web應用開(kāi)發(fā)中,這是不太可能的。Web應用的開(kāi)發(fā)會(huì )有很多頁(yè)面,我們必須提供一種方法實(shí)現不同頁(yè)面之間的切換。實(shí)現從一個(gè)頁(yè)面到另一個(gè)頁(yè)面切換的機制被稱(chēng)為“導航”。
JSF中有一套非常完善的導航系統。導航控制器根據請求實(shí)現的返回值確定下一個(gè)頁(yè)面跳轉到哪里。對于給定的頁(yè)面,一個(gè)導航規則定義了根據業(yè)務(wù)邏輯的動(dòng)作事件判斷頁(yè)面應該如何跳轉。根據導航規則發(fā)生的每一個(gè)頁(yè)面跳轉被稱(chēng)為一個(gè)導航事件。導航規則定義在JSF的配置文件中。下面這個(gè)例子演示了針對longin.jsp頁(yè)面的兩個(gè)導航事件:success和failure的一個(gè)導航規則。
<navigation-rule>
<from-view-id>/login.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/mainmenu.jsp</to-view-id>
</navigation-case>
<navigation-case>
<from-outcome>failure</from-outcome>
<to-view-id>/login.jsp</to-view-id>
</navigation-case>
</navigation-rule>
如你所見(jiàn),每一個(gè)出口對應一個(gè)JSP頁(yè)面,這里你不需要通過(guò)編碼實(shí)現這些規則。如果你曾經(jīng)使用過(guò)Struts你對這種定義方式一定不會(huì )陌生。你會(huì )發(fā)現,所有的導航事件只映射一個(gè)出口(對應一個(gè)jsp),也就是說(shuō),如果將來(lái)需要進(jìn)行變更你只需要修改需要變更的那一個(gè)頁(yè)面就可以了而不是修改多處。
現在,JSF中的幾個(gè)基本概念已經(jīng)介紹完了。在隨后的講解中我們會(huì )看到更多的例子。已經(jīng)這些概念集中到一起是如何使用的。