JSF+Spring+Hibernate的例項講解

elevenxl發表於2008-03-17

JSF+Spring+Hibernate的例項講解

使用JSF建立一個真實的Web應用程式不是沒有意義的任務,這篇文章介紹瞭如何將JSFSping FrameworkHibernate整合,並且給出了使用這些技術建立這個真實的Web應用程式的最佳實踐和設計指導
       JavaServer Faces(JSF)
技術是J2EE應用程式的一個新的使用者介面框架,它非常適合基於MVC(Model-View-Controller)體系結構的應用程式。已經有大量的文章介紹JSF。然而,很多文章都是站在理論研究的層面上,沒有挑戰一個真實的企業開發。很多問題沒有解決,例如,JSF怎樣全面適合MVC體系結構?JSF如何與其他JAVA框架整合?業務邏輯應該放在JSFbacking beans裡面嗎?怎樣處理JSF裡面的安全問題?最重要的是你怎樣使用JSF建立一個真實的Web應用程式?
     
這篇文章涉及所有這些問題。它向你展示如何整合其他特定的Java框架,Spring FrameworkHibernate,它示範怎樣去建立一個叫JCatalogWeb應用程式,一個線上的產品目錄系統。這篇文章使用JCatalog例子,介紹了Web應用程式設計的每一個階段,包括業務需求收集,分析,技術選擇,高層體系結構和詳細設計。這篇文章論述了JCatalog裡面好的和不好的技術,示範了應用程式設計中一些關鍵方面的方法和步驟。
      
這篇文章是寫給正在從事基於J2EE Web應用程式的Java架構師,開發者,它不是對JSFSpring FrameworkHibernate的入門教程。如果您對這些領域不熟悉,請參考文章最後的資源連結。
例子應用程式的功能需求
       
這篇文章的例子應用程式JCatalog是一個真實的Web應用程式,例子足夠現實是為了決定應用程式架構而進行意味深長的討論的基礎。我通過介紹JCatalog專案的需求開始。我在這裡談到後面貫穿於整個文章的內容是為了演示技術選擇和體系結構設計。
設計Web應用程式的第一步是收集系統的功能需求,這個例子應用程式是一個典型的電子商務應用系統。使用者能瀏覽產品目錄和檢視產品細節,管理員能管理產品目錄。功能還可以增加,舉例來說,為了開發一個成熟的電子商務系統,可以新增庫存管理和訂單處理的功能。
用例
用例分析被用於去訪問例子應用程式的功能需求,圖1是應用程式的用例圖。  

       
1 用例圖
       
一個用例圖確定在一個系統中的參與者以及參與者可以執行的操作。例子應用中7個用例必須被實現。參與者中的User能瀏覽產品目錄和察看產品細節。一旦使用者以Administrator身份連線到系統,他就能建立新產品,編輯存在的產品,刪除老的產品。

業務規則
JCatalog
必須符合下面的業務規則:
每個產品有一個唯一的產品ID
每個產品至少屬於一個目錄
產品ID一旦被建立就不能改變
假定
對於產品的設計和實現,我們做下面的假定。
英語是預設語言;不要求國際化
目錄中不超過500種產品
目錄的更新不頻繁
頁面流
2顯示了所有JCatalog的頁面和它們之間的轉換。

 2 頁面流圖
       
應用程式有兩組頁面:公共的國際網際網路和管理員的企業內部網。企業內部網只有對那些成功登陸到系統的使用者有效。產品概要頁面是公用的,它作為產品目錄的內容包含在一個HTML框架裡面。產品列表是一個特殊的目錄,只能被管理員看見,它包含建立、編輯和刪除產品的連結。
       
3是目錄頁的一個模型。理想情況下,每一個頁面所有的控制和必要的內容明細的模型應該被包含在需求文件裡面。

                                                                                          3 目錄頁面模型
