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

          常用鏈接

          留言簿(14)

          隨筆檔案(6)

          文章分類(467)

          文章檔案(423)

          相冊

          收藏夾(18)

          JAVA

          搜索

          •  

          積分與排名

          • 積分 - 827240
          • 排名 - 49

          最新評論

          閱讀排行榜

          評論排行榜

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

            摘要:

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

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

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

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

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

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

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

            表現(xiàn)層

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

            為用戶管理請求和響應(yīng);
            提供一個控制器代理調(diào)用業(yè)務(wù)邏輯和其它上層處理;
            處理從其它層擲出給一個Struts Action的異常;
            為顯示提供一個模型;
            執(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ā)時間,而且還經(jīng)常缺少功能和變得難以控制。有幾個開源的“對象-關(guān)系映射”框架非常解決問題。尤其是,Hibernate框架為java提供了"對象-關(guān)系持久化"機(jī)制和查詢服務(wù)。Hibernate對那些已經(jīng)熟悉了SQL和JDBC API的Java開發(fā)者有一個適中的學(xué)習(xí)曲線。Hibernate持久對象是基于簡單舊式Java對象和Java集合。此外,使用Hibernate并不妨礙你正在使用的IDE。下面的列表包含了你該寫在一個持久層框架里的代碼類型:

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

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

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

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

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

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

            業(yè)務(wù)層

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

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

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

            領(lǐng)域模型層

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

            結(jié)合一個簡單的例子

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

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

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

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

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

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

            持久層配置

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

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

            Order.hbm.xml
            OrderLineItem.hbm.xml

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

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

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

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

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

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


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

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

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

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

          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);
          }

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

            下一步是寫我們的DAO實(shí)現(xiàn)對象。因?yàn)镾pring有內(nèi)建的對Hibernate的支持,這個例子DAO將繼承HibernateDaoSupport類,這使得我們?nèi)菀兹〉靡粋€到HibernateTemplate類的引用,HibernateTemplate是一個幫助類,它能簡化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);
          }


            我們還有兩個對象要和我們的業(yè)務(wù)層連在一起。這包括HibernateSessionFactory和一個TransactionManager對象。這在Spring配置文件里直接完成。Spring提供一個HibernateTransactionManager,它將從工廠綁定一個Hibernate Session到一個線程來支持事務(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>

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

            既然我們已經(jīng)配置了我們的容器服務(wù)beans和把它們連在了一起,我們需要把我們的業(yè)務(wù)服務(wù)對象和我們的DAO對象連在一起。然后,我們需要把這些對象連接到事務(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)連在一起的東西的一個概覽。它展示了每個對象是怎樣相關(guān)聯(lián)的和怎樣被Spring設(shè)置進(jìn)其它對象中。把這幅圖和示例應(yīng)用中的Spring配置文件對比查看它們之間的關(guān)系。

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

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

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

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

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

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

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

            最后一個連接步驟是使我們的表現(xiàn)層和我們的業(yè)務(wù)層交互。這已經(jīng)通過使用前面討論的服務(wù)定位器來完成了。服務(wù)層充當(dāng)一個到我們的業(yè)務(wù)邏輯和持久層的接口。這兒是 Struts中的SaveNewOrder Action可能怎樣使用一個服務(wù)定位器調(diào)用一個業(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對象中編碼到接口,你能怎樣使用其它的技術(shù)或框架,比如 iBATIS,作為一個替代是顯而易見的。或者你可能用不同于Struts的框架替代你的UI層。改變UI層的實(shí)現(xiàn)不會直接影響你的業(yè)務(wù)邏輯層或者你的持久層。替換你的持久層不會影響你的UI邏輯或業(yè)務(wù)服務(wù)層。集成一個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.清晰的模型對象傳遞,這個模型對象可以是任何java對象,如果你不在意在各層之間傳遞同一個對象的話,這個模型對象就可以是hibernate的persistent object,通過open session in view,你可以以一致的方式使用業(yè)務(wù)模型對象。
          b.reference data,讓你清晰的處理look up數(shù)據(jù)。
          c. 多種可供選擇的視圖解析類型,可以在prpperties文件中定義page的邏輯名,或者定義在xml文件里的struts tiles邏輯名。
          d.無干擾的數(shù)據(jù)綁定,一個<spring:bind>可以對模型對象和form進(jìn)行綁定,就像struts自動填充formbean一樣,但spring 的綁定功能不會干擾界面布局,也就是說,你仍然可以使用html編輯器對頁面進(jìn)行處理。
          e.客戶端驗(yàn)證。
          f.服務(wù)器端驗(yàn)證。
          g.多種可供選擇的控制器,其中支持表單的控制器提供了類似vb中表單事件處理的功能,這是一系列的workflow,在你認(rèn)為合適的地方,插入你的處理代碼。

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

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

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

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

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

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

          三、整合

           

           Struts+Spring+Hibernate 的示例(一)
          先說說《Wiring Your Web Application with Open Source Java by Mark Eagle》這個示例,網(wǎng)上有這個的中英文文章。在后續(xù)的說明中我會將文章的部分內(nèi)容引用進(jìn)來。我使用的開發(fā)工具是 Eclipse3.1 + MyEclipse4.0M2。
          針對一個簡單或者復(fù)雜的 Web 應(yīng)用程序,我們需要考慮諸如是怎樣建立用戶接口?在哪里處理業(yè)務(wù)邏輯?怎樣持久化的數(shù)據(jù)?而針對這三個層次,每個層次我們都要仔細(xì)考慮:各個層該使用什么技術(shù)? 怎樣的設(shè)計能松散耦合還能靈活改變? 怎樣替換某個層而不影響整體構(gòu)架?應(yīng)用程序如何做各種級別的業(yè)務(wù)處理(比如事務(wù)處理)?等等。
          對于這個示例我們采用當(dāng)前流行的三種框架來做到 Web 應(yīng)用程序的松散耦合:表示層我們用 Struts;業(yè)務(wù)層我們用 Spring;而持久層則用 Hibernate。
          Struts 負(fù)責(zé)管理用戶的請求,做出響應(yīng);提供控制器,委派調(diào)用業(yè)務(wù)邏輯;處理異常;UI 驗(yàn)證等。
          Spring 負(fù)責(zé)處理應(yīng)用程序的業(yè)務(wù)邏輯和業(yè)務(wù)校驗(yàn);管理事務(wù);提供與其它層相互作用的接口;管理業(yè)務(wù)層級別的對象的依賴等。
          Hibernate 負(fù)責(zé)存儲、更新、刪除數(shù)據(jù)庫記錄等。
          這篇文章舉例說明如何使用這三個框架整合開發(fā),并揭示一個請求是如何貫穿于各個層的。(從用戶的加入一個Order到數(shù)據(jù)庫,顯示;進(jìn)而更新、刪除)。 
          1. 首先創(chuàng)建一組對象,這些對象有的需要持久化,有的提供業(yè)務(wù)邏輯,有的是顯示接口的設(shè)計。Hibernate 允許你將數(shù)據(jù)庫中的信息存放入對象,可以在連接斷開的情況下把這些數(shù)據(jù)顯示到UI層。而那些對象也可以返回給持續(xù)層,從而在數(shù)據(jù)庫里更新。
          使用 myeclipse 的 Web  Project 新建一個項(xiàng)目 SSHTest:
          創(chuàng)建 Order 類:
          利用 eclipse 生成 Getters 和 Setters。
          同樣創(chuàng)建 OrderLineItem 類。
          com.ivan.ssh.bo.Order 包含一個訂單的主要信息:訂單號,訂單總價,訂單客戶名。
          com.ivan.ssh.bo.OrderLineItem 包含訂單的詳細(xì)信息:訂單單項(xiàng)號,單價,描述。一個訂單對應(yīng)于多個訂單項(xiàng)。
          Order 與 OrderLineItem 的關(guān)系是一對多的關(guān)系,這里為它們建立雙向一對多的關(guān)系。
          在類中我們需要分別為 Order 和 OrderLineItem 添加屬性 orderLineItems(java.util.Set 類型) 和 order(Order 類型)及其 getter 和 setter 方法。
          2. 配置持久層,Hibernate 通過 XML 文件來映射 (OR) 對象,以下兩個 xml 文件分別映射了Order 和 OrderItem 對象。
          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,前者說明與哪個數(shù)據(jù)庫通信,使用哪個連接池或使用了 DataSource,加載哪些持久對象,后者用來完成查找、保存、刪除和更新這些操作。
          3. 配置業(yè)務(wù)層,這里要創(chuàng)建業(yè)務(wù)服務(wù)對象(Business Service Object),用他們來執(zhí)行程序的邏輯,調(diào)用持久層,得到 UI 層的 requests,處理 transactions,并且控制 exceptions。為了將這些連接起來并且易于管理,我們將使用面向方面的 SpringFramework。Spring 提供了控制倒置(Inversion of Control)和注射依賴設(shè)置(Setter Dependency Injection) 這些方式(可供選擇),用 XML 文件將對象連接起來。IoC 是一個簡單概念(它允許一個對象在上層接受其他對象的創(chuàng)建),用 IoC 這種方式讓你的對象從創(chuàng)建中釋放了出來,降低了偶合度。
          我們將用一個 business service object 接收一個 DAO,用它來控制 domain objects 的持久化。 由于在這個例子中使用了 Hibernate,我們可以很方便的用其他持久框架實(shí)現(xiàn)同時通知 Spring 有新的 DAO 可以使用了。在面向接口的編程中,你會明白 “注射依賴”模式是怎樣松散耦合你的業(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);
          }
          注意到這段代碼里有一個 setOrderDao(),它就是一個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;
           }
          }
          接下去對 DAO 的實(shí)現(xiàn)類進(jìn)行編碼。既然 Spring 已經(jīng)有對 Hibernate 的支持,那這個例子就直接繼承 HibernateDaoSupport類了,這個類很有用,我們可以參考 HibernateTemplate(它主要是針對 HibernateDaoSupport 的一個用法,具體可以查看 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>

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

                <!-- 業(yè)務(wù)服務(wù)對象定義 并將它配置在事務(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ù)對象實(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 對象定義 -->
                <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 中。

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

          4. 既然已經(jīng)將各種服務(wù)對象搭配起來了,現(xiàn)在需要把服務(wù)顯示到其他層。 這個通常是在 Struts 或者 Swing 這層里編碼。一個簡單方法就是用服務(wù)定位器返回給 Spring context 。當(dāng)然,可以通過直接調(diào)用 Spring 中的Bean 來做。
             下面就是一個 Struts Action 中的服務(wù)定位器使用的例子(后面的 Action 類將繼承這個類,這樣實(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  這個 Action 是處理表示層里提交的表單。這是 Struts 中很典型的 Action。注意觀察它的 exception 配置,這些 Exceptions 也在 Spring 配置文件中配置了。 當(dāng)異常在業(yè)務(wù)層被被拋出時,我們可以控制他們,并適當(dāng)?shù)娘@示到表示層。OrderException 在持久層保存 order 對象失敗的時候被觸發(fā)。這將導(dǎo)致事物回滾并且通過業(yè)務(wù)對象把異常回傳到 Struts 這一層。OrderMinimumAmountException 也是一樣。

          這兩個 Action 類都繼承了前面提到 BaseAction,現(xiàn)在看看 SaveNewAction 這個類中與業(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 的配置文件。可以參考我前面的文章。
          如果有需要示例的全部代碼,請告訴我郵箱。



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

           

           Struts+Spring+Hibernate 的兩種組合

          這兩天從網(wǎng)上 down 了兩個 Struts+Spring+Hibernate 的例子,一個是 Spring Live 中第二章的 myusers,一個是 Wiring your web application with open source java(這個文檔網(wǎng)上有中文也有英文的) 中的例子,這里我取名為 SSHTest。 在 MyEclipse 中建立這兩個工程并調(diào)試成功后,我看到這兩個工程在組合 Struts、Spring、Hibernate 的時候有點(diǎn)點(diǎn)不同,下面就三個配置文件(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 容器會自動加載 /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 又沒有什么特別之處了。

          兩個工程的 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 閱讀(2599) 評論(1)  編輯  收藏 所屬分類: struts+spring+hibernate

          FeedBack:
          # re: struts+spring+hibernate 組裝web應(yīng)用 2009-02-09 23:51 smaller
          麻煩樓主給我一份代碼吧,我郵箱myqq0803@163.com,謝謝了  回復(fù)  更多評論
            
          主站蜘蛛池模板: 西充县| 长白| 临桂县| 苗栗县| 南雄市| 上饶县| 黑龙江省| 巩留县| 江都市| 乡城县| 呼和浩特市| 靖边县| 沧源| 锦屏县| 田林县| 丁青县| 灵宝市| 双流县| 讷河市| 曲靖市| 曲阜市| 六安市| 孟连| 涡阳县| 镇巴县| 张北县| 大新县| 扎鲁特旗| 万宁市| 枣强县| 景德镇市| 尖扎县| 青神县| 河间市| 淮北市| 张家界市| 河北区| 河曲县| 饶平县| 洞口县| 天峻县|