用java來建立一個很有價值的web 應用不是一個簡單的任務。在架構這個應用時要考慮很多的因素和問題。從更高的層次來看,開發人員面臨著關于如何構建用戶接口,何處駐留業務邏輯,以及如何實現數據持久性這些問題。這3層都有各自的問題需要回答。而每一層又需要實現那些技術?應用如何設計來進行松散耦合并能進行靈活變更?應用架構是否允許某一層變更而不影響到其它的層次?應用應該如何處理容器一級的服務比如事務?
在為你的應用創建一個架構之前有許多問題需要澄清。幸運的是,有很多開發者都意識到這個問題,并建立了很多框架來解決這些問題。一個良好的框架可以讓開發人員減輕重新建立解決復雜問題方案的負擔和精力;它可以被擴展以進行內部的定制化;并且有強大的用戶社區來支持它。框架通常能很好的解決一個問題。然而,你的應用是分層的,可能每一個層都需要各自的框架。僅僅解決UI問題并不意味著你能夠很好的將業務邏輯和持久性邏輯和UI 組件很好的耦合。例如,你不應該使具有JDBC代碼的業務邏輯放入控制器之中,這不是控制器應該提供的功能。一個UI 控制器應該是輕量化的組件,由它代表對UI范圍之外的其它應用層的服務調用。良好的框架自然地形成代碼分離的原則。更為重要的是,框架減輕了開發人員從頭構建持久層代碼的精力,從而集中精力來應用邏輯上,這對客戶端來說更為重要。
本文討論了如何結合幾個著名的框架來達到松散耦合,如何設計你的架構,以及如何達到各個層次的一致性設計。面臨的挑戰是,將框架整合起來,以使每一層都向另外的層次以一種松散的方式來暴露接口,而不管底層功能使用的是什么技術。本文還討論整合3種著名開源框架的一種策略。對表現層,我們使用Struts;業務層使用Spring;對于持久層我們使用的是Hibernate。你盡可以取代這里的某個框架而使用你喜歡的框架已達到同樣的效果。圖1顯示了框架被整合起來時,從最高層次看到的視圖。

