<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    2006年11月8日

    使用 JSF 架構(gòu)進行設(shè)計

    探索 JavaServer Faces 框架中使用的設(shè)計模式

    ?
    ??
    ?

    未顯示需要 JavaScript 的文檔選項


    拓展 Tomcat 應用

    下載 IBM 開源 J2EE 應用服務(wù)器 WAS CE 新版本 V1.1


    級別: 中級

    Anand Prakash Joshi (ananjosh@in.ibm.com), 軟件工程師, IBM

    2006 年 1 月 04 日

    本文中,作者 Anand Joshi 使用 JSF 框架中的設(shè)計模式闡釋了 JavaServer Faces (JSF) 體系結(jié)構(gòu)。他討論了 JSF 體系結(jié)構(gòu)中使用的 GoF 設(shè)計模式,以及這些模式在 JSF 框架中的作用。任何對設(shè)計模式和 JSF 體系結(jié)構(gòu)有一定了解的人都能從 Anand 詳細的介紹中有所收獲。*讀者應該對 GoF 設(shè)計模式和 JSF 技術(shù)有很好的了解。

    設(shè)計模式可以幫助用戶在更高層次上抽象細節(jié),更好地理解體系結(jié)構(gòu)。如果比較熟悉 GoF 設(shè)計模式和 JavaServer Faces (JSF) 框架,本文可以幫助您洞察 JSF 框架中使用的設(shè)計模式,深入理解其工作原理。

    本文探討了 JSF 框架中使用的設(shè)計模式。詳細討論的設(shè)計模式包括 Singleton、Model-View-Controller、Factory Method、State、Composite、Decorator、Strategy、Template Method 和 Observer 模式。

    設(shè)計模式和 JavaServer Faces (JSF) 技術(shù)

    首先簡要地介紹一下模式和 JSF 框架。

    • 模式。設(shè)計模式是對問題和解決方案進行抽象的普遍適用的方法。因為模式是所有開發(fā)人員和架構(gòu)師公認的,所以模式可以節(jié)約時間和資源。用外行話來說,模式就是關(guān)于某個人所共知的問題的經(jīng)過驗證的解決方案。模式可以重用,重用使得解決方案更健壯。
    • Java Server Faces。 JSF 體系結(jié)構(gòu)是一種 Web 應用程序框架。它是 Java Community Process (JCP) 推動的,有望成為 Web 應用程序開發(fā)的標準框架。目前用于開發(fā) Web 應用程序的框架有 50 多個,這說明迫切需要實現(xiàn)框架的標準化,這正是 JSF 框架的目標!

    ?

    ?
    ?


    深入剖析 JSF 模式

    現(xiàn)在我們來討論 JSF 體系結(jié)構(gòu)中的各種設(shè)計模式。本文將詳細討論 Singleton、Model-View-Controller、Factory Method、State、Composite、Decorator、Strategy、Template Method 和 Observer 設(shè)計模式。我將分析每種模式的用途及其在 JSF 框架中的作用。



    ?
    ?


    Singleton 模式

    Singleton 模式的目的是保證類只有一個實例被加載,該實例提供一個全局訪問點。當啟動具有 JSF 支持的 Web 應用程序時,Web 容器初始化一個 FacesServlet 實例。在這個階段,F(xiàn)acesServlet 對每個 Web 應用程序?qū)嵗?Application 和 LifeCycle 實例一次。這些實例就采用眾所周知的 Singleton 模式,通常只需要該類型的一個實例。

    使用 JSF 的 Web 應用程序只需要 Application 和 LifeCycle 類的一個實例。LifeCycle 管理多個 JSF 請求的整個生命期。因為其狀態(tài)和行為在所有請求之間共享,這些對象采用 Singleton 模式合情合理。LifeCycle 維護的 PhaseListeners 也是 Singleton 模式的。PhaseListeners 由所有 JSF 請求共享。在 JSF 框架中可以廣泛使用 Singleton 模式,以減少內(nèi)存占用和提供對象的全局訪問。NavigationHandler(用于確定請求的邏輯結(jié)果)和 ViewHandler(用于創(chuàng)建視圖)也是使用 Singleton 模式的例子。




    ?
    ?


    Model-View-Controller (MVC)

    MVC 模式的目的是從數(shù)據(jù)表示(View)中將數(shù)據(jù)(即 Model)分離出來。如果應用程序有多種表示,可以僅替換視圖層而重用控制器和模型代碼。類似的,如果需要改變模型,可以在很大程度上不改變視圖層。控制器處理用戶動作,用戶動作可能造成模型改變和視圖更新。當用戶請求一個 JSF 頁面時,請求發(fā)送到 FacesServlet。FacesServlet 是 JSF 使用的前端控制器 servlet。和其他很多 Web 應用程序框架一樣,JSF 使用 MVS 模式消除視圖和模型之間的耦合。為了集中處理用戶請求,控制器 servlet 改變模型并將用戶導航到視圖。

    FacesServlet 是 JSF 框架中所有用戶請求都要經(jīng)過的控制器元素。FacesServlet 分析用戶請求,使用托管 bean 對模型調(diào)用各種動作。后臺(backing)或托管(managed)bean 就是該模型的例子。JSF 用戶界面(UI)組件是視圖層的例子。MVC 模式把任務(wù)分解給具有不同技能的開發(fā)人員,使這些任務(wù)能夠同時進行,這樣 GUI 設(shè)計人員就可以使用豐富的 UI 組件創(chuàng)建 JSF 頁面,同時后端開發(fā)人員可以創(chuàng)建托管 bean 來編寫專門的業(yè)務(wù)邏輯代碼。




    ?
    ?


    Factory Method 模式

    Factory Method 模式的目的是定義一個用于創(chuàng)建對象的接口,但是把對象實例化推遲到子類中。在 JSF 體系結(jié)構(gòu)中,F(xiàn)actory Method 模式被用于創(chuàng)建對象。LifeCycleFactory 是一個創(chuàng)建和返回 LifeCycle 實例的工廠對象。LifeCycleFactory 的 getLifeCycle (String LifeCycleId) 方法采用 Factory Method 模式,根據(jù) LifeCycleId 創(chuàng)建(如果需要)并返回 LifeCycle 實例。自定義的 JSF 實現(xiàn)可以重新定義 getLifeCycle 抽象方法來創(chuàng)建自定義的 LifeCycle 實例。默認的 JSF 實現(xiàn)提供默認的 LifeCycle 實例。此外,對于每個 JSF 請求,F(xiàn)acesServlet 都從 FacesContextFactory 得到 FacesContext。FacesContextFactory 是一個抽象類,公開了 getFacesContext API,JSF 實現(xiàn)提供了 FacesContextFactory 和 getFacesContext API 的具體實現(xiàn)。這是另外一個使用 Factory Method 模式的例子,具體的 FacesContextFactory 實現(xiàn)創(chuàng)建 FacesContext 對象。




    ?
    ?


    State 模式

    State 模式的目的是在表示狀態(tài)的不同類之間分配與狀態(tài)有關(guān)的邏輯。FacesServlet 對 LifCycle 實例調(diào)用 execute 和 render 方法。LifeCycle 協(xié)調(diào)不同的 Phrase 以便執(zhí)行 JSF 請求。在這里 JSF 實現(xiàn)就遵循了 State 模式。如果沒有使用這種模式,LifeCycle 實現(xiàn)就會被大量的條件(即 “if” 語句)攪得一塌糊涂。JSF 實現(xiàn)為每個狀態(tài)(或階段)創(chuàng)建單獨的類并調(diào)用 step。phase 是一個抽象類,定了每個 step 的公共接口。在 JSF 框架中定義了六個 phrase(即 step):RestoreViewPhase、ApplyRequestValues、ProcessValidationsPhase、UpdateModelValuesPhase、InvokeApplicationPhase 和 RenderResponsePhase。

    在 State 模式中,LifeCycle 把 FacesContext 對象傳遞給 phase。每個階段或狀態(tài)改變傳遞給它的上下文信息,然后設(shè)置 FacesContext 本身中的標志表明下一個可能的步驟。JSF 實現(xiàn)在每個步驟中改變其行為。每個階段都可以作為下一個階段的起因。FacesContext 有兩種標志 renderResponse 和 responseComplete 可以改變執(zhí)行的順序。每個步驟執(zhí)行完成后,LifeCycle 檢查上一階段是否設(shè)置了這些標志。如果設(shè)置了 responseComplete,LifeCycle 則完全放棄請求的執(zhí)行。如果經(jīng)過某個階段后設(shè)置了 renderResponse 標志,JSF 就會跳過剩下的階段而直接進入 Render Response 階段。如果這兩個標志都沒有設(shè)置,LifeCycle 就會按順序繼續(xù)執(zhí)行下一步。




    ?
    ?


    Composite 模式

    Composite 模式讓客戶代碼能夠統(tǒng)一處理復合對象和基本對象。復合對象是基本對象的容器。在第一階段(Restore View 階段)和最后一個階段(Render Response 階段),使用 JSF UI 組件構(gòu)造 UI View。UIComponentBase 就是 Composite 模式中 Component 抽象類的一個例子。UIViewRoot 是 Composite 類,而 UIOutput(比方說)就是葉子(或者基本類)。UIComponentBase 類定義了葉子和復合對象的公共方法,如編碼/解碼值和子節(jié)點管理函數(shù)。子節(jié)點管理函數(shù),如 getChildren,對于葉子節(jié)點返回空列表,對于復合節(jié)點則返回其子節(jié)點。




    ?
    ?


    Decorator 模式

    Decorator 模式的目的是不通過子類化動態(tài)擴展對象的行為。JSF 框架有很多擴展點(即可插入機制)。JSF 實現(xiàn)可使用 Decorator 模式替換默認的 PropertyResolver、VariableResolver、ActionListener、NavigationHandler、ViewHandler 或 StateManager。通常自定義實現(xiàn)接受通過構(gòu)造函數(shù)傳遞給它的默認實現(xiàn)的引用。自定義實現(xiàn)僅僅改寫功能的一個子集,而將其他功能委托給默認實現(xiàn)。如果希望實現(xiàn)自定義的 ViewHandler,改寫默認 ViewHandler 實現(xiàn)的 calculateLocale 方法,可以像 清單 1 那樣編寫 CustomViewHandler 類:

    清單 1. CustomViewHandler 片段

    public class CustomViewHandler extends ViewHandler {
     public CustomViewHandler(ViewHandler handler) {
    		 super();
    		 oldViewHandler = handler;
     }
    private ViewHandler oldViewHandler  = null;
    public void renderView (facesContext context, UIViewRoot view) {
                //delegate method to oldViewHandler
    		 oldViewHandler.renderView(context, view);
    }
    //custom implementation of calculateLocale
    public Locale calculateLocale(FacesContext context) {
    }
    }
    




    ?
    ?


    Strategy 模式

    Strategy 模式的目的是封裝不同的概念。JSF 框架采用 Strategy 模式使用委托實現(xiàn)模型呈現(xiàn) UI 組件。JSF 技術(shù)支持兩種呈現(xiàn)模型。在直接實現(xiàn)模型中,UI 組件對收到的請求中的數(shù)據(jù)進行解碼,然后編碼這些數(shù)據(jù)進行顯示。在委托實現(xiàn)模型中,解碼和編碼操作委托給和組建關(guān)聯(lián)的專門呈現(xiàn)器。后一種模型利用了 Strategy 設(shè)計模式,比直接實現(xiàn)更靈活。在 Strategy 模式中,將不同的算法封裝在單獨的對象中,從而可以動態(tài)地改變算法。JSF 實現(xiàn)可以用已有的 renderkit 實例注冊另外的呈現(xiàn)器,當應用程序啟動的時候,JSF 實現(xiàn)讀取配置文件將這些呈現(xiàn)器和 UI 組件聯(lián)系在一起。




    ?
    ?


    Template Method 模式

    Template Method 模式的目的是將變化的步驟推遲到子類中,而在父類中定義那些固定的算法步驟。JSF 框架通過 PhraseListeners 展現(xiàn)了 Template Method 模式提供的功能。采用 Template Method(或者 “hook”)使得 Web 作者可以為不同階段之間的可選步驟提供實現(xiàn),而主要階段仍然和 JSF 框架的定義一致。JSF 框架提供了 PhaseListeners,概念上類似于 Template Method 模式中的可變步驟。JSF 框架有六個預定義的階段,在每個階段之間,Web 作者可以實現(xiàn) PhaseListeners 來提供類似于 Template Method hook 的 hook。事實上,這種結(jié)構(gòu)比 Template Method 模式更具有擴展性。可以通過注冊 PhraseId 為 ANY_PHRASE 的 PhaseListener 在每個階段后提供 hook。如果 PhaseId 是 ANY_PHASE,JSF 實現(xiàn)就會在每個階段之前和之后調(diào)用該 PhaseListener。JSF 框架中的實現(xiàn)略有不同,因為可以根本沒有 PhaseListener,但是在 Template Method 模式中,子類通常重新定義父類中抽象的可變步驟。




    ?
    ?


    Observer 模式

    Observer 模式的目的是當目標對象的狀態(tài)改變時自動通知所有依賴的對象(即觀察器)。JSF 在 UI 組件中實現(xiàn)了 Observer 模式。JSF 有兩類內(nèi)建事件:ActionEvent 和 ValueChangedEvent。ActionEvent 用于確定用戶界面組件(如按鈕)的激活。當用戶單擊按鈕時,JSF 實現(xiàn)通知添加到該按鈕上的一個或多個動作監(jiān)聽程序。于是該按鈕被激活,或者說按鈕(主體)的狀態(tài)改變了。添加到按鈕上的所有監(jiān)聽程序(即觀察器)都收到通知該主體狀態(tài)已經(jīng)改變。類似的,當輸入 UI 組件中的值改變時,JSF 實現(xiàn)通知 ValueChangeListener。




    ?
    ?


    結(jié)束語

    JSF 框架利用了 Singleton、Model-View-Controller、Factory Method、State、Composite、Decorator、Strategy、Template Method 和 Observer 設(shè)計模式。因為它的體系結(jié)構(gòu)建立在已經(jīng)驗證的設(shè)計模式的基礎(chǔ)上,這是一個健壯的框架,模式在 JSF 框架中得到了很好的利用。



    參考資料

    學習

    獲得產(chǎn)品和技術(shù)

    討論


    關(guān)于作者

    Anand Joshi 的照片

    Anand 是一位 Sun 認證的企業(yè)架構(gòu)師,幾年來一直研究 Web 技術(shù)。他對 WebSphere 管理控制臺應用程序的設(shè)計和開發(fā)做了多方面的貢獻。Anand 曾經(jīng)在 IBM 美國工作過幾年,目前在 IBM 印度工作。


    posted @ 2006-11-08 09:51 GoodtigerZhao 閱讀(323) | 評論 (0)編輯 收藏

    2006年11月7日


    JSF是一種新的用于構(gòu)架j2ee應用用戶界面的技術(shù),它尤其適合于基于MVC架構(gòu)的應用中。雖已有很多文章介紹過了JSF,然而它們大多從理論高度來介紹JSF而不是面向于實際應用。目前對于實際應用,JSF仍有很多問題沒有解決,例如:如何使JSF適應于MVC整體構(gòu)架中?如何將JSF與其他Java 框架整合起來?是否應該將業(yè)務(wù)邏輯放置在JSF的backing beans中?如何處理JSF中的安全機制?更為重要的是如何利用JSF構(gòu)架現(xiàn)實世界的Web應用?

    本文將涉及到上面的這些問題,它將演示如何將JSF、Spring和Hibernate整合在一起,構(gòu)架出一個名為JCatalog的在線產(chǎn)品價目系統(tǒng)
    。利用該Demo,本文涵蓋了Web應用開發(fā)的每一個階段,包括需求收集、分析,技術(shù)選擇,系統(tǒng)架構(gòu)和實現(xiàn)。本文討論了在JCatalog中涉及到的各種技術(shù)的優(yōu)點和缺點并展示了一些關(guān)鍵部分的設(shè)計方法。

    本文的對象是從事基于J2ee的Web應用架構(gòu)人員和開發(fā)人員,它并不是對JSF、SpringFramework和Hibernate的簡單介紹,如果對這些領(lǐng)域不甚了解,請參看相關(guān)資源。

    該范例的功能需求
    JCatalog是一個現(xiàn)實世界的Web應用,我首先描述JCatalog的需求,在通篇的技術(shù)決策和架構(gòu)設(shè)計時都將涉及到本部分。

    在設(shè)計Web應用的第一階段是收集系統(tǒng)的功能需求,范例應用是一個典型的電子商務(wù)應用系統(tǒng),用戶可以瀏覽產(chǎn)品的catalog并查看產(chǎn)品的詳細情況,而管理員可以管理產(chǎn)品的catalog。通過增加一些其他功能,如inventory管理和訂單處理等,該應用可成為一個成熟的電子商務(wù)系統(tǒng)。

    Use cases
    Use-case分析被用來展示范例應用的功能需求,圖1就是該應用的use-case圖。
    ????


    use-case圖用于表示系統(tǒng)中的actors以及可能進行的operations,在該應用中將有七個use-case,用戶能夠瀏覽產(chǎn)品 catalog和查看產(chǎn)品的詳細情況,一旦用戶登錄到系統(tǒng)中,她將成為管理員,從而可以創(chuàng)建新的產(chǎn)品,編輯已存在的產(chǎn)品或者刪除老的產(chǎn)品等。

    Business rules
    JCatalog必須符合以下business rules:
    • 每個產(chǎn)品必須具有唯一的ID
    • 每個產(chǎn)品必須屬于至少一個category
    • 產(chǎn)品ID一旦創(chuàng)立不得修改
    Assumptions
    我們在系統(tǒng)的設(shè)計和實現(xiàn)中做以下假定:
    • 英語講是缺省語言,且不需事先國際化
    • 在Catalog不講不會超過500個產(chǎn)品
    • catalog將不會被頻繁的修改
    Page flow
    圖2顯示了所有的JCatalog的pages以及它們之間的transitions關(guān)系:
    ????


    該應用中存在兩組pages:公開的internet和用于管理的intranet,其中intranet只能被那些成功登錄到系統(tǒng)的用戶訪問。 ProductSummary不作為一個單獨的page展示給用戶,它顯示在Catalog page中的frame中。ProductList只對管理員可視,它包含用于創(chuàng)建、編輯和刪除產(chǎn)品的鏈接。

    圖3是一個Catalog頁面的示意圖,理想狀況下,在需求文檔中應該包含每一頁的詳細示意圖。
    ????????


    構(gòu)架設(shè)計
    Web應用開發(fā)的下一個階段是構(gòu)架設(shè)計,它包括將應用劃分為多個功能組件并將這些組件分割組合成層,高層的構(gòu)架設(shè)計應該中立于所選用的特定技術(shù)。

    多層架構(gòu)
    多層架構(gòu)是將整個系統(tǒng)清晰的分為多個功能單元:client、presentation、business-logic、integration和 EIS,這將確保職責得到清晰的劃分,使得系統(tǒng)更易于維護和擴展。具有三層或等多層的系統(tǒng)被證明比C/S模型具有更好的伸縮性和靈活性。

    client層是使用和表示數(shù)據(jù)模型的地方,對于一個Web應用,client層通常是瀏覽器,基于瀏覽器的瘦客戶端不包含任何表示邏輯,它依賴于
    presentation 層。

    presentation層將business-logic層的服務(wù)展示給用戶,它應知道如何處理用戶的請求,如何同business-logic層交互,并且知道如何選擇下一個視圖顯示給用戶。

    business-logic層包含應用的business objects和business services。它接受來在于presentation層的請求、基于請求處理業(yè)務(wù)邏輯。業(yè)務(wù)邏輯層組件將受益于系統(tǒng)級的服務(wù),如安全管理、事務(wù)管理和資源管理等。

    integration層是介于
    business-logic 層和EIS層之間的橋梁,它封裝了與EIS層交互的邏輯。有時,將integration層和business-logic層合稱為中間層。

    應用的數(shù)據(jù)被保存在EIS層中,它包括關(guān)系數(shù)據(jù)庫、面向?qū)ο髷?shù)據(jù)庫和以及遺留系統(tǒng)等。

    JCatalog的構(gòu)架設(shè)計
    圖4顯示了JCatalog的構(gòu)架設(shè)計以及如何應用于多層構(gòu)架系統(tǒng)中。
    ?


    該應用采用了多層非分布式的構(gòu)架,圖4展示了系統(tǒng)的分層以及每一層中選擇的技術(shù),它同時又是該范例的部署圖,它的presentation、 business-logic和integration層將存在于同一個web容器中。定義良好的接口將孤立每一層的職責,這一架構(gòu)使得應用更為簡單和更好的伸縮性。

    對于presentation層,經(jīng)驗表明,最好的方法是選擇已存在的并已得到證明了的Web應用框架,而不是自己去設(shè)計和開發(fā)新的框架。我們擁有多個可選擇的框架,如Struts,WebWork和JSF等,在JCatalog中,我們選擇采用JSF。

    EJB和POJO都可以用來創(chuàng)建業(yè)務(wù)邏輯層,如果應用是分布式的,采用具有remote接口的EJB是一個好的選擇;由于JCatalog是一個典型的不需要遠程訪問的Web應用,因此選用POJO,并充分利用Spring Framework的幫助,將是實現(xiàn)業(yè)務(wù)邏輯層的更好選擇。

    integration層利用關(guān)系型數(shù)據(jù)庫事先數(shù)據(jù)的持續(xù)化,存在多種方法可用來實現(xiàn):
    • JDBC:這是最為靈活的方法,然而,低級的JDBC難以使用,而且質(zhì)量差的JDBC代碼很難運轉(zhuǎn)良好
    • Entity beans:CMP的Entity bean是一種分離數(shù)據(jù)訪問代碼和處理ORM的昂貴的方法,它是以應用服務(wù)器為中心的方法,即entity bean不是將應用與某種數(shù)據(jù)庫類型而是EJB容器約束在一起。
    • O/R mapping framework:一個ORM框架采用以對象為中心的方法實現(xiàn)數(shù)據(jù)持續(xù)化,一個以對象為中心的應用易于開發(fā)并具有高度的可移植性。在該領(lǐng)域中存在幾個框架可用—JDO、Hibernate、TopLink以及CocoBase等。在我們的范例中將選用Hibernate。
    現(xiàn)在,我們將討論每一層中的設(shè)計問題,由于JSF是一個相對較新的技術(shù),因此將著重于它的使用:

    presentation 層和JSF
    表示層的功能是收集用戶的輸入、展示數(shù)據(jù)、控制頁面導航并將用戶的輸入傳遞給業(yè)務(wù)邏輯層,表示層同時需要驗證用戶的輸入以及維護應用的session狀態(tài)。在下面幾部分中,我將討論表示層設(shè)計時的考慮和模式,并說明選擇JSF作為JCatalog表示層的原因。

    MVC
    MVC是Java-Blueprints推薦的架構(gòu)設(shè)計模式,MVC將幾個方面分離開來,從而減少代碼的重復,它以控制為中心并使得應用更具擴展性。MVC同時可幫助具有不同技能的用戶更關(guān)注于自己的技能,通過定義良好的接口進行相互合作。MVC是表示層的架構(gòu)設(shè)計模式。

    JSF
    JSF是Web應用的服務(wù)器端用戶組件框架,它包含以下API:表示UI組件、管理它們的狀態(tài)、處理事件、服務(wù)器端驗證、數(shù)據(jù)轉(zhuǎn)換、定義頁面導航、支持國際化,并為這些特性提供擴展能力。它同時包括兩個JSP的tag庫以在JSP頁面中表示UI組件,以及將組件wire為服務(wù)器端對象。

    JSF和MVC
    JSF非常適合于基于MVC的表示層架構(gòu),它在行為和表示之間提供了清晰的分離,它使得你可以采用熟悉的UI組件和web層概念而無需受限于某種特殊的腳本技術(shù)或標記語言。

    JSF backing beans是JSF的Model層,此外,它同樣包含actions,action是controller層的擴展,用于將用戶的請求委派給業(yè)務(wù)邏輯層。這里請注意,從整體的應用構(gòu)架看,業(yè)務(wù)邏輯層也被稱為model層。包含JSF標簽的JSP頁面是表示層,F(xiàn)aces Servlet提供了controller的功能。

    為什么選用JSF?

    JSF不僅僅是另外一個Web框架,下面這些特性是JSF區(qū)別于其他Web框架之所在:
    • 類Swing的面向?qū)ο蟮腤eb應用開發(fā):服務(wù)器端有狀態(tài)的UI組件模型,配合event listeners和handlers,促進了面向?qū)ο蟮腤eb應用開發(fā)。
    • backing-bean管理: backing bean是與頁面中使用的UI組件相關(guān)聯(lián)的javabean組件,backing-bean管理將UI組件對象的定義同執(zhí)行應用相關(guān)處理和擁有數(shù)據(jù)的對象分離開來。JSF在合適的范圍內(nèi)保存和管理這些backing-bean實例。
    • 可擴展的UI模型:JSF的UI模型是可配置的、可重用的,用以構(gòu)建JSF應用的用戶界面。你可以通過擴展標準的UI組件來開發(fā)出更為復雜的組件,例如菜單條、樹組件等。
    • 靈活的rendering模型:renderer分離了UI組件的功能和顯示,多個renderers可創(chuàng)建和用來為同一客戶端或不同的客戶端定義不同的顯示。
    • 可擴展的轉(zhuǎn)換和驗證模型:基于標準的converter和validator,你可以開發(fā)出自己的可提供更好的模型保護的converter和validator。
    盡管如此,JSF目前尚未成熟,隨同JSF發(fā)布的 components、converters和validators都是最基礎(chǔ)的,而且per-component驗證模型不能處理components 和validators間的many-to-many驗證。此外,JSF標簽不能與JSTL間無縫的整合在一起。

    在下面的章節(jié)中,我將討論幾個在JCatalog實現(xiàn)中的關(guān)鍵部分和設(shè)計決策。我首先解釋managed bean的定義和使用以及JSF中的backing bean,然后,我將說明如何處理安全、分頁、caching、file upload、驗證以及錯誤信息定制。

    Managed bean,backing bean,view object 和domain object model
    JSF中引入了兩個新的名詞:managed bean和backing bean。JSF提供了一個強大的managed-bean工具,由JSF來管理的JavaBean對象稱為managed-bean,一個 managed bean表述了一個bean如何被創(chuàng)建和管理,它不包含該bean的任何功能性描述。

    backing bean定義了與頁面中使用的UI組件相關(guān)聯(lián)的屬性和處理邏輯。每一個backing-bean屬性邦定于一個組件實例或某實例的value。一個 backing-bean同時定義了一組執(zhí)行組件功能的方法,例如驗證組件的數(shù)據(jù)、處理組件觸發(fā)的事件、實施與組件相關(guān)的導航等。

    一個典型的JSF應用將其中的每個頁面和一個backing-bean結(jié)合起來,然而在現(xiàn)實應用中,強制的執(zhí)行這種one-on-one的關(guān)系不是一種理想的解決方案,它可能會導致代碼重復等問題。在現(xiàn)實的應用中,多個頁面可以共享一個backing-bean,例如在JCatalog中, CreateProduct和EditProduct將共享同一個ProductBean定義。

    model對象特定于表示層中的一個view對象,它包含必須顯示在view層的數(shù)據(jù)以及驗證用戶輸入、處理事件和與業(yè)務(wù)邏輯層交互的處理邏輯等。在基于 JSF的應用中backing bean就是view對象,在本文中backing bean和view對象是可互換的名詞。

    對比于struts中的ActionForm和Action,利用JSF中的backing-bean進行開發(fā)將能更好的遵循面向?qū)ο蠓椒ǎ粋€ backing-bean不僅包含view數(shù)據(jù),而且還包含與這些數(shù)據(jù)相關(guān)的行為,而在struts中,Action和ActionForm分別包含數(shù)據(jù)和邏輯。

    我們都應該聽說過domain object model,那么,domain object model和view對象之間有什么區(qū)別呢?在一個簡單的Web應用中,一個domain object model能夠橫穿所有層中,而在復雜的應用中,需要用到一個單獨的view對象模型。domain object model應該屬于業(yè)務(wù)邏輯層,它包含業(yè)務(wù)數(shù)據(jù)和與特定業(yè)務(wù)對象相關(guān)的業(yè)務(wù)邏輯;一個view對象包含presentation-specific的數(shù)據(jù)和邏輯。將view對象從domain object model中分離出來的缺點是在這兩個對象模型之間必將出現(xiàn)數(shù)據(jù)映射。在JCatalog中,ProductBeanBuilder和 UserBeanBuilder利用reflection-based Commons BeanUtils來實現(xiàn)數(shù)據(jù)映射。

    安全
    目前,JSF沒有內(nèi)建的安全特性,而對于范例應用來說安全需求是非常基礎(chǔ)的:用戶登錄到administration intranet中僅需用戶名和密碼認證,而無需考慮授權(quán)。
    針對于JSF的認證,已有幾種方法提出:
    • 利用一個backing bean:這一個方法非常簡單,然而它卻將backing bean與特殊的繼承關(guān)系結(jié)合起來了
    • 利用JSF的ViewHandler decorator:這一方法中,安全邏輯緊密地與一特定Web層技術(shù)聯(lián)系在了一起
    • 利用servlet filter:一個JSF應用與其他的Web應用沒有什么兩樣,filter仍是處理認證檢查的最好地方,這種方法中,認證邏輯與Web應用分離開來
    在我們的范例程序中,SecurityFilter類被用來處理用戶的認證,目前,受保護的資源只包含三個頁面,出于簡單的考慮,將它們的位置被硬編碼到Filter類中。

    分頁
    該應用中的Catalog頁面需要分頁,表示層可用來處理分頁,即它取出所有的數(shù)據(jù)并保存在這一層;分頁同樣可在business-logic層、 integration層、甚至EIS層中實現(xiàn)。由于在JCatalog中假設(shè)不超過500個產(chǎn)品,因此所有的產(chǎn)品信息能存放在一個user session中,我們將分頁邏輯放在了ProductListBean中,與分頁相關(guān)的參數(shù)將通過JSF managed-bean工具配置。

    Caching
    Caching是提高Web應用性能的最重要技術(shù)之一,在應用構(gòu)建中的很多層中都可以實現(xiàn)caching。JSF managed-bean工具可以使在表示層實現(xiàn)caching非常容易。通過改變一個managed bean的范圍,這個managed bean中包含的數(shù)據(jù)可以在不同的范圍內(nèi)緩存。

    范例應用中采用了兩級caching,第一級caching存在于業(yè)務(wù)邏輯層,CachedCatalogServiceImpl類維護了一個所有產(chǎn)品和目錄的讀寫cache,Spring將該類作為一個singleton service bean來管理,所以,一級cache是一個應用范圍的讀寫cache。

    為了簡化分頁邏輯并進而提高應用的速度,產(chǎn)品同樣在session范圍內(nèi)緩存到表示層,每一個用戶維護著他自己的ProductListBean,這一方法的缺點是內(nèi)存的消耗和數(shù)據(jù)的失效問題,在一個用戶session中,如果管理員更改了catalog,用戶可到的將是失效的數(shù)據(jù),然而,由于我們假設(shè)應用的數(shù)據(jù)不會經(jīng)常的改變,所以這些缺點將能夠忍受。

    File upload
    目前的JSF Sun參考實現(xiàn)中不支持file upload。Struts雖已具有非常不錯的file upload能力,然而要想使用這一特性需要Struts-Faces整合庫。在JCatalog中,一個圖像與一個產(chǎn)品相關(guān)聯(lián),在一個用戶創(chuàng)建了新的產(chǎn)品后,她必須將相應的圖片上傳,圖片將保存在應用服務(wù)器的文件系統(tǒng)里,產(chǎn)品的ID就是圖像名稱。

    范例應用中采用、Servlet和Jakarta Common的file-upload API來實現(xiàn)簡單的文件上傳功能,該方法包含兩個參數(shù):圖像路徑和圖像上傳結(jié)果頁面。它們將通過ApplicationBean來配置,詳細內(nèi)容請參看 FileUploadServlet類。

    Validation
    JSF中發(fā)布的標準validator是非常基礎(chǔ)的,無法滿足現(xiàn)實的需要,但很容易開發(fā)出自己的JSF validator,在范例中,我開發(fā)了SelectedItemsRange validator,它用來驗證UISelectMany組件中選擇的數(shù)量:

    ?
    ? ??
    ????
    ?


    詳細情況請參看范例。

    定制錯誤信息
    在JSF中,你可以為converters和validators創(chuàng)建resource bundle和定制錯誤信息,一個resource bundle可在faces-config.xml中創(chuàng)建:

    ? catalog.view.bundle.Messages

    并將錯誤信息的key-value對加到Message.properties文件中:

    ? javax.faces.component.UIInput.CONVERSION=Input data is not in the correct type.
    ? javax.faces.component.UIInput.REQUIRED=Required value is missing.

    業(yè)務(wù)邏輯層和Spring Framework
    業(yè)務(wù)對象和業(yè)務(wù)服務(wù)存在于業(yè)務(wù)邏輯層中,一個業(yè)務(wù)對象不僅包含數(shù)據(jù),而且包含相應的邏輯,在范例應用中包含三個業(yè)務(wù)對象:Product、Category和User。

    業(yè)務(wù)服務(wù)與業(yè)務(wù)對象交互并提供更高級的業(yè)務(wù)邏輯,需要首先定義一個正式的業(yè)務(wù)接口,它是直接與終端用戶交互的服務(wù)接口。在JCatalog中,通過在 Spring Framework幫助下的POJO實現(xiàn)業(yè)務(wù)邏輯層,其中共有兩個業(yè)務(wù)服務(wù):CatalogService包含Catalog管理相關(guān)的業(yè)務(wù)邏輯, UserService中包含User管理邏輯。

    Spring是基于IoC概念的框架,在范例應用中用到的Spring特性包括:
    • Bean management with application contexts:Spring可以有效地組織我們的中間層對象,它能夠消除singleton的proliferation,并易于實現(xiàn)良好的面向?qū)ο缶幊谭椒ǎ础熬幊痰浇涌凇薄?/font>
    • Declarative Transaction management: Spring利用AOP實現(xiàn)事務(wù)管理,而無需借助于EJB容器,利用這種方法,事務(wù)管理可以用于任何POJO中。Spring的事務(wù)管理不局限于JTA,而是可以采用不同的事務(wù)策略,在范例應用中,我們將使用declarative transaction management with Hibernate transaction。
    • Data-access exception hierarchy:Spring提供了非常好的異常來代替SQLException,為利用Spring的異常,必須在Spring的配置文件中定義以下異常轉(zhuǎn)換:
    ???????
    ? ? ? ? ?
    ?????????????
    ?????????

    ???????


    ??? ??? 在范例應用中,如果一個具有重復ID的新產(chǎn)品被插入,將會拋出DataIntegrityViolationException,這一異常將被
    ??????? catch并rethrown一個DuplicateProductIdException。這樣,該異常就可以與其它的異常區(qū)別處理。
    • Hibernate integration:Spring與Hibernate這樣的ORM框架整合的非常好,Spring提供了對Hibernate session的高效和安全的處理,它可通過application context配置Hibernate的SessionFactories和JDBC數(shù)據(jù)源,并使得應用易于測試。

    Integration層和Hibernate
    Hibernate是一個開源的ORM框架,它可以支持所有主流SQL數(shù)據(jù)庫系統(tǒng),Hibernate的查詢語言為對象和關(guān)系架起了非常好的橋梁。Hibernate提供了強大的功能以實現(xiàn):數(shù)據(jù)讀取和更新、事務(wù)管理、數(shù)據(jù)連接池、查詢和實體關(guān)系管理等。

    Data Access Ojbect(DAO)
    JCatalog中采用了Dao模式,該模式抽象和封裝了所有對數(shù)據(jù)源的訪問,該應用中包括兩個DAO接口:CatalogDao和UserDao,它們相應的實現(xiàn)HibernateCatalogDaoImpl和HibernateUserDAoImpl包含了Hibernate特定的邏輯來實現(xiàn)數(shù)據(jù)的管理和持久化。

    實現(xiàn)
    現(xiàn)在我們來看看如何將上面討論的這些東西包裝在一起以實現(xiàn)JCatalog,你可以從這個地址下載源碼:source code

    數(shù)據(jù)庫設(shè)計
    我們?yōu)樵摲独龖脛?chuàng)建了包含4個表的數(shù)據(jù)庫,如圖5所示:


    類設(shè)計
    圖6顯示了JCatalog的類圖


    “編程到接口”的思想貫穿了整個設(shè)計實現(xiàn)中,在表示層,共用到四個backing bean:ProductBean、ProductListBean、UserBean和MessageBean;業(yè)務(wù)邏輯層包含兩個業(yè)務(wù)服務(wù) (CatalogService和UserService)和三個業(yè)務(wù)對象(Product、Category和User);Integration層有兩個Dao接口和它們相應的Hibernate實現(xiàn),Spring的application context用來管理絕大多數(shù)的業(yè)務(wù)邏輯層和integration層的對象;ServiceLocator將JSF和業(yè)務(wù)邏輯層整合在了一起。

    Wire everything up
    由于篇幅所限,我們僅舉例說明,范例中use case CreateProduct展示了如何裝配和構(gòu)建應用,在詳細講述細節(jié)前,我們利用sequence圖(圖7)來說明所有層的end-tp-end整合。



    表示層
    表示層實現(xiàn)包括創(chuàng)建JSP頁面、定義頁導航、創(chuàng)建和配置backing bean以及將JSF與業(yè)務(wù)邏輯層整合。
    • JSP page:createProduct.jsp是用來創(chuàng)建新產(chǎn)品的頁面,它包含UI組件并將組件打包成ProductBean,ValidateItemsRange標簽用來驗證用戶選擇的種類數(shù)量,對每一個產(chǎn)品至少要有一個種類被選中。
    • 頁面導航:應用中的導航被定義在應用的配置文件faces-navigation.xml中,CreateProduct的導航準則如下:

    ?? *
    ??
    ????? createProduct
    ????? /createProduct.jsp
    ??


    ?? /createProduct.jsp
    ??
    ????? success
    ????? /uploadImage.jsp
    ??
    ??
    ????? retry
    ????? /createProduct.jsp
    ??
    ??
    ????? cancel
    ????? /productList.jsp
    ??

    • Backing bean:ProductBean不僅包含有將數(shù)據(jù)映射到頁面上的UI組件的屬性,還包括三個action:createAction、editAction和deleteAction,下面是createAction方法的代碼:
    public String createAction() {
    ?? try {
    ????? Product product = ProductBeanBuilder.createProduct(this);

    ????? //Save the product.
    ????? this.serviceLocator.getCatalogService().saveProduct(product);

    ????? //Store the current product id inside the session bean.
    ????? //For the use of image uploader.
    ????? FacesUtils.getSessionBean().setCurrentProductId(this.id);

    ????? //Remove the productList inside the cache.
    ????? this.logger.debug("remove ProductListBean from cache");
    ????? FacesUtils.resetManagedBean(BeanNames.PRODUCT_LIST_BEAN);
    ?? } catch (DuplicateProductIdException de) {
    ????? String msg = "Product id already exists";
    ????? this.logger.info(msg);
    ????? FacesUtils.addErrorMessage(msg);

    ????? return NavigationResults.RETRY;
    ?? } catch (Exception e) {
    ????? String msg = "Could not save product";
    ????? this.logger.error(msg, e);
    ????? FacesUtils.addErrorMessage(msg + ": Internal Error");

    ????? return NavigationResults.FAILURE;
    ?? }
    ?? String msg = "Product with id of " + this.id + " was created successfully.";
    ?? this.logger.debug(msg);
    ?? FacesUtils.addInfoMessage(msg);

    ?? return NavigationResults.SUCCESS;
    }
    • Managed-bean聲明:ProductBean必須在JSF配置文件faces-managed-bean.xml中配置:

    ??
    ????? Backing bean that contains product information.
    ??
    ?? productBean
    ?? catalog.view.bean.ProductBean
    ?? request???
    ??
    ????? id
    ????? #{param.productId}
    ??
    ??
    ????? serviceLocator
    ????? #{serviceLocatorBean}
    ??

    • ?表示層和業(yè)務(wù)邏輯層之間的整合: ServiceLocator抽象了查找服務(wù)的邏輯,在范例應用中,ServiceLocator被定義為一個接口,該接口實現(xiàn)為一個JSF的 managed bean,即ServiceLocatorBean,它將在Spring的application context中尋找服務(wù):
    ServletContext context = FacesUtils.getServletContext();
    this.appContext = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
    this.catalogService = (CatalogService)this.lookupService(CATALOG_SERVICE_BEAN_NAME);
    this.userService = (UserService)this.lookupService(USER_SERVICE_BEAN_NAME);
    業(yè)務(wù)邏輯層
    • 業(yè)務(wù)對象:由于采用Hibernate提供持久化,因此Product和Category兩個業(yè)務(wù)對象需要為它們的所有field提供getter和setter。
    • 業(yè)務(wù)服務(wù):CatalogService接口中定義了所有的與Catalog management相關(guān)的服務(wù):
    public interface CatalogService {
    ?? public Product saveProduct(Product product) throws CatalogException;
    ?? public void updateProduct(Product product) throws CatalogException;
    ?? public void deleteProduct(Product product) throws CatalogException;
    ?? public Product getProduct(String productId) throws CatalogException;
    ?? public Category getCategory(String categoryId) throws CatalogException;
    ?? public List getAllProducts() throws CatalogException;
    ?? public List getAllCategories() throws CatalogException;
    }
    • Spring Configuration:這里是CatalogService的Spring配置:


    ??




    ??




    ??
    ??
    ??
    ?????
    ???????? PROPAGATION_REQUIRED,readOnly
    ?????? PROPAGATION_REQUIRED
    ?????? PROPAGATION_REQUIRED
    ?????? PROPAGATION_REQUIRED
    ?????
    ??

    • Spring和Hibernate的整合:下面是HibernateSessionFactory的配置:

    <!-- Hibernate SessionFactory Definition -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
    ?? <property name="mappingResources">
    ??????<list>
    ???????? <value>catalog/model/businessobject/Product.hbm.xml</value>
    ???????? <value>catalog/model/businessobject/Category.hbm.xml</value>
    ???????? <value>catalog/model/businessobject/User.hbm.xml</value>
    ??????</list>
    ?? </property>
    ?? <property name="hibernateProperties">
    ??????<props>
    ???????? <prop key="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</prop>
    ?????? <prop key="hibernate.show_sql">true</prop>
    ?????? <prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
    ?????? <prop key="hibernate.cache.provider_class">net.sf.hibernate.cache.HashtableCacheProvider</prop>
    ??????</props>
    ?? </property>
    ?? <property name="dataSource">
    ??????<ref bean="dataSource"/>
    ?? </property>
    </bean>

    CatalogDao uses HibernateTemplate to integrate between Hibernate and Spring. Here's the configuration for HibernateTemplate:

    <!-- Hibernate Template Defintion -->
    <bean id="hibernateTemplate" class="org.springframework.orm.hibernate.HibernateTemplate">
    ?? <property name="sessionFactory"><ref bean="sessionFactory"/></property>
    ?? <property name="jdbcExceptionTranslator"><ref bean="jdbcExceptionTranslator"/></property>
    </bean>



    Integration層
    Hibernate通過xml配置文件來映射業(yè)務(wù)對象和關(guān)系數(shù)據(jù)庫,在JCatalog中,Product.hbm.xml表示了Product對象的映射,Category.hbm.xml則用來表示Category的映射,Product.hbm.xml如下:

    <?xml version="1.0"?>
    <!DOCTYPE hibernate-mapping PUBLIC
    ??????"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    ??????"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
    <hibernate-mapping package="catalog.model.businessobject">
    ?? <class name="Product" table="product">
    ??????<id name="id" column="ID" unsaved-value="null">
    ???????? <generator class="assigned"/>
    ??????</id>
    ??????<property name="name" column="NAME" unique="true" not-null="true"/>
    ??????<property name="price" column="PRICE"/>????
    ??????<property name="width" column="WIDTH"/>??????
    ??????<property name="height" column="height"/>??????
    ??????<property name="description" column="description"/> ??
    ??????<set name="categoryIds" table="product_category" cascade="all">
    ???????? <key column="PRODUCT_ID"/>
    ???????? <element column="CATEGORY_ID" type="string"/>
    ??????</set>
    ?? </class>
    </hibernate-mapping>

    CatalogDao is wired with HibernateTemplate by Spring:

    <!-- Catalog DAO Definition: Hibernate implementation -->
    <bean id="catalogDao" class="catalog.model.dao.hibernate.CatalogDaoHibernateImpl">
    ?? <property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property>
    </bean>

    結(jié)論
    本文主要講述了如何將JSF與Spring、Hibernate整合在一起來構(gòu)建實際的Web應用,這三種技術(shù)的組合提供了一個強大的Web應用開發(fā)框架。在Web應用的高層設(shè)計中應該采用多層構(gòu)架體系,JSF非常適合MVC設(shè)計模式以實現(xiàn)表示層,Spring可用在業(yè)務(wù)邏輯層中管理業(yè)務(wù)對象,并提供事物管理和資源管理等,Spring與Hibernate結(jié)合的非常出色,Hibernate是強大的O/R映射框架,它可以在integration層中提供最好的服務(wù)。

    通過將整個Web應用分割成多層,并借助于“編程到接口”,應用程序的每一層所采用的技術(shù)都是可替換的,例如Struts可以用來替換JSF,JDO可替換Hibernate。各層之間的整合不是不值得研究,采用IoC和ServiceLocator設(shè)計模式可使得整合非常容易。JSF提供了其它Web框架欠缺的功能,然而,這并不意味著你馬上拋棄Struts而開始使用JSF,是否采用JSF取決于項目目前的狀況和功能需求,以及開發(fā)團隊的意見等。
    posted @ 2006-11-07 19:46 GoodtigerZhao 閱讀(289) | 評論 (0)編輯 收藏
     

    板橋里人 http://www.jdon.com 2005/09/05

      Struts和JSF/Tapestry都屬于表現(xiàn)層框架,這兩種分屬不同性質(zhì)的框架,后者是一種事件驅(qū)動型的組件模型,而Struts只是單純的MVC模式框架,老外總是急吼吼說事件驅(qū)動型就比MVC模式框架好,何以見得,我們下面進行詳細分析比較一下到底是怎么回事?

      首先事件是指從客戶端頁面(瀏覽器)由用戶操作觸發(fā)的事件,Struts使用Action來接受瀏覽器表單提交的事件,這里使用了Command模式,每個繼承Action的子類都必須實現(xiàn)一個方法execute。

      在struts中,實際是一個表單Form對應一個Action類(或DispatchAction),換一句話說:在Struts中實際是一個表單只能對應一個事件,struts這種事件方式稱為application event,application event和component event相比是一種粗粒度的事件。

      struts重要的表單對象ActionForm是一種對象,它代表了一種應用,這個對象中至少包含幾個字段,這些字段是Jsp頁面表單中的input字段,因為一個表單對應一個事件,所以,當我們需要將事件粒度細化到表單中這些字段時,也就是說,一個字段對應一個事件時,單純使用Struts就不太可能,當然通過結(jié)合JavaScript也是可以轉(zhuǎn)彎實現(xiàn)的。

      而這種情況使用JSF就可以方便實現(xiàn),

    <h:inputText id="userId" value="#{login.userId}">
      <f:valueChangeListener type="logindemo.UserLoginChanged" />
    </h:inputText>

      #{login.userId}表示從名為login的JavaBean的getUserId獲得的結(jié)果,這個功能使用struts也可以實現(xiàn),name="login" property="userId"

      關(guān)鍵是第二行,這里表示如果userId的值改變并且確定提交后,將觸發(fā)調(diào)用類UserLoginChanged的processValueChanged(...)方法。

      JSF可以為組件提供兩種事件:Value Changed和 Action. 前者我們已經(jīng)在上節(jié)見識過用處,后者就相當于struts中表單提交Action機制,它的JSF寫法如下:

    <h:commandButton id="login" commandName="login">
      <f:actionListener type=”logindemo.LoginActionListener” />
    </h:commandButton>

      從代碼可以看出,這兩種事件是通過Listerner這樣觀察者模式貼在具體組件字段上的,而Struts此類事件是原始的一種表單提交Submit觸發(fā)機制。如果說前者比較語言化(編程語言習慣做法類似Swing編程);后者是屬于WEB化,因為它是來自Html表單,如果你起步是從Perl/PHP開始,反而容易接受Struts這種風格。

    基本配置

      Struts和JSF都是一種框架,JSF必須需要兩種包JSF核心包、JSTL包(標簽庫),此外,JSF還將使用到Apache項目的一些commons包,這些Apache包只要部署在你的服務(wù)器中既可。

      JSF包下載地址:http://java.sun.com/j2ee/javaserverfaces/download.html選擇其中Reference Implementation。

      JSTL包下載在http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi

      所以,從JSF的驅(qū)動包組成看,其開源基因也占據(jù)很大的比重,JSF是一個SUN伙伴們工業(yè)標準和開源之間的一個混血兒。

      上述兩個地址下載的jar合并在一起就是JSF所需要的全部驅(qū)動包了。與Struts的驅(qū)動包一樣,這些驅(qū)動包必須位于Web項目的WEB-INF/lib,和Struts一樣的是也必須在web.xml中有如下配置:

    <web-app>
      <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
      </servlet>

      <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
      </servlet-mapping>
    </web-app>

      這里和Struts的web.xml配置何其相似,簡直一模一樣。

      正如Struts的struts-config.xml一樣,JSF也有類似的faces-config.xml配置文件:


    <faces-config>
      <navigation-rule>
        <from-view-id>/index.jsp</from-view-id>
        <navigation-case>
          <from-outcome>login</from-outcome>
          <to-view-id>/welcome.jsp</to-view-id>
        </navigation-case>
      </navigation-rule>

      <managed-bean>
        <managed-bean-name>user</managed-bean-name>
        <managed-bean-class>com.corejsf.UserBean</managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
      </managed-bean>
    </faces-config>

    ?

      在Struts-config.xml中有ActionForm Action以及Jsp之間的流程關(guān)系,在faces-config.xml中,也有這樣的流程,我們具體解釋一下Navigation:

      在index.jsp中有一個事件:

    <h:commandButton label="Login" action="login" />

      action的值必須匹配form-outcome值,上述Navigation配置表示:如果在index.jsp中有一個login事件,那么事件觸發(fā)后下一個頁面將是welcome.jsp

      JSF有一個獨立的事件發(fā)生和頁面導航的流程安排,這個思路比struts要非常清晰。

      managed-bean類似Struts的ActionForm,正如可以在struts-config.xml中定義ActionForm的scope一樣,這里也定義了managed-bean的scope為session。

      但是如果你只以為JSF的managed-bean就這點功能就錯了,JSF融入了新的Ioc模式/依賴性注射等技術(shù)。

    Ioc模式

      對于Userbean這樣一個managed-bean,其代碼如下:

    public class UserBean {
      private String name;
      private String password;

      // PROPERTY: name
      public String getName() { return name; }
      public void setName(String newValue) { name = newValue; }

      // PROPERTY: password
      public String getPassword() { return password; }
      public void setPassword(String newValue) { password = newValue; }
    }

    <managed-bean>
      <managed-bean-name>user</managed-bean-name>
      <managed-bean-class>com.corejsf.UserBean</managed-bean-class>
      <managed-bean-scope>session</managed-bean-scope>

      <managed-property>
        <property-name>name</property-name>
        <value>me</value>
      </managed-property>

      <managed-property>
        <property-name>password</property-name>
        <value>secret</value>
      </managed-property>
    </managed-bean>

      faces-config.xml這段配置其實是將"me"賦值給name,將secret賦值給password,這是采取Ioc模式中的Setter注射方式

    Backing Beans

      對于一個web form,我們可以使用一個bean包含其涉及的所有組件,這個bean就稱為Backing Bean, Backing Bean的優(yōu)點是:一個單個類可以封裝相關(guān)一系列功能的數(shù)據(jù)和邏輯。

      說白了,就是一個Javabean里包含其他Javabean,互相調(diào)用,屬于Facade模式或Adapter模式。


      對于一個Backing Beans來說,其中包含了幾個managed-bean,managed-bean一定是有scope的,那么這其中的幾個managed-beans如何配置它們的scope呢?

    <managed-bean>
      ...
      <managed-property>
        <property-name>visit</property-name>
        <value>#{sessionScope.visit}</value>
      </managed-property>

      這里配置了一個Backing Beans中有一個setVisit方法,將這個visit賦值為session中的visit,這樣以后在程序中我們只管訪問visit對象,從中獲取我們希望的數(shù)據(jù)(如用戶登陸注冊信息),而visit是保存在session還是application或request只需要配置既可。

    UI界面

      JSF和Struts一樣,除了JavaBeans類之外,還有頁面表現(xiàn)元素,都是是使用標簽完成的,Struts也提供了struts-faces.tld標簽庫向JSF過渡。

      使用Struts標簽庫編程復雜頁面時,一個最大問題是會大量使用logic標簽,這個logic如同if語句,一旦寫起來,搞的JSP頁面象俄羅斯方塊一樣,但是使用JSF標簽就簡潔優(yōu)美:

    <jia:navigatorItem name="inbox" label="InBox"
      icon="/images/inbox.gif"
      action="inbox"
      disabled="#{!authenticationBean.inboxAuthorized}"/>

      如果authenticationBean中inboxAuthorized返回是假,那么這一行標簽就不用顯示,多干凈利索!

      先寫到這里,我會繼續(xù)對JSF深入比較下去,如果研究過Jdon框架的人,可能會發(fā)現(xiàn),Jdon框架的jdonframework.xml中service配置和managed-bean一樣都使用了依賴注射,看來對Javabean的依賴注射已經(jīng)迅速地成為一種新技術(shù)象征,如果你還不了解Ioc模式,趕緊補課。

    附Jsf核心教程一個JSF案例:login.rar

    相關(guān)討論:

    表現(xiàn)層框架Struts/Tapestry/JSF架構(gòu)比較

    討論

    posted @ 2006-11-07 19:38 GoodtigerZhao 閱讀(279) | 評論 (0)編輯 收藏
    僅列出標題  
     
    主站蜘蛛池模板: 国产成人无码免费视频97| 亚洲国产一区视频| 男人的天堂av亚洲一区2区| 亚洲国产a级视频| 久久青草免费91观看| 77777亚洲午夜久久多喷| 亚洲精品99久久久久中文字幕| 日本亚洲欧洲免费天堂午夜看片女人员 | 亚洲一区二区三区乱码A| 日韩人妻一区二区三区免费| 亚洲欧美成aⅴ人在线观看| 亚洲人色婷婷成人网站在线观看| 免费视频爱爱太爽了| 四虎国产精品成人免费久久| 亚洲视频手机在线| 亚洲&#228;v永久无码精品天堂久久 | 亚洲性无码一区二区三区| 亚洲精品无码精品mV在线观看| 日韩亚洲国产高清免费视频| 国产福利在线观看永久免费| 亚洲人成网国产最新在线| 亚洲AV永久青草无码精品| 日韩免费视频播播| 69av免费观看| 国内精品免费久久影院| 国产成人亚洲综合一区| 亚洲国产国产综合一区首页| 亚洲Av无码乱码在线观看性色 | 在线jyzzjyzz免费视频| 免费A级毛片无码专区| 人成电影网在线观看免费| 亚洲性无码AV中文字幕| 亚洲精品中文字幕麻豆| 久久精品国产精品亚洲精品 | 91嫩草亚洲精品| 久久久久久久综合日本亚洲| 亚洲AV无码不卡在线观看下载| 成人A级毛片免费观看AV网站| 人妻无码久久一区二区三区免费| gogo免费在线观看| 精品免费AV一区二区三区|