高階體系結構設計
下一步的設計是Web應用程式的高階體系結構設計,它包括將應用程式細分成功能元件以及將這些元件劃分到各自所屬的層。高階體系結構設計獨立於使用的技術。
多層體系結構
一個多層體系結構將整個系統劃分成清晰的單元——客戶端、表示層、業務邏輯層、整合層和企業資訊系統(EIS),這保證了清晰的責任劃分以及可維護性和可擴充套件性。三層或多層系統已經被證明比沒有業務邏輯層的客戶-伺服器系統具有更多的可升級性和柔韌性。
客戶端是資料模型被消費和呈現的地方。對於一個Web應用程式,客戶層通常是Web瀏覽器。基於瀏覽器的瘦客戶不包含表示邏輯;它依賴於表示層。
表示層使用業務邏輯層為使用者服務,它知道怎樣去處理一個客戶請求,怎樣去和業務邏輯層結合以及怎樣去選擇下一個試圖去顯示。
業務邏輯層包含一個應用程式的業務物件和業務服務。它從表示層接受請求,基於請求處理業務邏輯,作為訪問EIS層資源的的中介。業務邏輯層元件使用許多系統級別的服務,例如,安全管理、事物管理和資源管理。
整合層是業務邏輯層和EIS層之間的橋樑。它封裝了與EIS層相結合的邏輯。有時,整合層和業務邏輯層的結合是作為中間層被提到。
應用程式資料在EIS層被持久化,包括關聯式資料庫,物件導向資料庫和遺留系統。
JCatalog
的體系結構設計
4顯示了JCatalog的高階體系結構設計以及它怎樣適合多層體系結構。

                                                                      