應用層
許多設計良好的web 應用,可以被按職責分為四層。這些層次是表現層、持久層、業務層、和領域模型層。每一個層次都有其獨特的職責,不能把各自的功能與其它層次相混合。每一個應用層都應該和其它層隔離開來,但允許使用接口在層間進行通信。我們開始來看看每個層,并討論一下它們各自都應該提供什么和不應該提供什么。
表現層
一個典型的web 應用的末端是表現層。許多Java 開發者都知道Struts 提供了什么東西。然而,太多時候,耦合代碼比如業務邏輯被放進org.apache.struts.Action中。所以,我們先總結一下Struts 之類的框架應該提供什么。下面就是Struts 的職責所在:
- 管理用戶的請求和響應
- 提供一個控制起來將調用委托到業務邏輯和其他上游處理
- 將來自于拋出例外的其他層的例外處理到Struts Action 中
- 組裝可以在視圖中表現的模型對象
- 執行UI 校驗
下面是一些經常可以使用Struts進行編碼但是不應該和表現層關聯的事情:
- 直接和數據庫交互,比如JDBC 調用
- 與應用相關的業務邏輯和校驗
- 事務管理
在表現層中引入這些類型的代碼將導致類型耦合和維護負擔。
持久層
一個典型Web應用的另一端是持久層。這也是應用中最容易很快失控的地方。開發者通常低估了自己構建自己的持久層框架的挑戰。一個定制的,內部開發的持久層不僅需要大量的開發時間,并且通常缺乏功能和難以管理。目前有許多解決這些問題的開源對象關系映射 (ORM) 框架。特別地, Hibernate 框架就允許Java中的對象-關系的持久性和查詢服務。Hibernate 對已經熟悉了SQL 和JDBC API 的Java開發者來或具有中度的學習曲線。Hibernate 的持久對象基于POJO和Java 群集(collections)。此外,使用Hibernate 不和你的IDE接口。下面列出了你需要在持久性框架中編寫的代碼類型:
- 查詢關系信息到對象中。Hibernate 是通過稱為HQL的OO查詢語言,或者使用更有表現能力的規則API,來完成這個工作的。除了使用對象而不是表,使用字段而不是列的方式,HQL非常類似于 SQL。也有一些新的特定的HQL 語言特征需要學習;但是,它們是很容易理解和良好編寫的。HQL 是一種用于查詢對象的自然語言,而對象,只需要很少的學習曲線吧。.
- 存儲、更新和刪除存儲在數據庫中的信息
- 高級的對象關系映射框架比如Hibernate支持大部分主流SQL數據庫,它們支持父/子關系,事務,繼承和多態。
下面是應該在持久層避免的一些事情:
- 業務邏輯應該置于應用的更高層中。這里只允許數據訪問方法。
- 不應該使持久邏輯和表現邏輯耦合。避免表現組件如JSP或者基于servlet的類中的邏輯直接和數據訪問進行通信。通過將持久性邏輯隔離在其自己的層中,應用將具有更加靈活的修改性而不影響到其他層的代碼。例如, Hibernate 可以使用其他持久框架和API代替,而不需要修改其它層中的代碼。
業務層
典型的Web應用的中間組件一般是業務層和服務層。從編程的角度來說,service layer經常被忽略。這種類型的代碼散布于UI表現層和持久層并不是不多見。這些都不是正確的地方因為它導致了緊密耦合的應用和難以維護的代碼。幸運的是,大多數框架都解決了這個問題。這個空間內最流行的兩個框架是Spring 和PicoContainer。它們都被視為是具有非常小的足跡(footprint)并且決定如何將你的對象整合在一起的微容器(microcontainer)。這些框架都建立在一種叫做依賴性注入(dependency injection) (也稱控制反轉(inversion of control:IOC))的簡單概念之上。我們將關注Spring中通過針對命名配置參數的bean屬性的setter 注入的使用。Spring 也允許一種更加高級的構造器注入(constructor injection)形式作為setter injection 的可選替代。對象通過簡單的XML 文件進行連接,該配置文件包含對各種對象的引用,比如事務管理處理器(transaction management handler),對象工廠,包含業務邏輯的服務對象,以及數據訪問對象(DAO)。
我們隨后會用一些例子來澄清Spring中使用這些改變的方式。
業務層應該負責下面的問題:
- 處理應用的業務邏輯和業務校驗
- 管理事務
- 允許與其他層進行交互的接口
- 管理業務級對象之間的依賴性
- 加入了表現和持久層之間的靈活性,以便它們不需要彼此進行直接通信
- 從表現層暴露上下文給業務層以獲得業務服務
- 管理從業務層到表現層的實現
領域模型層
最后,因為我們要解決實際的問題的web應用,我們需要一套在不同的層間移動的對象。領域模型層包含的是表達實際業務對象的對象,比如Order, OrderLineItem, Product 等等。這一層允許能讓開發者不再構建和維護不必要的數據傳輸對象DTO來匹配其領域對象。例如, Hibernate允許你讀取數據庫信息到一個領域對象的對象圖中,以便你可以在離線的情況下將其表現在UI層中。這些對象可以被更新并跨過表現層發送回去,然后進行數據庫更新。另外,你不再需要將對象轉變成DTO,因為它們在不同的層間移動時可能會丟失事務。這種模型允許Java 開發者能夠以OO風格的方式很自然的處理對象,而不用編寫額外的代碼。
整合一個簡單的例子
到此,應該對各種層次和組件有一個高層的理解了罷。可以開始一些實踐了。再次說明。我們的例子整合了Struts, Spring, 和Hibernate 框架。每個框架都包含大量的內容細節,我們不會多述。我們的目的使用一個例子向你說明如何將它們整合在一起構建一個優雅的Web應用架構。實例將演示一個請求是如何得到各層的服務的。此應用的用戶可以將一個訂單保存在數據庫中并且察看數據中的已有訂單。進一步的增強允許將用戶更新和刪除現有訂單。
首先,我們將常見我們的領域對象,因為它們是要和各層溝通的。這些對象將允許我們能夠定義那些對象需要持久化,那些業務邏輯需要提供,以及應該設計那些表現接口。接下來,我們將使用Hibernate 來為領域對象配置持久層和定義對象關系映射。然后,我們將定義和配置我們的業務層。在完成這些組件后,我們將討論如何使用Spring將這些層關聯起來。最后,我們將提供一個表現層,它知道如何與業務服務層通信以及如何處理來自于其他層的例外。
摘要: 第1.5式. 將JSP 應用轉到Struts
問題
你需要將一個已有的基于JSP的web 應用轉換為Struts 的應用。
動作分解
在加入新的功能到應用中時,可應用Struts采取重構的方式來進行。隨著你對Struts 知識的增加,你可以將現有代碼重新架構成使用Struts。如果沒有計劃對應用進行新的開發,就一次性重構現有的JSP代碼。
變化
遷移一個現有JSP應用的困難程度取決于應... 閱讀全文
對于RAD 工具的四個層次, JavaServer Faces 定義了其中3個:一個組件架構,一個標準的UI 部件集,以及一個應用架構。JSF的組件架構定義了通用的方式來建立UI 部件。此架構能驅動標準的JSF UI 組件(按鈕,超鏈接,復選框,文本框等等),也為第3方組件留了空間。組件是面向事件的,所以JSF 允許你處理客戶產生的事件 (如,文本框中值的變化或者點擊了按鈕)。

