隨筆 - 6  文章 - 129  trackbacks - 0
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          常用鏈接

          留言簿(14)

          隨筆檔案(6)

          文章分類(467)

          文章檔案(423)

          相冊(cè)

          收藏夾(18)

          JAVA

          搜索

          •  

          積分與排名

          • 積分 - 827222
          • 排名 - 49

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          使用struts+spring+hibernate 組裝web應(yīng)用

            摘要:

            這篇文章將討論怎樣組合幾個(gè)著名的框架去做到松耦合的目的,怎樣建立你的構(gòu)架,怎樣讓你的各個(gè)應(yīng)用層保持一致。富于挑戰(zhàn)的是:組合這些框架使得每一層都以一種松耦合的方式彼此溝通,而與底層的技術(shù)無關(guān)。這篇文章將使用3種流行的開源框架來討論組合框架的策略

            其實(shí),就算用Java建造一個(gè)不是很煩瑣的web應(yīng)用程序,也不是件輕松的事情。當(dāng)為一個(gè)應(yīng)用程序建造一個(gè)構(gòu)架時(shí)有許多事情需要考慮。從高層來說,開發(fā)者需要考慮:怎樣建立用戶接口?在哪里處理業(yè)務(wù)邏輯?和怎樣持久化應(yīng)用數(shù)據(jù)。這三層每一層都有它們各自的問題需要回答。 各個(gè)層次應(yīng)該使用什么技術(shù)?怎樣才能把應(yīng)用程序設(shè)計(jì)得松耦合和能靈活改變?構(gòu)架允許層的替換不會(huì)影響到其它層嗎?應(yīng)用程序怎樣處理容器級(jí)的服務(wù),比如事務(wù)處理?

            當(dāng)為你的web應(yīng)用程序創(chuàng)建一個(gè)構(gòu)架時(shí),需要涉及到相當(dāng)多的問題。幸運(yùn)的是,已經(jīng)有不少開發(fā)者已經(jīng)遇到過這類重復(fù)發(fā)生的問題,并且建立了處理這類問題的框架。一個(gè)好框架具備以下幾點(diǎn): 減輕開發(fā)者處理復(fù)雜的問題的負(fù)擔(dān)(“不重復(fù)發(fā)明輪子”);內(nèi)部定義為可擴(kuò)展的;有一個(gè)強(qiáng)大的用戶群支持??蚣芡ǔD軌蚝芎玫慕鉀Q一方面的問題。然而,你的應(yīng)用程序有幾個(gè)層可能都需要它們各自的框架。就如解決你的用戶接口(UI)問題時(shí)你就不應(yīng)該把事務(wù)邏輯和持久化邏輯摻雜進(jìn)來。例如,你不應(yīng)該在控制器里面寫jdbc代碼,使它包含有業(yè)務(wù)邏輯,這不是控制器應(yīng)該提供的功能。它應(yīng)該是輕量級(jí)的,代理來自用戶接口(UI)外的調(diào)用請(qǐng)求給其它服務(wù)于這些請(qǐng)求的應(yīng)用層。好的框架自然的形成代碼如何分布的指導(dǎo)。更重要的是,框架減輕開發(fā)者從頭開始寫像持久層這樣的代碼的痛苦,使他們專注于對(duì)客戶來說很重要的應(yīng)用邏輯。

            這篇文章將討論怎樣組合幾個(gè)著名的框架去做到松耦合的目的,怎樣建立你的構(gòu)架,怎樣讓你的各個(gè)應(yīng)用層保持一致。富于挑戰(zhàn)的是:組合這些框架使得每一層都以一種松耦合的方式彼此溝通,而與底層的技術(shù)無關(guān)。這篇文章將使用3種流行的開源框架來討論組合框架的策略。表現(xiàn)層我們將使用Struts;業(yè)務(wù)層我們將使用Spring;持久層使用Hibrenate.你也可以在你的應(yīng)用程序中替換這些框架中的任何一種而得到同樣的效果。圖1展示了當(dāng)這些框架組合在一起時(shí)從高層看是什么樣子。

          圖1用Struts, Spring, 和 Hibernate框架構(gòu)建的概覽

            應(yīng)用程序的分層

            大多數(shù)不復(fù)雜的web應(yīng)用都能被分成至少4個(gè)各負(fù)其責(zé)的層次。這些層次是:表現(xiàn)層、持久層、業(yè)務(wù)層、領(lǐng)域模型層。每層在應(yīng)用程序中都有明確的責(zé)任,不應(yīng)該和其它層混淆功能。每一應(yīng)用層應(yīng)該彼此獨(dú)立但要給他們之間放一個(gè)通訊接口。讓我們從審視各個(gè)層開始,討論這些層應(yīng)該提供什么和不應(yīng)該提供什么。

            表現(xiàn)層

            在一個(gè)典型的web應(yīng)用的一端是表現(xiàn)層。很多Java開發(fā)者也理解Struts所提供的。然而,太常見的是,他們把像業(yè)務(wù)邏輯之類的耦合的代碼放進(jìn)了一個(gè)org.apache.struts.Action。所以,讓我們?cè)谙馭truts這樣一個(gè)框架應(yīng)該提供什么上取得一致意見。這兒是Struts負(fù)責(zé)的:

            為用戶管理請(qǐng)求和響應(yīng);
            提供一個(gè)控制器代理調(diào)用業(yè)務(wù)邏輯和其它上層處理;
            處理從其它層擲出給一個(gè)Struts Action的異常;
            為顯示提供一個(gè)模型;
            執(zhí)行用戶接口驗(yàn)證。

            這兒是一些經(jīng)常用Struts編寫的但是卻不應(yīng)該和Struts表現(xiàn)層相伴的項(xiàng)目:
            直接和數(shù)據(jù)庫通訊,比如JDBC調(diào)用;
            業(yè)務(wù)邏輯和與你的應(yīng)用程序相關(guān)的驗(yàn)證;
            事務(wù)管理;
            在表現(xiàn)層中引入這種代碼將導(dǎo)致典型耦合和討厭的維護(hù)。

            持久層

            在典型web應(yīng)用的另一端是持久層。這通常是使事情迅速失控的地方。開發(fā)者低估了構(gòu)建他們自己的持久層框架的挑戰(zhàn)性。一般來說,機(jī)構(gòu)內(nèi)部自己寫的持久層不僅需要大量的開發(fā)時(shí)間,而且還經(jīng)常缺少功能和變得難以控制。有幾個(gè)開源的“對(duì)象-關(guān)系映射”框架非常解決問題。尤其是,Hibernate框架為java提供了"對(duì)象-關(guān)系持久化"機(jī)制和查詢服務(wù)。Hibernate對(duì)那些已經(jīng)熟悉了SQL和JDBC API的Java開發(fā)者有一個(gè)適中的學(xué)習(xí)曲線。Hibernate持久對(duì)象是基于簡(jiǎn)單舊式Java對(duì)象和Java集合。此外,使用Hibernate并不妨礙你正在使用的IDE。下面的列表包含了你該寫在一個(gè)持久層框架里的代碼類型:

            查詢相關(guān)的信息成為對(duì)象。Hibernate通過一種叫作HQL的面向?qū)ο蟮牟樵冋Z言或者使用條件表達(dá)式API來做這個(gè)事情。 HQL非常類似于SQL-- 只是把SQL里的table和columns用Object和它的fields代替。有一些新的專用的HQL語言成分要學(xué);不過,它們?nèi)菀桌斫舛椅臋n做得好。HQL是一種使用來查詢對(duì)象的自然語言,花很小的代價(jià)就能學(xué)習(xí)它。

            保存、更新、刪除儲(chǔ)存在數(shù)據(jù)庫中的信息。

            像Hibernate這樣的高級(jí)“對(duì)象-關(guān)系”映射框架提供對(duì)大多數(shù)主流SQL數(shù)據(jù)庫的支持,它們支持“父/子”關(guān)系、事務(wù)處理、繼承和多態(tài)。

            這兒是一些應(yīng)該在持久層里被避免的項(xiàng)目:

            業(yè)務(wù)邏輯應(yīng)該在你的應(yīng)用的一個(gè)高一些的層次里。持久層里僅僅允許數(shù)據(jù)存取操作。

            你不應(yīng)該把持久層邏輯和你的表現(xiàn)層邏輯攪在一起。避免像JSPs或基于servlet的類這些表現(xiàn)層組件里的邏輯和數(shù)據(jù)存取直接通訊。通過把持久層邏輯隔離進(jìn)它自己的層,應(yīng)用程序變得易于修改而不會(huì)影響在其它層的代碼。例如:Hebernate能夠被其它持久層框架或者API代替而不會(huì)修改在其它任何層的代碼。

            業(yè)務(wù)層

            在一個(gè)典型的web應(yīng)用程序的中間的組件是業(yè)務(wù)層或服務(wù)層。從編碼的視角來看,這個(gè)服務(wù)層是最容易被忽視的一層。不難在用戶接口層或者持久層里找到散布在其中的這種類型的代碼。這不是正確的地方,因?yàn)檫@導(dǎo)致了應(yīng)用程序的緊耦合,這樣一來,隨著時(shí)間推移代碼將很難維護(hù)。幸好,針對(duì)這一問題有好幾種Frameworks存在。在這個(gè)領(lǐng)域兩個(gè)最流行的框架是Spring和PicoContainer,它們叫作微容器,你可以不費(fèi)力不費(fèi)神的把你的對(duì)象連在一起。所有這些框架都工作在一個(gè)簡(jiǎn)單的叫作“依賴注入”(也通稱“控制反轉(zhuǎn)”)的概念上。這篇文章將著眼于Spring的為指定的配置參數(shù)通過bean屬性的setter注入的使用。Spring也提供了一個(gè)構(gòu)建器注入的復(fù)雜形式作為setter注入的一個(gè)替代。對(duì)象們被一個(gè)簡(jiǎn)單的XML文件連在一起,這個(gè)XML文件含有到像事務(wù)管理器、對(duì)象工廠、包含業(yè)務(wù)邏輯的服務(wù)對(duì)象、和數(shù)據(jù)存取對(duì)象這些對(duì)象的引用。

            這篇文章的后面將用例子來把Spring使用這些概念的方法說得更清楚一些。業(yè)務(wù)層應(yīng)該負(fù)責(zé)下面這些事情:

            處理應(yīng)用程序的業(yè)務(wù)邏輯和業(yè)務(wù)驗(yàn)證;
            管理事務(wù);
            預(yù)留和其它層交互的接口;
            管理業(yè)務(wù)層對(duì)象之間的依賴;
            增加在表現(xiàn)層和持久層之間的靈活性,使它們互不直接通訊;
            從表現(xiàn)層中提供一個(gè)上下文給業(yè)務(wù)層獲得業(yè)務(wù)服務(wù);
            管理從業(yè)務(wù)邏輯到持久層的實(shí)現(xiàn)。

            領(lǐng)域模型層

            最后,因?yàn)槲覀冇懻摰氖且粋€(gè)不是很復(fù)雜的、基于web的應(yīng)用程序,我們需要一組能在不同的層之間移動(dòng)的對(duì)象。領(lǐng)域?qū)ο髮佑赡切┐憩F(xiàn)實(shí)世界中的業(yè)務(wù)對(duì)象的對(duì)象們組成,比如:一份訂單、訂單項(xiàng)、產(chǎn)品等等。這個(gè)層讓開發(fā)者停止建立和維護(hù)不必要的數(shù)據(jù)傳輸對(duì)象(或者叫作DTOs),來匹配他們的領(lǐng)域?qū)ο蟆@?,Hibernate允許你把數(shù)據(jù)庫信息讀進(jìn)領(lǐng)域?qū)ο蟮囊粋€(gè)對(duì)象圖,這樣你可以在連接斷開的情況下把這些數(shù)據(jù)顯示到UI層。那些對(duì)象也能被更新和送回到持久層并在數(shù)據(jù)庫里更新。而且,你不必把對(duì)象轉(zhuǎn)化成DTOs,因?yàn)镈TOs在不同的應(yīng)用層間移動(dòng),可能在轉(zhuǎn)換中丟失。這個(gè)模型使得Java開發(fā)者自然地以一種面向?qū)ο蟮娘L(fēng)格和對(duì)象打交道,沒有附加的編碼。

            結(jié)合一個(gè)簡(jiǎn)單的例子

            既然我們已經(jīng)從一個(gè)高的層次上理解了這些組件, 現(xiàn)在就讓我們開始實(shí)踐吧。在這個(gè)例子中,我們還是將合并Struts、Spring、Hibernate框架。每一個(gè)這些框架在一篇文章中都有太多的細(xì)節(jié)覆蓋到。這篇文章將用一個(gè)簡(jiǎn)單的例子代碼展示怎樣把它們結(jié)合在一起,而不是進(jìn)入每個(gè)框架的許多細(xì)節(jié)。示例應(yīng)用程序?qū)⑹痉兑粋€(gè)請(qǐng)求怎樣跨越每一層被服務(wù)的。這個(gè)示例應(yīng)用程序的一個(gè)用戶能保存一個(gè)訂單到數(shù)據(jù)庫中和查看一個(gè)在數(shù)據(jù)庫中存在的訂單。進(jìn)一步的增強(qiáng)可以使用戶更新或刪除一個(gè)存在的訂單。

            因?yàn)轭I(lǐng)域?qū)ο髮⒑兔恳粚咏换?,我們將首先?chuàng)建它們。這些對(duì)象將使我們定義什么應(yīng)該被持久化,什么業(yè)務(wù)邏輯應(yīng)該被提供,和哪種表現(xiàn)接口應(yīng)該被設(shè)計(jì)。然后,我們將配置持久層和用Hibernate為我們的領(lǐng)域?qū)ο蠖x“對(duì)象-關(guān)系”映射。然后,我們將定義和配置我們的業(yè)務(wù)對(duì)象。在有了這些組件后,我們就能討論用Spring把這些層連在一起。最后,我們將提供一個(gè)表現(xiàn)層,它知道怎樣和業(yè)務(wù)服務(wù)層交流和知道怎樣處理從其它層產(chǎn)生的異常。

            領(lǐng)域?qū)ο髮?/strong>

            因?yàn)檫@些對(duì)象將和所有層交互,這也許是一個(gè)開始編碼的好地方。這個(gè)簡(jiǎn)單的領(lǐng)域模型將包括一個(gè)代表一份訂單的對(duì)象和一個(gè)代表一個(gè)訂單項(xiàng)的對(duì)象。訂單對(duì)象將和一組訂單項(xiàng)對(duì)象有一對(duì)多的關(guān)系。例子代碼在領(lǐng)域?qū)佑袃蓚€(gè)簡(jiǎn)單的對(duì)象:

            com.meagle.bo.Order.java: 包括一份訂單的概要信息;
            com.meagle.bo.OrderLineItem.java: 包括一份訂單的詳細(xì)信息;

            考慮一下為你的對(duì)象選擇包名,它將反映你的應(yīng)用程序是怎樣分層的。例如:簡(jiǎn)單應(yīng)用的領(lǐng)域?qū)ο罂梢苑胚M(jìn)com.meagle.bo包。更多專門的領(lǐng)域?qū)ο髮⒎湃朐赾om.meagle.bo下面的子包里。業(yè)務(wù)邏輯在com.meagle.service包里開始打包,DAO對(duì)象放進(jìn)com.meagle.service.dao.hibernate包。對(duì)于forms和actions的表現(xiàn)類分別放入com.meagle.action 和 com.meagle.forms包。準(zhǔn)確的包命名為你的類提供的功能提供一個(gè)清楚的區(qū)分,使當(dāng)故障維護(hù)時(shí)更易于維護(hù),和當(dāng)給應(yīng)用程序增加新的類或包時(shí)提供一致性。

            持久層配置

            用Hibernate設(shè)置持久層涉及到幾個(gè)步驟。第一步是進(jìn)行配置持久化我們的領(lǐng)域業(yè)務(wù)對(duì)象。因?yàn)槲覀冇糜陬I(lǐng)域?qū)ο蟪志没腍ibernate和POJOs一起工作,因此,訂單和訂單項(xiàng)對(duì)象包括的所有的字段的都需要提供getter和setter方法。訂單對(duì)象將包括像ID、用戶名、合計(jì)、和訂單項(xiàng)這樣一些字段的標(biāo)準(zhǔn)的JavaBean格式的setter和getter方法。訂單項(xiàng)對(duì)象將同樣的用JavaBean的格式為它的字段設(shè)置setter和getter方法。

            Hibernate在XML文件里映射領(lǐng)域?qū)ο蟮疥P(guān)系數(shù)據(jù)庫。訂單和訂單項(xiàng)對(duì)象將有兩個(gè)映射文件來表達(dá)這種映射。有像XDoclet這樣的工具來幫助這種映射。Hibernate將映射領(lǐng)域?qū)ο蟮竭@些文件:

            Order.hbm.xml
            OrderLineItem.hbm.xml

            你可以在WebContent/WEB-INF/classes/com/meagle/bo目錄里找到這些生成的文件。配置Hibernate SessionFactory使它知道是在和哪個(gè)數(shù)據(jù)庫通信,使用哪個(gè)數(shù)據(jù)源或連接池,加載哪些持久對(duì)象。SessionFactory提供的Session對(duì)象是Java對(duì)象和像選取、保存、更新、刪除對(duì)象這樣一些持久化功能間的翻譯接口。我們將在后面的部分討論Hibernate操作Session對(duì)象需要的SessionFactory配置。

            業(yè)務(wù)層配置

            既然我們已經(jīng)有了領(lǐng)域?qū)ο?,我們需要有業(yè)務(wù)服務(wù)對(duì)象來執(zhí)行應(yīng)用邏輯、執(zhí)行向持久層的調(diào)用、獲得從用戶接口層的請(qǐng)求、處理事務(wù)、處理異常。為了將所有這些連接起來并且易于管理,我們將使用Spring框架的bean管理方面。Spring使用“控制反轉(zhuǎn)”,或者“setter依賴注入”來把這些對(duì)象連好,這些對(duì)象在一個(gè)外部的XML文件中被引用。“控制反轉(zhuǎn)”是一個(gè)簡(jiǎn)單的概念,它允許對(duì)象接受其它的在一個(gè)高一些的層次被創(chuàng)建的對(duì)象。使用這種方法,你的對(duì)象從必須創(chuàng)建其它對(duì)象中解放出來并降低對(duì)象耦合。

            這兒是個(gè)不使用IoC的對(duì)象創(chuàng)建它的從屬對(duì)象的例子,這導(dǎo)致緊的對(duì)象耦合:

            圖2:沒有使用IoC的對(duì)象組織。對(duì)象A創(chuàng)建對(duì)象B和C。

            這兒是一個(gè)使用IoC的例子,它允許對(duì)象在一個(gè)高一些層次被創(chuàng)建和傳進(jìn)另外的對(duì)象,所以另外的對(duì)象能直接使用現(xiàn)成的對(duì)象·[譯者注:另外的對(duì)象不必再親自創(chuàng)建這些要使用的對(duì)象]:


          圖3:對(duì)象使用IoC組織。對(duì)象A包含setter方法,它們接受到對(duì)象B和C的接口。這也可以用對(duì)象A里的接受對(duì)象B和C的構(gòu)建器完成。

            建立我們的業(yè)務(wù)服務(wù)對(duì)象

            我們將在我們的業(yè)務(wù)對(duì)象中使用的setter方法接受的是接口,這些接口允許對(duì)象的松散定義的實(shí)現(xiàn),這些對(duì)象將被設(shè)置或者注入。在我們這個(gè)例子里我們將使我們的業(yè)務(wù)服務(wù)對(duì)象接受一個(gè)DAO去控制我們的領(lǐng)域?qū)ο蟮某志没?。?dāng)我們?cè)谶@篇文章的例子中使用Hibernate,我們可以容易的轉(zhuǎn)換到一個(gè)不同的持久框架的實(shí)現(xiàn),通知Spring使用新的實(shí)現(xiàn)的DAO對(duì)象。你能明白編程到接口和使用“依賴注入”模式是怎樣寬松耦合你的業(yè)務(wù)邏輯和你的持久化機(jī)制的。

            這兒是業(yè)務(wù)服務(wù)對(duì)象的接口,它是一個(gè)DAO對(duì)象依賴的樁。

          public interface IOrderService {
           public abstract Order saveNewOrder(Order order)
            throws OrderException,
                OrderMinimumAmountException;
           public abstract List findOrderByUser(
                             String user)
                        throws OrderException;
           public abstract Order findOrderById(int id)
                        throws OrderException;
           public abstract void setOrderDAO(
                         IOrderDAO orderDAO);
          }

            注意上面的代碼有一個(gè)為DAO對(duì)象準(zhǔn)備的setter方法。這兒沒有一個(gè)getOrderDAO方法因?yàn)樗皇潜匾?,因?yàn)椴惶袕耐饷嬖L問連著的OrderDAO對(duì)象的需要。DAO對(duì)象將被用來和我們的持久層溝通。我們將用Spring把業(yè)務(wù)服務(wù)對(duì)象和DAO對(duì)象連在一起。因?yàn)槲覀兙幋a到接口,我們不會(huì)緊耦合實(shí)現(xiàn)。

            下一步是寫我們的DAO實(shí)現(xiàn)對(duì)象。因?yàn)镾pring有內(nèi)建的對(duì)Hibernate的支持,這個(gè)例子DAO將繼承HibernateDaoSupport類,這使得我們?nèi)菀兹〉靡粋€(gè)到HibernateTemplate類的引用,HibernateTemplate是一個(gè)幫助類,它能簡(jiǎn)化Hibernate Session的編碼和處理HibernateExceptions。這兒是DAO的接口:
          public interface IOrderDAO {
           public abstract Order findOrderById(
                            final int id);
           public abstract List findOrdersPlaceByUser(
                        final String placedBy);
           public abstract Order saveOrder(
                          final Order order);
          }


            我們還有兩個(gè)對(duì)象要和我們的業(yè)務(wù)層連在一起。這包括HibernateSessionFactory和一個(gè)TransactionManager對(duì)象。這在Spring配置文件里直接完成。Spring提供一個(gè)HibernateTransactionManager,它將從工廠綁定一個(gè)Hibernate Session到一個(gè)線程來支持事務(wù)。這兒是HibernateSessionFactory和HibernateTransactionManager的Spring配置。
          <bean id="mySessionFactory"
              class="org.springframework.orm.hibernate.
                 LocalSessionFactoryBean">
           <property name="mappingResources">
            <list>
             <value>
              com/meagle/bo/Order.hbm.xml
             </value>
             <value>
              com/meagle/bo/OrderLineItem.hbm.xml
             </value>
            </list>
           </property>
           <property name="hibernateProperties">
            <props>
             <prop key="hibernate.dialect">
              net.sf.hibernate.dialect.MySQLDialect
             </prop>
             <prop key="hibernate.show_sql">
              false
             </prop>
             <prop key="hibernate.proxool.xml">
              C:/MyWebApps/.../WEB-INF/proxool.xml
             </prop>
             <prop key="hibernate.proxool.pool_alias">
               spring
             </prop>
            </props>
           </property>
          </bean>
          <!-- Transaction manager for a single Hibernate
          SessionFactory (alternative to JTA) -->
          <bean id="myTransactionManager"
               class="org.
                   springframework.
                  orm.
                  hibernate.
                  HibernateTransactionManager">
           <property name="sessionFactory">
            <ref local="mySessionFactory"/>
           </property>
           </bean>

            每一個(gè)對(duì)象能被Spring配置里的一個(gè)<bean>標(biāo)記引用。在這個(gè)例子里,bean “mySessionFactory”代表一個(gè)HibernateSessionFactory,bean “myTransactionManager”代表一個(gè)Hibernate transaction manager。注意transactionManger bean有一個(gè)叫作sessionFactory的屬性元素。HibernateTransactionManager有一個(gè)為sessionFactory準(zhǔn)備的setter和getter方法,它們是用來當(dāng)Spring容器啟動(dòng)時(shí)的依賴注入。sessionFactory屬性引用mySessionFactory bean。這兩個(gè)對(duì)象現(xiàn)在當(dāng)Spring容器初始化時(shí)將被連在一起。這種連接把你從為引用和創(chuàng)建這些對(duì)象而創(chuàng)建singleton對(duì)象和工廠中解放出來,這減少了你應(yīng)用程序中的代碼維護(hù)。mySessionFactory bean有兩個(gè)屬性元素,它們翻譯成為mappingResources 和 hibernatePropertes準(zhǔn)備的setter方法。通常,如果你在Spring之外使用Hibernate,這個(gè)配置將被保存在hibernate.cfg.xml文件中。不管怎樣,Spring提供了一個(gè)便捷的方式--在Spring配置文件中合并Hibernate的配置。

            既然我們已經(jīng)配置了我們的容器服務(wù)beans和把它們連在了一起,我們需要把我們的業(yè)務(wù)服務(wù)對(duì)象和我們的DAO對(duì)象連在一起。然后,我們需要把這些對(duì)象連接到事務(wù)管理器。

            這是在Spring配置文件里的樣子:

          <!-- ORDER SERVICE -->
          <bean id="orderService"
           class="org.
               springframework.
               transaction.
               interceptor.
               TransactionProxyFactoryBean">
           <property name="transactionManager">
            <ref local="myTransactionManager"/>
           </property>
           <property name="target">
            <ref local="orderTarget"/>
           </property>
           <property name="transactionAttributes">
            <props>
             <prop key="find*">
            PROPAGATION_REQUIRED,readOnly,-OrderException
             </prop>
             <prop key="save*">
            PROPAGATION_REQUIRED,-OrderException
             </prop>
            </props>
           </property>
          </bean>
          <!-- ORDER TARGET PRIMARY BUSINESS OBJECT:
          Hibernate implementation -->
          <bean id="orderTarget"
               class="com.
                  meagle.
                  service.
                  spring.
                  OrderServiceSpringImpl">
           <property name="orderDAO">
            <ref local="orderDAO"/>
           </property>
          </bean>
          <!-- ORDER DAO OBJECT -->
          <bean id="orderDAO"
               class="com.
                  meagle.
                  service.
                  dao.
                  hibernate.
                  OrderHibernateDAO">
           <property name="sessionFactory">
            <ref local="mySessionFactory"/>
           </property>
          </bean>


            圖4是我們已經(jīng)連在一起的東西的一個(gè)概覽。它展示了每個(gè)對(duì)象是怎樣相關(guān)聯(lián)的和怎樣被Spring設(shè)置進(jìn)其它對(duì)象中。把這幅圖和示例應(yīng)用中的Spring配置文件對(duì)比查看它們之間的關(guān)系。

          圖4:這是Spring怎樣將在這個(gè)配置的基礎(chǔ)上裝配beans。

            這個(gè)例子使用一個(gè)TransactionProxyFactoryBean,它有一個(gè)為我們已經(jīng)定義了的事務(wù)管理者準(zhǔn)備的setter方法。這是一個(gè)有用的對(duì)象,它知道怎樣處理聲明的事務(wù)操作和你的服務(wù)對(duì)象。你可以通過transactionAttributes屬性定義事務(wù)怎樣被處理,transactionAttributes屬性為方法名定義模式和它們?cè)鯓訁⑴c進(jìn)一個(gè)事務(wù)。

            TransactionProxyFactoryBean類也有一個(gè)為一個(gè)target準(zhǔn)備的setter,target將是一個(gè)到我們的叫作orderTarget的業(yè)務(wù)服務(wù)對(duì)象的引用。 orderTarget bean定義使用哪個(gè)業(yè)務(wù)服務(wù)對(duì)象并有一個(gè)指向setOrderDAO()的屬性。orderDAO bean將居于這個(gè)屬性中,orderDAO bean是我們的和持久層交流的DAO對(duì)象。

            還有一個(gè)關(guān)于Spring和bean要注意的是bean能以兩種模式工作。這兩種模式被定義為singleton和prototype。一個(gè)bean默認(rèn)的模式是singleton,意味著一個(gè)共享的bean的實(shí)例將被管理。這是用于無狀態(tài)操作--像一個(gè)無狀態(tài)會(huì)話bean將提供的那樣。當(dāng)bean由Spring提供時(shí),prototype模式允許創(chuàng)建bean的新實(shí)例。你應(yīng)當(dāng)只有在每一個(gè)用戶都需要他們自己的bean的拷貝時(shí)才使用prototype模式。

            提供一個(gè)服務(wù)定位器

            既然我們已經(jīng)把我們的服務(wù)和我們的DAO連起來了,我們需要把我們的服務(wù)暴露給其它層。通常是一個(gè)像使用Struts或Swing這樣的用戶接口層里的代碼來使用這個(gè)服務(wù)。一個(gè)簡(jiǎn)單的處理方法是使用一個(gè)服務(wù)定位器模式的類從一個(gè)Spring上下文中返回資源。這也可以靠引用bean ID通過Spring來直接完成。

            這兒是一個(gè)在Struts Action中怎樣配置一個(gè)服務(wù)定位器的例子:

          public abstract class BaseAction extends Action {
           private IOrderService orderService;
           public void setServlet(ActionServlet
                           actionServlet) {
            super.setServlet(actionServlet);
            ServletContext servletContext =
                  actionServlet.getServletContext();
            WebApplicationContext wac =
             WebApplicationContextUtils.
               getRequiredWebApplicationContext(
                           servletContext);
             this.orderService = (IOrderService)
                     wac.getBean("orderService");
           }
           protected IOrderService getOrderService() {
            return orderService;
           }
          }

            用戶接口層配置

            示例應(yīng)用的用戶接口層使用Struts框架。這兒我們將討論當(dāng)為一個(gè)應(yīng)用分層時(shí)和Struts相關(guān)的部分。讓我們從在struts-config.xml文件里檢查一個(gè)Action配置開始。

          <action path="/SaveNewOrder"
            type="com.meagle.action.SaveOrderAction"
            name="OrderForm"
            scope="request"
            validate="true"
            input="/NewOrder.jsp">
           <display-name>Save New Order</display-name>
           <exception key="error.order.save"
            path="/NewOrder.jsp"
            scope="request"
            type="com.meagle.exception.OrderException"/>
           <exception key="error.order.not.enough.money"
            path="/NewOrder.jsp"
            scope="request"
            type="com.
            meagle.
            exception.
            OrderMinimumAmountException"/>
           <forward name="success" path="/ViewOrder.jsp"/>
           <forward name="failure" path="/NewOrder.jsp"/>
          </action>

            SaveNewOrder Action被用來持久化一個(gè)用戶從用戶接口層提交的訂單。這是一個(gè)典型的Struts Action;然而,注意這個(gè)action的異常配置。這些Exceptions為我們的業(yè)務(wù)服務(wù)對(duì)象也在Spring 配置文件中配置了。當(dāng)這些異常被從業(yè)務(wù)層擲出我們能在我們的用戶接口里恰當(dāng)?shù)奶幚硭鼈儭5谝粋€(gè)異常,OrderException,當(dāng)在持久層里保存訂單對(duì)象失敗時(shí)將被這個(gè)action使用。這將引起事務(wù)回滾和通過業(yè)務(wù)對(duì)象傳遞把異常傳回給Struts層。OrderMinimumAmountException,在業(yè)務(wù)對(duì)象邏輯里的一個(gè)事務(wù)因?yàn)樘峤坏挠唵芜_(dá)不到最小訂單數(shù)量而失敗也將被處理。然后,事務(wù)將回滾和這個(gè)異常能被用戶接口層恰當(dāng)?shù)奶幚怼?

            最后一個(gè)連接步驟是使我們的表現(xiàn)層和我們的業(yè)務(wù)層交互。這已經(jīng)通過使用前面討論的服務(wù)定位器來完成了。服務(wù)層充當(dāng)一個(gè)到我們的業(yè)務(wù)邏輯和持久層的接口。這兒是 Struts中的SaveNewOrder Action可能怎樣使用一個(gè)服務(wù)定位器調(diào)用一個(gè)業(yè)務(wù)方法:
          public ActionForward execute(
           ActionMapping mapping,
           ActionForm form,
           javax.servlet.http.HttpServletRequest request,
           javax.servlet.http.HttpServletResponse response)
           throws java.lang.Exception {
           OrderForm oForm = (OrderForm)form;
           // Use the form to build an Order object that
           // can be saved in the persistence layer.
           // See the full source code in the sample app.
           // Obtain the wired business service object
           // from the service locator configuration
           // in BaseAction.
           // Delegate the save to the service layer and
           // further upstream to save the Order object.
           getOrderService().saveNewOrder(order);
           oForm.setOrder(order);
           ActionMessages messages = new ActionMessages();
           messages.add(
             ActionMessages.GLOBAL_MESSAGE,
          new ActionMessage(
             "message.order.saved.successfully"));
           saveMessages(request, messages);
           return mapping.findForward("success");
          }

            結(jié)論

            這篇文章按照技術(shù)和架構(gòu)覆蓋了許多話題。從中而取出的主要思想是怎樣更好的給你的應(yīng)用程序分層:用戶接口層、持久邏輯層、和其它任何你需要的應(yīng)用層。這樣可以解耦你的代碼,允許添加新的代碼組件,使你的應(yīng)用在將來更易維護(hù)。這里覆蓋的技術(shù)能很好的解決這類的問題。不管怎樣,使用這樣的構(gòu)架可以讓你用其他技術(shù)代替現(xiàn)在的層。例如,你也許不想使用Hibernate持久化。因?yàn)槟阍谀愕腄AO對(duì)象中編碼到接口,你能怎樣使用其它的技術(shù)或框架,比如 iBATIS,作為一個(gè)替代是顯而易見的?;蛘吣憧赡苡貌煌赟truts的框架替代你的UI層。改變UI層的實(shí)現(xiàn)不會(huì)直接影響你的業(yè)務(wù)邏輯層或者你的持久層。替換你的持久層不會(huì)影響你的UI邏輯或業(yè)務(wù)服務(wù)層。集成一個(gè)web應(yīng)用其實(shí)也不是一件煩瑣的工作,靠解耦你的各應(yīng)用層和用適當(dāng)?shù)目蚣芙M成它,它能變得更容易處理。

          二、比較

          http://qxndl.blog.sohu.com/905950.html

          struts+spring+hibernate之間的關(guān)系與差別

          Struts:用來作VC部分,即控制和顯示作用; Spring:用來作數(shù)據(jù)庫操作的事務(wù)處理,在配置文件里配置好就OK了; Hibernate:用來作DAO處理,在此用了Spring的getHibernateTemplate()方法來操作hsql進(jìn)行數(shù)據(jù)增刪改等操作。


          Struts:用來作VC部分,即控制和顯示作用;
          Spring:用來作數(shù)據(jù)庫操作的事務(wù)處理,在配置文件里配置好就OK了;
          Hibernate:用來作DAO處理,在此用了Spring的getHibernateTemplate()方法來操作hsql進(jìn)行數(shù)據(jù)增刪改等操作。


          1,先說說你的表示層
          其實(shí)沒有必要使用struts,除非你有歷史遺留問題不得不用struts,因?yàn)閟pring的mvc已經(jīng)足夠好了:
          a.清晰的模型對(duì)象傳遞,這個(gè)模型對(duì)象可以是任何java對(duì)象,如果你不在意在各層之間傳遞同一個(gè)對(duì)象的話,這個(gè)模型對(duì)象就可以是hibernate的persistent object,通過open session in view,你可以以一致的方式使用業(yè)務(wù)模型對(duì)象。
          b.reference data,讓你清晰的處理look up數(shù)據(jù)。
          c. 多種可供選擇的視圖解析類型,可以在prpperties文件中定義page的邏輯名,或者定義在xml文件里的struts tiles邏輯名。
          d.無干擾的數(shù)據(jù)綁定,一個(gè)<spring:bind>可以對(duì)模型對(duì)象和form進(jìn)行綁定,就像struts自動(dòng)填充formbean一樣,但spring 的綁定功能不會(huì)干擾界面布局,也就是說,你仍然可以使用html編輯器對(duì)頁面進(jìn)行處理。
          e.客戶端驗(yàn)證。
          f.服務(wù)器端驗(yàn)證。
          g.多種可供選擇的控制器,其中支持表單的控制器提供了類似vb中表單事件處理的功能,這是一系列的workflow,在你認(rèn)為合適的地方,插入你的處理代碼。

          spring mvc與struts比較,可能只是少了很多taglib和頁面布局,但這都可以通過第三方工具補(bǔ)充,因?yàn)橐晥D相比于其他部分,畢竟更輕量級(jí)一些??梢赃x擇的第三方工具可以是:displaytag,struts-menu,struts tiles,等等。

          2,在說說業(yè)務(wù)邏輯部分
          業(yè)務(wù)邏輯類可以用spring的beans進(jìn)行配置,并由spring管理與表現(xiàn)層的控制器及更下層的DAO對(duì)象的關(guān)系。另外,還可以進(jìn)行配置性的事務(wù)處理,一個(gè)interceptor配置,免去了你的所有煩惱。

          3,dao層
          用spring 封裝后的hibernate API,讓Hibernate繼續(xù)瘦身,并且通過spring建立與上層的關(guān)系。

          4,最后,說說hibernate的po
          你可以選擇你喜歡的任何方式進(jìn)行建模,以下工具提供了足夠的支持:
          a. 從java對(duì)象到hbm文件:xdoclet
          b. 從hbm文件到j(luò)ava對(duì)象:hibernate extension
          c. 從數(shù)據(jù)庫到hbm文件:middlegen
          d. 從hbm文件到數(shù)據(jù)庫:SchemaExport

          至于可供參考的項(xiàng)目,可以看看spring的例子petclinic(spring+hibernate),還有一個(gè)不可不看的網(wǎng)站:http://raibledesigns.com/wiki/Wiki.jsp?page=AppFuse(struts+spring+hibernate或spring mvc + spring +hibernate)。另外,spring帶的mvc step-by-step是一個(gè)很好的入門教程。

          需要說明的是,spring僅僅為我們提供了一種設(shè)計(jì)和實(shí)現(xiàn)框架的方式,因此,項(xiàng)目的成功與否,是與我們的構(gòu)架設(shè)計(jì)緊密相關(guān)的,在有了好的設(shè)計(jì)思想以后,善用spring,會(huì)讓我們的成功來的更容易。
          a

          三、整合

           

           Struts+Spring+Hibernate 的示例(一)
          先說說《Wiring Your Web Application with Open Source Java by Mark Eagle》這個(gè)示例,網(wǎng)上有這個(gè)的中英文文章。在后續(xù)的說明中我會(huì)將文章的部分內(nèi)容引用進(jìn)來。我使用的開發(fā)工具是 Eclipse3.1 + MyEclipse4.0M2。
          針對(duì)一個(gè)簡(jiǎn)單或者復(fù)雜的 Web 應(yīng)用程序,我們需要考慮諸如是怎樣建立用戶接口?在哪里處理業(yè)務(wù)邏輯?怎樣持久化的數(shù)據(jù)?而針對(duì)這三個(gè)層次,每個(gè)層次我們都要仔細(xì)考慮:各個(gè)層該使用什么技術(shù)? 怎樣的設(shè)計(jì)能松散耦合還能靈活改變? 怎樣替換某個(gè)層而不影響整體構(gòu)架?應(yīng)用程序如何做各種級(jí)別的業(yè)務(wù)處理(比如事務(wù)處理)?等等。
          對(duì)于這個(gè)示例我們采用當(dāng)前流行的三種框架來做到 Web 應(yīng)用程序的松散耦合:表示層我們用 Struts;業(yè)務(wù)層我們用 Spring;而持久層則用 Hibernate。
          Struts 負(fù)責(zé)管理用戶的請(qǐng)求,做出響應(yīng);提供控制器,委派調(diào)用業(yè)務(wù)邏輯;處理異常;UI 驗(yàn)證等。
          Spring 負(fù)責(zé)處理應(yīng)用程序的業(yè)務(wù)邏輯和業(yè)務(wù)校驗(yàn);管理事務(wù);提供與其它層相互作用的接口;管理業(yè)務(wù)層級(jí)別的對(duì)象的依賴等。
          Hibernate 負(fù)責(zé)存儲(chǔ)、更新、刪除數(shù)據(jù)庫記錄等。
          這篇文章舉例說明如何使用這三個(gè)框架整合開發(fā),并揭示一個(gè)請(qǐng)求是如何貫穿于各個(gè)層的。(從用戶的加入一個(gè)Order到數(shù)據(jù)庫,顯示;進(jìn)而更新、刪除)。 
          1. 首先創(chuàng)建一組對(duì)象,這些對(duì)象有的需要持久化,有的提供業(yè)務(wù)邏輯,有的是顯示接口的設(shè)計(jì)。Hibernate 允許你將數(shù)據(jù)庫中的信息存放入對(duì)象,可以在連接斷開的情況下把這些數(shù)據(jù)顯示到UI層。而那些對(duì)象也可以返回給持續(xù)層,從而在數(shù)據(jù)庫里更新。
          使用 myeclipse 的 Web  Project 新建一個(gè)項(xiàng)目 SSHTest:
          創(chuàng)建 Order 類:
          利用 eclipse 生成 Getters 和 Setters。
          同樣創(chuàng)建 OrderLineItem 類。
          com.ivan.ssh.bo.Order 包含一個(gè)訂單的主要信息:訂單號(hào),訂單總價(jià),訂單客戶名。
          com.ivan.ssh.bo.OrderLineItem 包含訂單的詳細(xì)信息:訂單單項(xiàng)號(hào),單價(jià),描述。一個(gè)訂單對(duì)應(yīng)于多個(gè)訂單項(xiàng)。
          Order 與 OrderLineItem 的關(guān)系是一對(duì)多的關(guān)系,這里為它們建立雙向一對(duì)多的關(guān)系。
          在類中我們需要分別為 Order 和 OrderLineItem 添加屬性 orderLineItems(java.util.Set 類型) 和 order(Order 類型)及其 getter 和 setter 方法。
          2. 配置持久層,Hibernate 通過 XML 文件來映射 (OR) 對(duì)象,以下兩個(gè) xml 文件分別映射了Order 和 OrderItem 對(duì)象。
          Order.hbm.xml:
          <?xml version="1.0"?>
          <!DOCTYPE hibernate-mapping PUBLIC
           "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
           "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
          <hibernate-mapping>
              <class
                  name="com.meagle.bo.Order"
                  table="Orders"
                  dynamic-update="false"
                  dynamic-insert="false">
                  <id
                      name="id"
                      column="Order_ID"
                      type="int"
                      unsaved-value="0">
                      <generator class="native">
                      </generator>
                  </id>
                  <set
                      name="orderLineItems"
                      table="OrderLineItem"
                      lazy="true"
                      inverse="true"
                      cascade="save-update"
                      sort="unsorted">
                        <key column="Order_ID"/>
                        <one-to-many class="com.meagle.bo.OrderLineItem"/>
                  </set>
                  <property
                      name="userName"
                      type="string"
                      update="true"
                      insert="true"
                      column="UserName"
                      not-null="true"
                      unique="false"/>
                  <property
                      name="total"
                      type="double"
                      update="true"
                      insert="true"
                      column="Total"
                      not-null="false"
                      unique="false"/>
              </class>
          </hibernate-mapping>
          OrderLineItem.hbm.xml:
          <?xml version="1.0"?>
          <!DOCTYPE hibernate-mapping PUBLIC
           "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
           "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
          <hibernate-mapping>
              <class
                  name="com.meagle.bo.OrderLineItem"
                  table="OrderLineItem"
                  dynamic-update="false"
                  dynamic-insert="false">
                  <id
                      name="id"
                      column="OrderLineItem_ID"
                      type="int"
                      unsaved-value="0">
                      <generator class="native">
                      </generator>
                  </id>
                  <many-to-one
                      name="order"
                      class="com.meagle.bo.Order"
                      cascade="none"
                      outer-join="auto"
                      update="true"
                      insert="true"
                      column="Order_ID"/>
                  <property
                      name="description"
                      type="string"
                      update="true"
                      insert="true"
                      column="Description"
                      not-null="false"
                      unique="false"/>
                  <property
                      name="lineItemPrice"
                      type="double"
                      update="true"
                      insert="true"
                      column="LineItemPrice"
                      not-null="false"
                      unique="false"/>
              </class>
          </hibernate-mapping>
          稍后我們介紹怎樣配置 SessionFactory 和 Session,前者說明與哪個(gè)數(shù)據(jù)庫通信,使用哪個(gè)連接池或使用了 DataSource,加載哪些持久對(duì)象,后者用來完成查找、保存、刪除和更新這些操作。
          3. 配置業(yè)務(wù)層,這里要?jiǎng)?chuàng)建業(yè)務(wù)服務(wù)對(duì)象(Business Service Object),用他們來執(zhí)行程序的邏輯,調(diào)用持久層,得到 UI 層的 requests,處理 transactions,并且控制 exceptions。為了將這些連接起來并且易于管理,我們將使用面向方面的 SpringFramework。Spring 提供了控制倒置(Inversion of Control)和注射依賴設(shè)置(Setter Dependency Injection) 這些方式(可供選擇),用 XML 文件將對(duì)象連接起來。IoC 是一個(gè)簡(jiǎn)單概念(它允許一個(gè)對(duì)象在上層接受其他對(duì)象的創(chuàng)建),用 IoC 這種方式讓你的對(duì)象從創(chuàng)建中釋放了出來,降低了偶合度。
          我們將用一個(gè) business service object 接收一個(gè) DAO,用它來控制 domain objects 的持久化。 由于在這個(gè)例子中使用了 Hibernate,我們可以很方便的用其他持久框架實(shí)現(xiàn)同時(shí)通知 Spring 有新的 DAO 可以使用了。在面向接口的編程中,你會(huì)明白 “注射依賴”模式是怎樣松散耦合你的業(yè)務(wù)邏輯和持久機(jī)制的。
          public interface IOrderService {
            public abstract Order saveNewOrder(Order order)
               throws OrderException, OrderMinimumAmountException;
            public abstract List findOrderByUser(String user) throws OrderException;
            public abstract Order findOrderById(int id) throws OrderException;
            public abstract void setOrderDAO(IOrderDAO orderDAO);
          }
          注意到這段代碼里有一個(gè) setOrderDao(),它就是一個(gè)DAO Object設(shè)置方法(注射器)。
          其實(shí)現(xiàn)類:
          public class OrderServiceSpringImpl implements IOrderService {
           private static final double ORDER_MINIMUM = 100.0;
           private IOrderDAO orderDAO;
           public Order saveNewOrder(Order order)
            throws OrderException, OrderMinimumAmountException {
            // do some business logic
            if (order != null && order.getTotal() == 0) {
             double total = 0.0;
             Set items = order.getOrderLineItems();
             Iterator iter = items.iterator();
             while (iter.hasNext()) {
              OrderLineItem item = (OrderLineItem) iter.next();
              total += item.getLineItemPrice();
             }
             if (total < OrderServiceSpringImpl.ORDER_MINIMUM) {
              throw new OrderMinimumAmountException("Order did not exceed the order minimum");
             } else {
              order.setTotal(total);
             }
            }
            Order savedOrder = null;
            try {
             savedOrder = getOrderDAO().saveOrder(order);
            } catch (RuntimeException e) {
             throw new OrderException("Could not save order " + e.toString());
            }
            return savedOrder;
           }
           public List findOrderByUser(String user) throws OrderException {
            List orders = null;
            try {
             orders = getOrderDAO().findOrdersPlaceByUser(user);
            } catch (RuntimeException e) {
             // should really use a logger instead of System.out
             System.out.println(
              "Could not locate order by user " + e.getMessage());
             throw new OrderException(
              "Could not locate order by user " + e.getMessage());
            }
            return orders;
           }
           public Order findOrderById(int id) throws OrderException {
            Order order = null;
            try {
             order = getOrderDAO().findOrderById(id);
            } catch (RuntimeException e) {
             // should really use a logger instead of System.out
             System.out.println(
              "Could not locate order by ID " + e.getMessage());
             throw new OrderException(
              "Could not locate order by ID " + e.getMessage());
            }
            return order;
           }
           public IOrderDAO getOrderDAO() {
            return orderDAO;
           }
           public void setOrderDAO(IOrderDAO orderDAO) {
            this.orderDAO = orderDAO;
           }
          }
          接下去對(duì) DAO 的實(shí)現(xiàn)類進(jìn)行編碼。既然 Spring 已經(jīng)有對(duì) Hibernate 的支持,那這個(gè)例子就直接繼承 HibernateDaoSupport類了,這個(gè)類很有用,我們可以參考 HibernateTemplate(它主要是針對(duì) HibernateDaoSupport 的一個(gè)用法,具體可以查看 Spring 的 API)。
          public interface IOrderDAO {
           public  Order findOrderById(final int id);
           public abstract List findOrdersPlaceByUser(final String placedBy);
           public abstract Order saveOrder(final Order order);
          }
          此接口的實(shí)現(xiàn)類:
          public class OrderHibernateDAO
           extends HibernateDaoSupport
           implements IOrderDAO {
           public OrderHibernateDAO() {
            super();
           }
           public Order findOrderById(final int id) {
            Order order = (Order) getHibernateTemplate().load(Order.class, new Integer(id));
             
            if(order.getOrderLineItems().size() > 0){
             // collection initialized. 
            }   
            return order;
           }
           public List findOrdersPlaceByUser(final String placedBy) {
            return getHibernateTemplate().executeFind(new HibernateCallback() {
             public Object doInHibernate(Session session)
              throws HibernateException, SQLException {
              StringBuffer sb = new StringBuffer(100);
              sb.append("select distinct order ");
              sb.append("from Order order ");
              sb.append("join order.lineItems lineItems ");
              sb.append("where order.placedBy = :placedBy");
              sb.append("order by order.id");
              Query query = session.createQuery(sb.toString());
              query.setString("placedBy", placedBy);
              List list = query.list();
              return list;
             }
            });
           }
           public Order saveOrder(final Order order) {
            getHibernateTemplate().save(order);
            return order;
           }


          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=448765

           

           Struts+Spring+Hibernate 的示例(二)

          續(xù)前,現(xiàn)在我們來看看 Spring 的配置文件 applicationContext-hibernate.xml :
          <beans>     
                <!-- 數(shù)據(jù)源定義-->
                <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
                  <property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
                  <property name="url"><value>jdbc:mysql://localhost:3306/test</value></property>
                  <property name="username"><value>root</value></property>
                  <property name="password"><value></value></property>
              </bean>

              <!-- Hibernate 的 SessionFactory 定義 -->
                <bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
                   <property name="dataSource"><ref local="dataSource"/></property>
                      <property name="mappingResources">
                            <list>
                                  <value>com/meagle/bo/Order.hbm.xml</value>
                                  <value>com/meagle/bo/OrderLineItem.hbm.xml</value>                       
                            </list>
                      </property>           
                      <property name="hibernateProperties">
                            <props>
                                  <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                                  <prop key="hibernate.show_sql">true</prop>
                            </props>
                      </property>           
                </bean>

                <!-- 對(duì)單一 Hibernate SessionFactory 的事務(wù)管理器定義 -->
                <bean id="myTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
                      <property name="sessionFactory"><ref local="mySessionFactory"/></property>
                </bean>     

                <!-- 業(yè)務(wù)服務(wù)對(duì)象定義 并將它配置在事務(wù)管理器中 -->
                <bean id="orderService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">     
                      <property name="transactionManager"><ref local="myTransactionManager"/></property>
                      <property name="target"><ref local="orderTarget"/></property>
                      <property name="transactionAttributes">
                            <props>
                                  <prop key="find*">PROPAGATION_REQUIRED,readOnly,-OrderException</prop>
                                  <prop key="save*">PROPAGATION_REQUIRED,-OrderException,-OrderMinimumAmountException</prop>
                            </props>
                      </property>
                </bean>

                <!-- 業(yè)務(wù)對(duì)象實(shí)現(xiàn)定義 -->
                <bean id="orderTarget" class="com.meagle.service.spring.OrderServiceSpringImpl">
                      <property name="orderDAO"><ref local="orderDAO"/></property>
                </bean>
               
                <!-- Hibernate 實(shí)現(xiàn)的 DAO 對(duì)象定義 -->
                <bean id="orderDAO" class="com.meagle.service.dao.hibernate.OrderHibernateDAO">
                      <property name="sessionFactory"><ref local="mySessionFactory"/></property>
                </bean>     
          </beans>

          這里我們使用了 Spring 提供的便捷的方式-----在 Spring 內(nèi)部配置中并入了 Hibernate 的配置。也可以在 Spring 外使用 Hibernate,將 Hibernate 的配置寫在 hibernate.cfg.xml 中。

          從下圖可以看出,每個(gè)對(duì)象都聯(lián)系著 Spring,并且能通過 Spring 注入到其他對(duì)象。把它與 Spring 的配置文件比較,觀察他們之間的關(guān)系:

          4. 既然已經(jīng)將各種服務(wù)對(duì)象搭配起來了,現(xiàn)在需要把服務(wù)顯示到其他層。 這個(gè)通常是在 Struts 或者 Swing 這層里編碼。一個(gè)簡(jiǎn)單方法就是用服務(wù)定位器返回給 Spring context 。當(dāng)然,可以通過直接調(diào)用 Spring 中的Bean 來做。
             下面就是一個(gè) Struts Action 中的服務(wù)定位器使用的例子(后面的 Action 類將繼承這個(gè)類,這樣實(shí)現(xiàn)表示層同業(yè)務(wù)層的結(jié)合):

          public abstract class BaseAction extends Action {

                private IOrderService orderService;

                public void setServlet(ActionServlet actionServlet) {
                      super.setServlet(actionServlet);
                      ServletContext servletContext = actionServlet.getServletContext();
                      WebApplicationContext wac =
                            WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);
                      this.orderService = (IOrderService) wac.getBean("orderService");
                }

                protected IOrderService getOrderService() {
                      return orderService;
                }
          }

          既然表示層是使用 Struts 框架的,現(xiàn)在來看看 Struts 的配置文件是怎樣的:
          <struts-config>
                <!-- Form Beans -->
                <form-beans>
                      <form-bean name="OrderForm" type="com.meagle.forms.OrderForm"/>
                </form-beans>

                <!-- Global Exceptions -->
                <global-exceptions>
                      <exception key="global.data.access.exception"
                            path="/queryOrder.jsp"
                            scope="request"
                            type="org.springframework.dao.DataAccessException"/>
                </global-exceptions>

                <!-- Action Mappings -->
                <action-mappings>
                      <action path="/Index"
                        forward="/index.jsp"/>

                      <action path="/PlaceOrder"
                                    forward="/newOrder.jsp"/>
                                   
                      <action path="/QueryOrder"
                                    forward="/queryOrder.jsp"/>
                     
                      <action path="/SaveNewOrder"
                        type="com.meagle.action.SaveOrderAction"
                        name="OrderForm"
                        scope="request"
                        validate="true"
                        input="/newOrder.jsp">
                        <display-name>Save New Order</display-name>                 
                                 <exception key="error.order.save"
                                       path="/newOrder.jsp"
                                       scope="request"
                                       type="com.meagle.exception.OrderException"/>
                                 <exception key="error.order.not.enough.money"
                                       path="/newOrder.jsp"
                                       scope="request"
                                       type="com.meagle.exception.OrderMinimumAmountException"/>
                        <forward name="success" path="/viewOrder.jsp"/>
                        <forward name="failure" path="/newOrder.jsp"/>
                </action>
                     
                     
                <action path="/FindOrderID"
                        type="com.meagle.action.FindOrderAction"
                                 name="OrderForm"
                                 scope="request"
                                 validate="true"
                                 input="/queryOrder.jsp">                       
                                 <display-name>Find Existing Order</display-name>                 
                                 <exception key="error.order.find"
                                       path="/queryOrder.jsp"
                                       scope="request"
                                       type="com.meagle.exception.OrderException"/>
                                 <forward name="success" path="/viewOrder.jsp"/>
                      </action>
                </action-mappings>
                <message-resources parameter="com.meagle.resources.ApplicationResources"/>           
          </struts-config>

          SaveNewOrder  這個(gè) Action 是處理表示層里提交的表單。這是 Struts 中很典型的 Action。注意觀察它的 exception 配置,這些 Exceptions 也在 Spring 配置文件中配置了。 當(dāng)異常在業(yè)務(wù)層被被拋出時(shí),我們可以控制他們,并適當(dāng)?shù)娘@示到表示層。OrderException 在持久層保存 order 對(duì)象失敗的時(shí)候被觸發(fā)。這將導(dǎo)致事物回滾并且通過業(yè)務(wù)對(duì)象把異?;貍鞯?Struts 這一層。OrderMinimumAmountException 也是一樣。

          這兩個(gè) Action 類都繼承了前面提到 BaseAction,現(xiàn)在看看 SaveNewAction 這個(gè)類中與業(yè)務(wù)層的交互:

                public ActionForward execute(
                      ActionMapping mapping,
                      ActionForm form,
                      javax.servlet.http.HttpServletRequest request,
                      javax.servlet.http.HttpServletResponse response)
                      throws java.lang.Exception {

                      OrderForm oForm = (OrderForm) form;

                      Order order = new Order();
                      order.setUserName(oForm.getWhoPlacedOrder());

                      Set lineItems = new HashSet();

                      if (oForm.getItemDesc_1() != null && oForm.getItemDesc_1().length() > 0) {
                            OrderLineItem item = new OrderLineItem();
                            item.setDescription(oForm.getItemDesc_1());
                            item.setLineItemPrice(oForm.getItemPrice_1());
                            lineItems.add(item);
                            item.setOrder(order);
                      }

                      if (oForm.getItemDesc_2() != null && oForm.getItemDesc_2().length() > 0) {
                            OrderLineItem item = new OrderLineItem();
                            item.setDescription(oForm.getItemDesc_2());
                            item.setLineItemPrice(oForm.getItemPrice_2());
                            lineItems.add(item);
                            item.setOrder(order);
                      }

                      if (oForm.getItemDesc_3() != null && oForm.getItemDesc_3().length() > 0) {
                            OrderLineItem item = new OrderLineItem();
                            item.setDescription(oForm.getItemDesc_3());
                            item.setLineItemPrice(oForm.getItemPrice_3());
                            lineItems.add(item);
                            item.setOrder(order);
                      }

                      order.setOrderLineItems(lineItems);

                      getOrderService().saveNewOrder(order);
                     
                      oForm.setOrder(order);
                     
                      ActionMessages messages = new ActionMessages();
                      messages.add(Globals.MESSAGE_KEY, new ActionMessage("message.order.saved.successfully"));
                      saveErrors(request, messages);

                      return mapping.findForward("success");
                }

          說到這差不多了。在 web.xml 中需要引入 Spring 的配置文件??梢詤⒖嘉仪懊娴奈恼?。
          如果有需要示例的全部代碼,請(qǐng)告訴我郵箱。



          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=457726

           

           Struts+Spring+Hibernate 的兩種組合

          這兩天從網(wǎng)上 down 了兩個(gè) Struts+Spring+Hibernate 的例子,一個(gè)是 Spring Live 中第二章的 myusers,一個(gè)是 Wiring your web application with open source java(這個(gè)文檔網(wǎng)上有中文也有英文的) 中的例子,這里我取名為 SSHTest。 在 MyEclipse 中建立這兩個(gè)工程并調(diào)試成功后,我看到這兩個(gè)工程在組合 Struts、Spring、Hibernate 的時(shí)候有點(diǎn)點(diǎn)不同,下面就三個(gè)配置文件(web.xml、struts-config.xml、applicationContext.xml、)來看他們的不同:

          myusers 的 web.xml 沒有引入什么特別的。

          SSHTest 的 web.xml :
          通過: 
             <listener>
                <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
             </listener>
          或:
             <servlet>
                <servlet-name>SpringContextServlet</servlet-name>
                <servlet-class>org.springframework.web.context.ContextLoaderServlet</servlet-class>
                <load-on-startup>1</load-on-startup>
             </servlet>
          Web 容器會(huì)自動(dòng)加載 /WEB-INF/applicationContext.xml 初始化 ApplicationContex t實(shí)例;
          也可以通過
             <context-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/applicationContext-*.xml</param-value>
             </context-param>
          使 Web 容器加載指定名稱路徑的 Spring 配置文件。

          myusers 的 struts-config.xml
          通過
              <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
                  <set-property property="contextConfigLocation"
                      value="/WEB-INF/applicationContext.xml,
                             /WEB-INF/action-servlet.xml"/>
              </plug-in>
          來加載 Spring 配置文件。

          而 SSHTest 的 struts-config.xml 又沒有什么特別之處了。

          兩個(gè)工程的 applicationContext.xml 都大同小異。

          由上可以看出,即可以使用 web.xml 來使 Web 容器加載 Spring,也可以通過 struts-config.xml 來使 Web 容器加載 Spring。

            



          Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=431799



          posted on 2007-09-18 15:46 Ke 閱讀(2598) 評(píng)論(1)  編輯  收藏 所屬分類: struts+spring+hibernate

          FeedBack:
          # re: struts+spring+hibernate 組裝web應(yīng)用 2009-02-09 23:51 smaller
          麻煩樓主給我一份代碼吧,我郵箱myqq0803@163.com,謝謝了  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 正定县| 武穴市| 扬州市| 卓尼县| 临洮县| 庆云县| 通河县| 比如县| 策勒县| 马鞍山市| 醴陵市| 托克托县| 武穴市| 东源县| 马龙县| 宾阳县| 烟台市| 塔河县| 五大连池市| 富顺县| 东至县| 廊坊市| 英德市| 沁水县| 延安市| 长乐市| 永寿县| 凉城县| 巴中市| 灵丘县| 惠州市| 宣城市| 璧山县| 贺兰县| 绥中县| 邵阳县| 全州县| 长沙县| 泰和县| 始兴县| 施甸县|