4 高階體系結構圖
應用程式使用了一個多層的非分散式的體系結構,圖4顯示應用程式層和每一層技術選擇的劃分。它也用於應用程式的部署圖。對於一個可配置的體系結構,表示層、業務邏輯層和整合層被定位在同樣的Web容器。定義良好的介面隔離了每一層的職責。可配置的體系結構使應用程式簡單和可升級。
對於表示層,經驗告訴我們,最好的實踐是選擇一個存在的,被驗證的Web應用框架,遠比設計開發一個定製的框架好。我們有幾個Web應用框架可供選擇,舉例來說,StrutsWebWorkJSF。對於JCatalog專案,我們使用JSF
對於業務邏輯層,不是使用EJB(Enterprise JavaBeans)就是使用POJO(plain old Java objects)。如果應用程式是分散式的,EJB具有遠端介面是一個較好的選擇。因為JCatalog是一個典型的沒有遠端訪問請求的Web應用程式,POJOSpring框架的幫助下,用於實現業務邏輯層。
Pure JDBC(Java Database Connectivity)
:這是最靈活的實現方法;然而,低階的JDBC和不好的JDBC程式碼工作是麻煩的,執行的不好。
Entity beans
:一個容器管理持久化(CMP,container-managed persistence)的entity bean是隔離資料訪問程式碼和處理O/R(object- relational) mapping資料持久化的昂貴的方法。它是一個以應用伺服器為中心的解決辦法。一個entity bean不和特定的資料庫緊耦合,但是應用程式和EJB容器進耦合。
O/R mapping framework
:一個O/R影射的框架採用以物件為中心的方法實現資料持久化。一個以物件為中心的應用程式是容易開發和高度輕便的。在這個領域記憶體在幾個框架——JDO(Java Data Objects)Hibernate,ToplinkCocoBase是一個新的例子。在例子應用程式中我們使用HIbernate
現在,讓我們討論將應用程式的每一個層聯合起來設計的問題。因為JSF相對來說是一個新技術,我強調一下它的使用。
表現層和JavaServer Faces(JSF)
表現層收集使用者輸入,呈現資料,控制頁面導航,代替使用者與業務邏輯層互動。表現層也能校驗使用者輸入,維護應用程式的會話狀態。下面的章節,我討論表現層的設計考慮和模式以及我選擇JSF去實現JCatalog專案的表現層的原因。
MOdel-View-Controller(MVC)
MVC
Java藍皮書(BluePrints)中推薦的互動式應用程式體系結構設計模式。MVC分別設計關注的問題,因此減少了程式碼的重複,集中控制,使應用程式更具擴充套件性。MVC也幫助開發者使用不同的技術集合,集中他們核心的技術,通過定義清晰的介面進行合作。MVC是表現層的體系結構設計模式。
JavaServer Face
JSF
是一個基於JavaWeb應用程式服務端的使用者介面元件框架。JSF包括表示UI元件和管理其狀態的API;處理事件,服務端校驗,資料轉換;定義頁面導航;支援國際化和可訪問性;提供所有這些特點的擴充套件能力。它還包括兩個為JSP定製的標籤庫,一個用於表示JSP頁面內的UI元件,一個用於配置服務端的物件元件。
JSF
MVC
JSF
很適合基於MVC的表現層體系結構。它提供動作和表現之間清楚地劃分。它影響了UI元件和Web層概念,不限定你去使用特定的指令碼技術或者標記語言。
JSF backing beans
model層(後面的章節有關於backing beans 的更多內容)。它們也包含動作,這是控制層的擴充套件,代理使用者對業務邏輯層的請求。請注意,從整體應用程式的體系結構來看,業務邏輯層也能被作為Model層提到。使用JSF定製標籤的JSP頁面是檢視層。Faces Servlet提供控制者的功能。
為什麼用JSF
JSF
不僅僅只是另一個Web框架,下面是JSF與其他Web框架不同的特點:
Swing一樣物件導向的Web應用程式開發:服務端有狀態的UI元件模型,具有事件監聽和操作者,開始了物件導向Web應用程式開發。
Backing-bean
管理:Backing beans是頁面中JavaBeans元件和UI元件的聯合。Backing-bean管理UI元件物件定義和物件執行應用程式特殊過程以及控制資料的分離。JSF在正確的範圍內執行儲存和管理這些backing-bean例項。
可擴充套件的UI元件模型:JSF UI元件是組成JSF應用程式使用者介面可配置、可複用的元素。你能擴充套件標準的UI元件和開發更多的複雜元件。舉例來說,選單條和樹型構件。
靈活的表現模型:一個renderer分隔一個UI元件的功能和檢視。多個renderer能被建立,用於定義相同或不同客戶端上同樣元件的不同外觀。
可擴充套件的轉化和校驗模型:基於標準的轉換者和校驗者,你能開發定製的轉換者和校驗者,它們提供最好的模型保護。
儘管JSF很強大,但是現在還不成熟。元件、轉換者和校驗者是JSF基本的。每一個校驗模型不能處理元件和校驗者之間多對多的校驗。另外,JSF定製標籤不能和JSTLJSP Standard Tag Library)無縫結合。
在下面的部分,我討論用JSF實現JCatalog專案時幾個關鍵方面和設計決定。首先討論JSFmanaged beansbacking beans的定義和使用。然後,我介紹JSF中怎樣處理安全、分頁、快取、檔案上傳、校驗和錯誤訊息定製。
Managed bean,backing bean,view object
domain object model
JSF
介紹了兩個新的術語:managed bean backing beanJSF 提供一個強大的managed-bean工廠。被JSF執行的JavaBean物件管理被叫做managed beans。一個managed bean描述一個bean怎樣被建立和管理。它沒有利用bean的功能性。
Backing bean
定義頁面特性和處理邏輯與UI元件的聯合。每一個backing-bean屬性被繫結到元件例項或者它的值中的一個。一個backing bean也定義一個元件可執行的功能的集合,例如,校驗元件的資料,處理元件觸發事件,元件啟用時與導航相關的執行過程。
一個典型的JSF應用程式在應用程式的每一個頁面中連線一個backing bean。然而,有時在真實的世界裡,強迫一個backing bean和一個頁面一對一的關係不是一個理想的解決方案。它能造成象程式碼重複這樣的問題。在真實世界的場景裡,幾個頁面可能需要共享在後臺的同樣的backing bean。例如,在JCatalog專案裡,CreateProductEditProduct頁面共享同樣的ProductBean的定義。
一個試圖物件是在表示層明確使用的模型物件。它包含了必須顯示在檢視層的資料和校驗使用者輸入,處理事件和與業務邏輯層相結合的邏輯。backing bean是基於JSF應用程式的檢視物件。
在這篇文章中Backing bean 和檢視物件是可交換的術語。
比較Struts中的ActionformAction,在JSF中開發backing beans遵循物件導向設計的最好實踐。一個backing bean不僅包含檢視資料,也包含與資料相關的行為。在Struts 中,Action ActionForm包含資料和邏輯分離。
我們都聽說過域物件模型。那麼,域物件模型和檢視物件有什麼不同呢?在一個簡單的Web應用程式裡,一個域物件模型能被用於所有的層,然而,在一些複雜的Web應用程式裡面,一個單獨的檢視物件模型需要被使用。域物件模型是關於業務物件,應該歸入業務邏輯層。它包含特定業務物件相關的業務資料和業務邏輯。一個檢視物件包含特定資料和行為的表示。JCatalog專案的ProductListBean提供了一個好的例子。它包含表示層資料和邏輯細節,舉例來說,與分頁相關的資料和邏輯。從域物件模型分離檢視物件的缺點是資料對映必須發生在兩個物件模型之間。在JCatalog專案中,ProductBeanBuilderUserBeanBuilder使用基於反射的Commons BeanUtils去實現資料對映。
安全
當前,JSF沒有內建的安全特徵。例子的安全需求是基本的:使用者連線到管理員使用的公司內部網需要的認證是基於使用者名稱和密碼,不需要授權。
JSF裡面幾個處理使用者認證的方法已經被提出:
Use a base backing bean
:這個解決方 案是簡單的。然而,它使backing beans與特殊的遺產層次繫結。
Use JSF ViewHandler decorator
:這種方法使安全邏輯緊緊地加上一個特殊的Web層技術。
Use a servlet filter
:一個JSF 應用程式與其他基於JavaWeb應用程式不同。它在一個恰當的地方使用一個過濾器處理認證檢查。這種方法使Web應用程式中的認證邏輯減弱了。
在例子應用程式中,SecurityFilter類處理使用者認證。當前,受保護的資源只有三個頁面,為了簡單,它們被硬編碼在Filter類裡面。可以通過擴充套件安全規則來改進它,把受保護的資源放到配置檔案中。
分頁
應用程式的目錄頁需要分頁。表現層能處理分頁,這意味著所有資料必須被重新得到儲存在這層。分頁也能在業務邏輯層、整合層甚至是EIS層處理。JCatalog專案的假定是在目錄中的產品不超過500種。所有產品資訊適合儲存在使用者session中。分頁邏輯存在ProductListBean類中。與分頁有關的引數每頁的產品通過JSFmanaged-bean工具配置。
快取
快取是Web應用程式中改善效能的眾多重要技術中的一種。快取能在應用程式體系結構內的許多層完成。體系結構中的一層減少呼叫它下面的層時,快取是非常有益的。JSF managed-bean工具使在表現層實現快取更容易。通過改變一個managed bean的範圍,包含在managed bean中的資料能在不同的範圍內快取。
例子應用程式使用二級快取。第一級快取在業務邏輯層裡面。CachedCatalogServiceImpl類維護所有產品和目錄的讀/寫快取。Spring 管理的類作為一個單獨服務bean。所以,一級快取是一個應用程式範圍的讀/寫快取。
對於簡單的分頁邏輯和將來應用程式速度的提高,表現層的會話範圍內的產品也被快取。每個使用者維護他session裡面自己的ProductListBean。缺點是佔用系統記憶體和存在舊資料。在一個使用者session的持續時間裡,如果管理員更新了目錄,使用者可能會看到舊的目錄資料。然而,基於這樣的假定,目錄中部超過500種產品,而且目錄更新不頻繁,我們應該能夠忍受這些缺點。
檔案上傳
目前,JSFSun參考實現中不支援檔案上傳。Struts有很好的檔案上傳能力,然而,Struts外觀整合庫是必須使用。 在JCatalog專案中,一個圖片與每個產品關聯。一個使用者建立一個新的產品之後,必須上傳與之相關的圖片。圖片儲存在應用伺服器的檔案系統裡面。產品ID是圖片名.
例子應用程式使用<input type="file">,Servlet Jakarta通用的檔案上傳API,實現一個簡單的檔案長傳功能。這個功能使用兩個引數:產品圖片路徑和圖片上傳結果頁面。它們都通過ApplicatonBean配置。請參考FileUploadServlet類的詳細資料。
校驗
JSF
具有的標準校驗是簡單基本的,不能滿足真實的需求。開發自己的JSF校驗是容易的。我在例子應用程式中使用定製標籤來開發SelectedItemsRange校驗。它校驗通過UISelectMany UI元件選擇的專案數量:
<h:selectManyListbox value="#{productBean.selectedCategoryIds}" id="selectedCategoryIds">
   <catalog:validateSelectedItemsRange minNum="1"/>
   <f:selectItems value="#{applicationBean.categorySelectItems}" id="categories"/>