因為對Web應用來說,不象其桌面應用堂兄弟,它必須總是要滿足多個客戶 (比如桌面瀏覽器,移動電話和PDA等), JSF 有一個強大的架構來以不同的方式顯示組件。它也有一個可擴展的機制來進行輸入校驗 (如字段長度) 以及在顯示字符串和對象之間進行轉換。
Faces 也能夠自動的保持你的UI 組件和收集用戶輸入值的Java 對象之間的同步,并且通過調用后臺Bean來對事件進行響應。另外,它有一個強大的導航系統并且全面支持多語言特征。這些特征構成了JSF的應用基礎架構—即對新應用系統必不可少的基本構建塊。
JavaServer Faces 定義了工具支持的基礎,但是其實現留給了工具廠商,這是Java的習慣。你可以自行選擇業界領導提供的工具,它們都可以是你能夠像使用其他RAD 開發工具如Visual Studio. NET一般可視化的布局和設計你的Web UI。 (如圖1.1, 1.2, 和 1.3 分別展示了在IBM, Oracle, 和 Sun的IDE開發工具中開發JSF是什么樣子) 。或者,如果你愿意在沒有設計工具下開發Faces 應用。

在這些贊美之詞之后,我們應該指出JavaServer Faces 和桌面UI 框架如Swing 或者SWT之間的關鍵不同之處: JSF 是運行在服務器之上。因此, Faces 應用將運行在一個標準的Java web 容器之中,如Apache Tomcat [ASF, Tomcat],Oracle Application Server [Oracle, AS],或者IBM WebSphere Application Server [IBM, WAS],然后向客戶顯示HTML 或者其他標記語言。

如果你點擊一個Swing 應用中的按鈕,它將產生一個事件,而你可以直接在駐留在桌面中的代碼來處理該事件。相反, web 瀏覽器并不知道JSF組件和其事件的任何東西;它僅僅知道顯示HTML而已。所以當你點擊一個Faces 應用按鈕,它將產生一個請求,有瀏覽器發送到服務器。Faces 負責將該請求轉換成一個可以被服務器中的應用邏輯所處理的事件。它也負責保證你在服務器所定義的每一個UI 部件都正確顯示給瀏覽器。

圖1.4 顯示了一個Faces 應用的高階視圖。你可以看到,應用運行在服務器上可以和其他子系統集成,如EJB服務或者數據庫服務。當然, JSF還提供許多其他服務可以幫助你你更小的代價構建強大的Web應用。
JavaServer Faces 有一個特定的目標:使web 開發更快更容易。它允許開發人員以組件,事件,后臺Bean以及它們之間的交互來進行思考,而不是請求,響應和標記。換句話說,它掩蓋了Web開發的大量的復雜性,是開發人員能夠集中于如何使他們的應用做的最好。
工業支持
對JCP社區和Sun 擴展Java的方式來說,最好的事情莫過于有大量的公司,組織和個人投身其中。通過JCP 產生一種規范實際上算不上快速,但結果卻是非常好的。JavaServer Faces 在2001年5月通過Java 規范請求(JSR) 127 引入;規范的最終版本,JSF 1.0,在2004年3月3日才發布。而JSF 1.1 (維護發布版) 則是2004年5月27日發布的。參與開發Faces的公司和組織 (除Sun之外)包括Apache軟件基金, BEA 系統, Borland 軟件,
IBM,Oracle,Macromedia,等等。
這些公司開發的產品可分為3類(某些可能適合不止一類):J2EE 容器,開發工具,和UI 框架。因為JavaServer Faces是一個與工具一起工作和運行于J2EE 容器中的UI框架,這樣做則非常之好。最重要的是這些公司中包括許多業界巨頭。這意味著你可以期望JSF 具有大量的工業支持。并且,如果你的供應商不支持JSF,你也可以免費下載Sun的參考實現 [Sun, JSF RI]。
要跟蹤最新的JSF 新聞,文章,產品和供應商,請訪問JSF Central [JSF Central],本書作者所運作的一個社區站點。
JSF,Struts,和其他框架
我們面對這一情況:有大量的Java web 框架可用。它們中某些,如Struts [ASF, Struts] 和 WebWork [OpenSymphony, WebWork],有助于表單處理和其他問題,比如遵循Model 2,集成數據源,以及通過XML配置文件中心化控制引用的所有應用資源。這些基本框架提供了廣泛的基礎設施,但是還沒有屏蔽基本的HTTP請求響應處理。
其他框架,象Tapestry [ASF, Tapestry],Oracle的應用開發框架 (ADF) UIX [Oracle, ADF UIX],以及SOFIA [Salmon, SOFIA],都提供一個UI 組件模型和某些事件處理機制。這些UI 框架,包括JSF,目的是簡化整體變成模型。經常,基礎架構和UI 框架具有重疊的功能。
為了理解這種重疊,你可以想象web 應用架構師一個服務棧。靠近棧底部的服務沒能抽象基礎協議的許多細節;它們更像粗加工品。棧中靠近頂部的服務則隱藏了更多討厭的細節,提供更高級別的抽象。最低層的服務由web servers,Servlet API,和JSP處理。大部分框架都提供一些附加服務的子集。圖1.6顯示了這個棧,以及與JSF,Struts,servlets,JSP,和典型的web server的關系。
你可以從圖中看到JSF 支持足夠多的服務,這也使得它自己成為強大的框架。在大多數情況下,這就是你需要的東西。后續發布的Faces極有可能也會包括傳統的服務。
然而,即使Faces 與Struts這樣的框架有些重疊,也并不是必須替代它們。 (事實上,如Struts的領導, Craig McClanahan, 是JavaServer Faces的開發指導) 如果你將他們集成起來,你就可以訪問棧中的所有服務(第 14 章將包含Struts 集成)。你也可以和其他框架一起使用JSF,比如Spring [Spring-Faces]。
對于面向UI的框架,JSF 和他們很多功能都有重疊。這些項目的某些申明將在其未來版本中支持JSF。Faces 的獨特之處在于有通過JCP的工業巨頭參與的開發聯盟,以及將成為J2EE的一部分。作為結果,它將分享受強有力的工具支持,并將隨很多J2EE server一起交付。