</h:selectManyListbox>
更多的詳細資料請參考例子應用程式。
錯誤訊息定製
 
JSF裡面,你可以設定資源包定製轉換和校驗時的錯誤訊息。資源包被設定在faces-config.xml裡面:
<message-bundle>catalog.view.bundle.Messages</message-bundle>
The error message's key-value pairs are added to the Message.properties file:


#conversion error messages
javax.faces.component.UIInput.CONVERSION=Input data is not in the correct type.

#validation error messages
javax.faces.component.UIInput.REQUIRED=Required value is missing.
業務邏輯層和Spring Framework
業務物件和業務服務在業務邏輯層。一個業務物件不僅包含資料,也有與特定物件關聯的邏輯。在例子應用程式中標識了三個業務物件:Product,CategoryUser.
業務服務與業務物件相結合,提供高階的業務邏輯。一個包含直接使用的服務介面的標準的業務介面層應該被定義。在Spring Framework的幫助下,POJO實現了Jcatalog專案業務邏輯層。有兩個業務服務:CatalogService包含與目錄管理相關的業務邏輯,UserService包含了使用者管理邏輯。
Spring
是基於控制反轉概念(IOC,inversion of control)。在例子應用程式中使用的Spring特徵包括:
Bean management with application contexts
Spring能有效地組織我們的中間層物件,垂直處理。Spring 能避免一個實體功能的分解,促進好的物件導向設計實現,舉例來說,介面設計。
Declarative transaction management
Spring 使用AOP(aspect-oriented programming)去描述不使用EJB容器的宣告性事務處理。這種方法,事務管理能被應用到任何POJOSpring事務管理不和JTA(Java Transaction API)繫結,使用不同的事物策略工作。在例子應用程式中宣告性事務管理Hibernate中的事務。
Data-access exception hierarchy
Spring提供一個值得回味的異常層次代替SQLException。使用Spring資料訪問異常層次,Spring資料訪問異常翻譯者必須在Spring配置檔案裡面定義:       
<bean id="jdbcExceptionTranslator"
class= "org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">
   <property name="dataSource">
      <ref bean="dataSource"/>
   </property>