組件無處不在
令人悲哀的是,“組件”一詞的過度使用在今天已經到處蔓延了。操作系統是一個組件,應用程序是一個組件,EJBs 是組件,庫是組件,甚至廚房的水槽也是。有大量的書論及組件,有好的書指出組件有好多定義存在。
如果你知道他的確實意義,對這個詞的濫用,你就不會感到陌生。如果你在詞典中查找“組件(component)”這個詞,你就會看到他有一個同義詞供選—整體的一個部分。因此,如果你使用這個詞的字面意思,在一個分布式應用歡迎用,操作系統確實是一個組件。
更有趣的是,從概念上講,廚房水槽對操作系統相比對Faces組件來說更有共通之處。你不用自己從頭制造它—你只需要購買一個符合你需要的水槽:尺寸,顏色,材料,容器數,等等。對其他廚房用品也是如此,比如櫥柜和工作臺面。所有這些組件都有特定的接口可以使他們能夠和其他東西進行集成,但是依賴于特定的環境服務。(例如,接口管)。最終結果可能是獨特的,但整體是由獨立可重用的部件組成。
如果我們采用廚房組件的概念,并應用到軟件商,我們會得出這個定義:
廚房的“環境依賴性”就是諸如房間本身,配管,電路等等的因素。本質上,環境是所有組件的容器。一個容器是擁有組件,并且提供一系列允許進行組件操作的服務的系統。有時,這種操作在IDE (設計時)中進行,有時則在部署環境中運行,比如J2EE server之中 (運行時)。
短語“獨立部署” 意味著一個組件是一個自包含的單元,可以被安裝到一個容器中。廚房水槽是一個獨立的,自包含的組件,可以安裝在工作臺中。
當你改造你的廚房時,你雇用一個承包商,由他來組裝你所選擇的組件 (櫥柜,抽屜,水槽等等) 成為一個完整的廚房。我們使用組件構建軟件時,我們也是將各種組件組裝起來,創建能夠運行的軟件系統。
JSF 組件, Swing 組件, servlet, EJB, JavaBean, ActiveX 控件,以及Delphi 可視組件庫 (VCL) 組件都符合這個定義。但這些組件卻集中于不同的事情。JSF 和Swing 組件單獨針對UI 開發,而ActiveX 和 VCL 控件可以也可以不影響UI。Servlets 和 EJBs 則更粗糙一些— 他們在應用和業務邏輯領域提供大量的功能。
因為JSF 著眼于UI 組件,我們來相應窄化我們的組件定義。
如果你是在開發傳統的GUI應用,那么UI 組件的概念應該對你非常熟悉了。JavaServer Faces 的精彩之處在于將標準的UI 組件模型引入到Web世界。
第1.4式. 從Struts 1.1 升級至Struts 1.2
問題
你想要升級基于Struts 1.1 的應用至Struts 1.2。
動作分解
Table 1-4. Struts 1.1 和 1.2 的Taglib URI |
Struts 1.1 Taglib URI |
Struts 1.2.4 Taglib URI |
http://jakarta.apache.org/struts/tags-bean |
http://struts.apache.org/tags-bean |
http://jakarta.apache.org/struts/tags-html |
http://struts.apache.org/tags-html |
http://jakarta.apache.org/struts/tags-logic |
http://struts.apache.org/tags-logic |
http://jakarta.apache.org/struts/tags-template |
http://struts.apache.org/tags-template |
http://jakarta.apache.org/struts/tags-tiles |
http://struts.apache.org/tags-tiles |
http://jakarta.apache.org/struts/tags-nested |
http://struts.apache.org/tags-nested |
- 將validation.xml文件中開頭的的DOCTYPE 聲明修改為:
<!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.1.3//EN" http://jakarta.apache.org/commons/dtds/validator_1_1_3.dtd">
- 將struts-config.xml文件中開頭的DOCTYPE 聲明修改為:
<!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.2//EN" "http://struts.apache.org/dtds/struts-config_1_2.dtd">
- 將ActionError 類的使用替換為ActionMessage 類。
- 將除了定制ActionForms 的validate( )方法之外的地方的ActionErrors類的使用替換為ActionMessages類。
- 去除ActionServlet中除了config參數之外的其他任何init-param元數的依賴。這些參數在Struts 1.1 中已經不贊成,而在Struts 1.2已經不支持。而是將這些參數值移到struts-config.xml文件中。這些參數大多數被controller元素的屬性替代了。
- 去除html:form標簽中對name, scope, 和type屬性的依賴。這些參數在Struts 1.1 中已經不贊成,而在Struts 1.2已經不支持。
動作變化
Struts 1.2 的正式目標是去除不贊成方法并完成對模塊化的支持。盡管Struts 1.2 并未對Struts 1.1 的核心進行徹底的修改,它也包括了一些值得努力去升級的新的特征和增強。大部分這些特征都將在本秘籍中討論。下面是一些明顯的增強:
- 新的validwhen校驗器用作復雜的交叉字段校驗(第8.4式)
- 支持通配符的action mapping,允許你在多個相關的URL中重用action元素。(第7.8式)
- 新的預構建的action 包括一個新的MappingDispatchAction類和一個場所切換LocaleAction類(第6.10 式和第12.4式)
對于新應用,應該盡量使用Struts 1.2。如果你已經有一個Struts 1.1 應用,你將發現Struts 1.2 引入了大量新的和有用的特征。比之于從Struts 1.0 升級至Struts 1.1,從升級Struts 1.2 要容易些,只需要少一些的代碼修改。
相關招式
Struts wiki 有一些關于這個升級的詳細內容。相關的wiki 頁面可以在http://wiki.apache.org/struts/StrutsUpgradeNotes11to124中找到。
第1.3式. 從Struts 1.0遷移至Struts 1.1
問題
你需要將一個基于Struts 1.0的應用遷移到Struts 1.1.
動作分解
使用Struts1.1中對應的文件替換Struts 1.0 JAR 文件、標簽庫描述符(TLD) 文件、以及XML DTD 文件。如果你有使用Struts標簽庫絕對URI的JSP 頁面,你需要修改它們。使用新的標簽庫重新編譯和構建你的應用,解決兼容性錯誤。
最后,你需要將原來使用不贊成API的代碼修改為使用新的Struts 1.1 API。
變化
Struts 1.1 在Struts 1.0基礎上作了較大變化,從功能上講,基于 Struts 1.0 的應用可以通過使用Struts1.1中的對應文件來替換Struts 1.0 的JAR 和TLD文件來進行遷移,這沒什么大的困難。你需要修改所使用的標簽庫的URI,因為它們在Struta1.1中已經改變;這一般來說需要修改你的 web.xml部署描述符。如果你在JSP中使用絕對URI,這些值也需要修改。Table 1-3列出了標簽庫URI的改變。
Table 1-3. Struts標簽庫URI |
Struts 1.0.2 Taglib URI |
Struts 1.1 Taglib URI |
http://jakarta.apache.org/struts/tags-bean-1.0.2 |
http://jakarta.apache.org/struts/tags-bean |
http://jakarta.apache.org/struts/tags-html-1.0.2 |
http://jakarta.apache.org/struts/tags-html |
http://jakarta.apache.org/struts/tags-logic-1.0.2 |
http://jakarta.apache.org/struts/tags-logic |
http://jakarta.apache.org/struts/tags-template-1.0.2 |
http://jakarta.apache.org/struts/tags-template |
Not Available with Struts 1.0.2 |
http://jakarta.apache.org/struts/tags-tiles |
Not Available with Struts 1.0.2 |
http://jakarta.apache.org/struts/tags-nested |
Struts1.1中最明顯的改變是Struts 的ActionServlet (org.apache.action.ActionServlet) 和Action類(org.apache.struts.Action)。Struts 1.1 也引入了請求處理器RequestProcessor (org.apache.struts.action.RequestProcessor)的概念。ActionServlet將請求處理委托給請求處理器。在Struts 1.1中,你不再需要一定要擴展ActionServlet來進行定制化;相反,你應該子類化RequestProcessor。如果一個基于 Struts 1.0的應用沒有擴展ActionServlet,那么不需要做任何修改就能使用RequestProcessor。如果ActionServlet被子類化了,你卻應該擴展RequestProcessor。
另一個主要的增強是Struts的Action。Struts 1.1 引入了一個新方法execute( ), 即其子類應該實現這個方法,而不是原來的perform()方法。Example 1-1展示了一個實現perform()方法的簡單Action例子。
Example 1-1. Struts 1.0 Action
package org.apache.struts.webapp.example;

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;