</bean>
在例子應用程式中,如果插入的一個新產品的ID是重複的,一個 DataIntegrityViolationException 會被丟擲。這個異常會被捕獲然後作為DuplicateProductIdException被丟擲。這種方法,DuplicateProductIdException能處理不同的資料訪問異常。
 Hibernate integration
Spring不強迫我們使用它強大的JDBC抽象特徵。它和O/R對映框架整合的很好,尤其是HibernateSping提供有效的、安全的Hibernate會話操作。在應用程式上下文操作Hibernate的配置SessionFactories JDBC資料來源,使應用程式容易測試。
整合層和HIbernate
Hibernate
是一個開源O/R對映框架,它減少使用JDBC API的需要。Hibernate支援所有主流的SQL資料庫管理系統。Hibernate Query LanguageSQL物件導向的最小的擴充套件來設計的,在物件和關係世界間提供了一個優雅的橋。Hibernate提供資料恢復和更新的工具,事務管理,資料連線池,programmatic and declarative queries,宣告實體關係管理。
Hibernate
和其他O/R對映框架相比入侵性較小。使用反射和執行時產生位元組碼,SQL在系統開始時產生。它允許我們開發符合Java習慣的持久物件,包括聯合,繼承,多型,聚合和Java集合框架。在例子應用程式中的業務物件是POJO,不需要實現Hibernate的特殊介面。
Data Access Object (DAO)
JCatalog
專案使用DAO模式。這個模式抽象和封裝了所有對資料來源的訪問。應用程式有兩個DAO介面。CatalogDaoUserDao。它們的實現類是HibernateCatalogdaoImplHibernateUserDaoImpl包含與Hibernate相關的管理和持久化資料邏輯。
實現設計
現在,讓我把每件事情都串起來,實現JCatalog專案。你可以從資源列表中下載應用程式的完整原始碼。
資料庫設計
我們為例子應用程式建立指定目錄的結構,它包含4個表,如圖5
   5 資料結構圖

類設計:圖6圖解了JCatalog專案的類圖

 

                                         6 類圖

面向介面程式設計貫穿於整個設計。在表現層,四個bean被使用:ProductBean, ProductListBean, UserBean MessageBean。業務邏輯層包含兩個服務(CatalogService and UserService)和三個業務物件(Product, Category, and User)。整合層包括兩個DAO介面和它們的Hibernate實現。Spring application contexts 包含和管理業務邏輯層和整合層的很多object beansServiceLocator使JSF和業務邏輯層結合到一起。
Wire everything up
因為這篇文章篇幅的限制,我們只看一個用例。CreateProduct用例示範了怎樣將每件事情串起來建造應用程式。深入細節以前,讓我們使用一個序列圖(圖7)示範所有層端到端的整合:

                                                                                    7 CreateProduct用例的序列圖
現在,讓我們通過對每一層的介紹討論如何實現CreateProduct用例的更多細節。
表現層
表現層的實現包括建立JSP頁面,定義頁面導航,建立和配置backing beans,JSF與業務邏輯層結合。
JSP page
createProduct.jsp是建立新產品的頁面。它包括UI元件和捆綁這些元件的ProductBeanValidateItemsRange自定義標籤檢驗使用者選擇目錄的數目。每個新產品至少有一個目錄被選擇。
Page navigation
:應用程式的導航定義在應用程式的配置檔案裡面,faces-navigation.xmlCreateProduct定義的導航規則是:
<navigation-rule>
   <from-view-id>*</from-view-id>
   <navigation-case>
      <from-outcome>createProduct</from-outcome>
      <to-view-id>/createProduct.jsp</to-view-id>
   </navigation-case>
</navigation-rule>
<navigation-rule>
   <from-view-id>/createProduct.jsp</from-view-id>
   <navigation-case>
      <from-outcome>success</from-outcome>
      <to-view-id>/uploadImage.jsp</to-view-id>
   </navigation-case>
   <navigation-case>
      <from-outcome>retry</from-outcome>
      <to-view-id>/createProduct.jsp</to-view-id>
   </navigation-case>
   <navigation-case>
      <from-outcome>cancel</from-outcome>
      <to-view-id>/productList.jsp</to-view-id>
   </navigation-case>
</navigation-rule>
Backing bean: ProductBean
不僅包含了頁面中UI元件與資料對映的屬性,也包含三個actionscreateAction,editActiondeleteAction。這是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;
}
在這個action裡面,基於ProductBean的一個Product業務物件被建立。ServiceLocator查詢CatalogService。最後,createProduct的請求被委派給業務邏輯層的CatalogService
Managed-bean declaration: ProductBean
必須在JSF的配置資原始檔faces-managed-bean.xml中配置:

<managed-bean>
   <description>
      Backing bean that contains product information.
   </description>
   <managed-bean-name>productBean</managed-bean-name>
   <managed-bean-class>catalog.view.bean.ProductBean</managed-bean-class>
   <managed-bean-scope>request</managed-bean-scope>   
   <managed-property>
      <property-name>id</property-name>
      <value>#{param.productId}</value>
   </managed-property>
   <managed-property>
      <property-name>serviceLocator</property-name>
      <value>#{serviceLocatorBean}</value>
   </managed-property>