public final class ExampleAction extends Action
{
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)

throws IOException, ServletException
{


try
{
ExampleService service = new ExampleService( );
Service.doService( );
}

catch (ServiceException ex)
{
throw new ServletException( ex );
}
return (mapping.findForward("success"));
}
}

Example 1-2則是使用Struts1.1的同一個例子。
Example 1-2. Struts 1.1 Action
package org.apache.struts.webapp.example;

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
import org.apache.struts.action.*;


public final class ExampleAction extends Action
{
public ActionForward execute (ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)

throws Exception
{

ExampleService service = new ExampleService( );
Service.doService( );

return (mapping.findForward("success"));
}
}

如你所見,基于Struts 1.1的Action, 例外處理不再需要在方法中執行。Struts 1.1 現在支持將例外處理作為框架的一部分。我們將在第9.1式練習這個招數。
你并不是一定要修改你的Actions 來使用execute( )方法,因為Struts 1.1 仍舊支持perform( )方法;但是該方法已經不贊成使用了。
]

|
如果你直接從Struts 1.0 遷移至Struts 1.2, Struts 1.1 中的不贊成因素,比如perform( )方法,已經從Struts 1.2 API中刪除了。 |
雖然這個方法將繼續發揮作用,但是我們還是建議你盡可能的將你的代碼修改來使用execute( )方法。這樣可以減少進一步升級到Struts 1.2的難度和工作。更明顯的是,這可以使你得到Struts 1.1 的例外處理能力的優勢。
參見
第9.1 式Struts 1.1的例外處理。