</managed-bean>
ProductBean
有一個請求的範圍,這意味著如果ProductBeanJSP頁面內引用JSF執行為每一個請求建立ProductBean例項的任務。被管理的ID屬性與productId這個請求引數組裝。JSF從請求得到引數,設定managed property
Integration between presentation and business-logic tiers: ServiceLocator
抽象了查詢服務的邏輯。在例子應用程式中,ServiceLocator被定義成一個一個介面。介面被JSF managed bean實現為ServiceLocatorBean,它從Spring application context查詢服務:
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);
ServiceLocator
被定義為BaseBean中的一個屬性。JSF managed bean容易連線ServiceLocator執行必須訪問ServiceLocator的那些managed beans。使用了Inversion of controlIOC,控制反轉)
業務邏輯層
定義業務物件,建立服務介面和實現,在Spring中配置這些物件組成了這一層的任務。
Business objects:
因為Hibernate提供了持久化,ProductCategory業務物件需要為它們包含的所有屬性提供gettersetter方法。
Business services:CatalogService
介面定義了所有與目錄管理有關的服務:

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;
}
CachedCatalogServiceImpl
服務的介面實現,它包含CatalogDao物件的一個setterSpringCachedCatalogServiceImpl CatalogDao連線在一起。因為我們提供了介面,所以對實現的依賴不是很緊密。
Spring configuration:
下面是CatalogServiceSpring comfiguration

<!-- Hibernate Transaction Manager Definition -->
<bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
   <property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>

<!-- Cached Catalog Service Definition -->
<bean id="catalogServiceTarget" class="catalog.model.service.impl.CachedCatalogServiceImpl" init-method="init">
   <property name="catalogDao"><ref local="catalogDao"/></property>
</bean>

<!-- Transactional proxy for the Catalog Service -->
<bean id="catalogService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <property name="transactionManager"><ref local="transactionManager"/></property>
   <property name="target"><ref local="catalogServiceTarget"/></property>
   <property name="transactionAttributes">
      <props>
         <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
       <prop key="save*">PROPAGATION_REQUIRED</prop>
       <prop key="update*">PROPAGATION_REQUIRED</prop>
       <prop key="delete*">PROPAGATION_REQUIRED</prop>
      </props>
   </property>
</bean>
Spring
宣告事務管理是在CatalogService. CatalogService 裡面設定,它能實現不同CatalogDaoSpring建立並管理單體例項Catalogservice,不需要工廠。
現在,業務邏輯層準備好了,讓我們將它與整合層整合。
Integration between Spring and 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
使用HibernateTemplate整合HibernateSpring.下面是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>
整合層
Hibernate
使用一個XML配置檔案去對映業務物件到關係型資料庫。在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
通過Spring使用HibernateTemplate連線:
<!-- Catalog DAO Definition: Hibernate implementation -->
<bean id="catalogDao" class="catalog.model.dao.hibernate.CatalogDaoHibernateImpl">
   <property name="hibernateTemplate"><ref bean="hibernateTemplate"/></property>
</bean>
結論
這篇文章介紹了怎樣將JSF整合到Spring FrameworkHibernate,建立了一個真實的應用程式。這三種技術的聯合提供了一個可靠的Web應用程式開發框架。一個多層體系結構應該做為Web應用程式的高階體系結構。JSF很適合MVC設計模式,能夠被用於實現表示層。Spring框架能被用於業務邏輯層去管理業務物件,提供宣告性事務管理和資源管理。SpringHibernate結合的很好。Hibernate是一個強有力的O/R對映框架,能夠提供整合層的服務。
通過將Web應用程式劃分成不同的層和麵向介面程式設計,每一層的技術可以被取代。例如, 在表示層Struts能取代JSF,在整合層JDO能取代Hibernate。應用程式層之間的整合不是沒有意義的,使用inversion of controlService Locator設計模式能使這個工作容易。JSF提供了其他框架,如Struts所缺少的功能。然而,這不意味著你應該立刻拋棄Struts而開始使用JSF 。無論怎樣,你的專案是否使用JSF作為你的Web框架,取決於你專案的狀態和功能需求以及團隊專家的意見。

 

注:以上內容來自網路,本人不承擔任何連帶責任
文章轉自:(由於是很早前下的資料,所以已經不記得連結在哪了,如果有看到的朋友知道,請發郵件或者留言告訴我下吧,謝謝了) 

相關文章