做一個好的架構師一直是我的一個目標。但是,做過這么多項目后發現自己在設計上仍存在很多不足。下文是一篇不錯的文章。希望大家能夠得到一些啟示或共鳴。歡迎大家發表自己在架構設計方面的觀點。
我們期待自己成為一個優秀的軟件模型設計者,但是,要怎樣做,又從哪里開始呢?將下列原則應用到你的軟件工程中,你會獲得立桿見影的成果。
1. 人遠比技術重要 你開發軟件是為了供別人使用,沒有人使用的軟件只是沒有意義的數據的集合而已。許多在軟件方面很有成就的行家在他們事業的初期卻表現平平,因為他們那時侯將主要精力都集中在技術上。顯然,構件(components),EJB(Enterprise Java Beans)和代理(agent)是很有趣的東西。但是對于用戶來說,如果你設計的軟件很難使用或者不能滿足他們的需求,后臺用再好的技術也于事無補。多花點時間到軟件需求和設計一個使用戶能很容易理解的界面上。
2. 理解你要實現的東西 好的軟件設計人員把大多數時間花費在建立系統模型上,偶爾寫一些源代碼,但那只不過是為了驗證設計過程中所遇到的問題。這將使他們的設計方案更加可行。
3. 謙虛是必須的品格 你不可能知道一切,你甚至要很努力才能獲得足夠用的知識。軟件開發是一項復雜而艱巨的工作,因為軟件開發所用到的工具和技術是在不斷更新的。而且,一個人也不可能了解軟件開發的所有過程。在日常生活中你每天接觸到的新鮮事物可能不會太多。但是對于從事軟件開發的人來說,每天可以學習很多新東西(如果愿意的話)。
4. 需求就是需求 如果你沒有任何需求,你就不要動手開發任何軟件。成功的軟件取決于時間(在用戶要求的時間內完成)、預算和是否滿足用戶的需求。如果你不能確切知道用戶需要的是什么,或者軟件的需求定義,那么你的工程注定會失敗。
5. 需求其實很少改變,改變的是你對需求的理解 Object ToolSmiths公司(www.objecttoolsmiths.com)的Doug Smith常喜歡說:“分析是一門科學,設計是一門藝術”。他的意思是說在眾多的“正確”分析模型中只存在一個最“正確”分析模型可以完全滿足解決某個具體問題的需要(我理解的意思是需求分析需要一絲不茍、精確的完成,而設計的時候反而可以發揮創造力和想象力 - 譯者注)。
如果需求經常改動,很可能是你沒有作好需求分析,并不是需求真的改變了。
你可以抱怨用戶不能告訴你他們想得到什么,但是不要忘記,收集需求信息是你工作。
你可以說是新來的開發人員把事情搞得一團糟,但是,你應該確定在工程的第一天就告訴他們應該做什么和怎樣去做。 如果你覺得公司不讓你與用戶充分接觸,那只能說明公司的管理層并不是真正支持你的項目。
你可以抱怨公司有關軟件工程的管理制度不合理,但你必須了解大多同行公司是怎么做的。
你可以借口說你們的競爭對手的成功是因為他們有了一個新的理念,但是為什么你沒先想到呢?
需求真正改變的情況很少,但是沒有做好需求分析工作的理由卻很多。
6. 經常閱讀 在這個每日都在發生變化的產業中,你不可能在已取得的成就上陶醉太久。
每個月至少讀2、3本專業雜志或者1本專業書籍。保持不落伍需要付出很多的時間和金錢,但會使你成為一個很有實力的競爭者。
7. 降低軟件模塊間的耦合度 高耦合度的系統是很難維護的。一處的修改引起另一處甚至更多處的變動。
你可以通過以下方法降低程序的耦合度:隱藏實現細節,強制構件接口定義,不使用公用數據結構,不讓應用程序直接操作數據庫(我的經驗法則是:當應用程序員在寫SQL代碼的時候,你的程序的耦合度就已經很高了)。
耦合度低的軟件可以很容易被重用、維護和擴充。
8. 提高軟件的內聚性 如果一個軟件的模塊只實現一個功能,那么該模塊具有高內聚性。高內聚性的軟件更容易維護和改進。
判斷一個模塊是否有高的內聚性,看一看你是否能夠用一個簡單的句子描述它的功能就行了。如果你用了一段話或者你需要使用類似“和”、“或”等連詞,則說明你需要將該模塊細化。
只有高內聚性的模塊才可能被重用。
9. 考慮軟件的移植性 移植是軟件開發中一項具體而又實際的工作,不要相信某些軟件工具的廣告宣傳(比如java 的宣傳口號write once run many 譯者注)。
即使僅僅對軟件進行常規升級,也要把這看得和向另一個操作系統或數據庫移植一樣重要。
記得從16位Windows移植到32位windows的“樂趣”嗎 ?當你使用了某個操作系統的特性,如它的進程間通信(IPC)策略,或用某數據庫專有語言寫了存儲過程。你的軟件和那個特定的產品結合度就已經很高了。
好的軟件設計者把那些特有的實現細節打包隱藏起來,所以,當那些特性該變的時候,你的僅僅需要更新那個包就可以了。
10. 接受變化 這是一句老話了:惟一不變的只有變化。
你應該將所有系統將可能發生的變化以及潛在需求記錄下來,以便將來能夠實現。 通過在建模期間考慮這些假設的情況,你就有可能開發出足夠強壯且容易維護的軟件。設計強壯的軟件是你最基本的目標。
11. 不要低估對軟件規模的需求 Internet 帶給我們的最大的教訓是你必須在軟件開發的最初階段就考慮軟件規模的可擴充性。
今天只有100人的部門使用的應用程序,明天可能會被有好幾萬人的組織使用,下月,通過因特網可能會有幾百萬人使用它。
在軟件設計的初期,根據在用例模型中定義的必須支持的基本事務處理,確定軟件的基本功能。然后,在建造系統的時候再逐步加入比較常用的功能。
在設計的開始考慮軟件的規模需求,避免在用戶群突然增大的情況下,重寫軟件。
12. 性能僅僅是很多設計因素之一 關注軟件設計中的一個重要因素--性能,這好象也是用戶最關心的事情。一個性能不佳的軟件將不可避免被重寫。
但是你的設計還必須具有可靠性,可用性,便攜性和可擴展性。你應該在工程開始就應該定義并區分好這些因素,以便在工作中恰當使用。性能可以是,也可以不是優先級最高的因素,我的觀點是,給每個設計因素應有的考慮。
13. 管理接口 “UML User Guide”(Grady Booch,Ivar Jacobson和Jim Rumbaugh ,Addison Wesley, 1999)中指出,你應該在開發階段的早期就定義軟件模塊之間的接口。
這有助于你的開發人員全面理解軟件的設計結構并取得一致意見,讓各模塊開發小組相對獨立的工作。一旦模塊的接口確定之后,模塊怎樣實現就不是很重要了。
從根本上說,如果你不能夠定義你的模塊“從外部看上去會是什么樣子”,你肯定也不清楚模塊內要實現什么。
14. 走近路需要更長的時間 在軟件開發中沒有捷徑可以走。 縮短你的在需求分析上花的時間,結果只能是開發出來的軟件不能滿足用戶的需求,必須被重寫。
在軟件建模上每節省一周,在將來的編碼階段可能會多花幾周時間,因為你在全面思考之前就動手寫程序。
你為了節省一天的測試時間而漏掉了一個bug,在將來的維護階段,可能需要花幾周甚至幾個月的時間去修復。與其如此,還不如重新安排一下項目計劃。
避免走捷徑,只做一次但要做對(do it once by doing it right)。
15. 別信賴任何人 產品和服務銷售公司不是你的朋友,你的大部分員工和高層管理人員也不是。
大部分產品供應商希望把你牢牢綁在他們的產品上,可能是操作系統,數據庫或者某個開發工具。
大部分的顧問和承包商只關心你的錢并不是你的工程(停止向他們付款,看一看他們會在周圍呆多長時間)。
大部分程序員認為他們自己比其他人更優秀,他們可能拋棄你設計的模型而用自己認為更好的。
只有良好的溝通才能解決這些問題。
要明確的是,不要只依靠一家產品或服務提供商,即使你的公司(或組織)已經在建模、文檔和過程等方面向那個公司投入了很多錢。
16. 證明你的設計在實踐中可行 在設計的時候應當先建立一個技術原型, 或者稱為“端到端”原型。以證明你的設計是能夠工作的。
你應該在開發工作的早期做這些事情,因為,如果軟件的設計方案是不可行的,在編碼實現階段無論采取什么措施都于事無補。技術原型將證明你的設計的可行性,從而,你的設計將更容易獲得支持。
17. 應用已知的模式 目前,我們有大量現成的分析和設計模式以及問題的解決方案可以使用。
一般來說,好的模型設計和開發人員,都會避免重新設計已經成熟的并被廣泛應用的東西。 http://www.ambysoft.com/processPatternsPage.html 收藏了許多開發模式的信息。
18. 研究每個模型的長處和弱點 目前有很多種類的模型可以使用,用例捕獲的是系統行為需求,數據模型則描述支持一個系統運行所需要的數據構成。你可能會試圖在用例中加入實際數據描述,但是,這對開發者不是非常有用。同樣,數據模型對描述軟件需求來說是無用的。每個模型在你建模過程中有其相應的位置,但是,你需要明白在什么地方,什么時候使用它們。
19. 在現有任務中應用多個模型 當你收集需求的時候,考慮使用用例模型,用戶界面模型和領域級的類模型。
當你設計軟件的時候,應該考慮制作類模型,順序圖、狀態圖、協作圖和最終的軟件實際物理模型。
程序設計人員應該慢慢意識到,僅僅使用一個模型而實現的軟件要么不能夠很好地滿足用戶的需求,要么很難擴展。
20. 教育你的聽眾 你花了很大力氣建立一個很成熟的系統模型,而你的聽眾卻不能理解它們,甚至更糟-連為什么要先建立模型都不知道。那么你的工作是毫無意義的。 教給你開發人員基本的建模知識;否則,他們會只看看你畫的漂亮圖表,然后繼續編寫不規范的程序。
另外, 你還需要告訴你的用戶一些需求建模的基礎知識。給他們解釋你的用例(uses case)和用戶界面模型,以使他們能夠明白你要表達地東西。當每個人都能使用一個通用的設計語言的時候(比如UML-譯者注),你的團隊才能實現真正的合作。
21. 帶工具的傻瓜還是傻瓜 你給我CAD/CAM工具,請我設計一座橋。但是,如果那座橋建成的話,我肯定不想當第一個從橋上過的人,因為我對建筑一竅不通。
使用一個很優秀的CASE工具并不能使你成為一個建模專家,只能使你成為一個優秀CASE工具的使用者。成為一個優秀的建模專家需要多年的積累,不會是一周針對某個價值幾千美元工具的培訓。一個優秀的CASE工具是很重要,但你必須學習使用它,并能夠使用它設計它支持的模型。
22. 理解完整的過程 好的設計人員應該理解整個軟件過程,盡管他們可能不是精通全部實現細節。軟件開發是一個很復雜的過程,除了編程、建模、測試等你擅長工作外,還有很多工作要做。好的設計者需要考慮全局。必須從長遠考慮如何使軟件滿足用戶需要,如何提供維護和技術支持等。
23. 常做測試,早做測試 如果測試對你的軟件來說是無所謂的,那么你的軟件多半也沒什么必要被開發出來。建立一個技術原型供技術評審使用,以檢驗你的軟件模型。在軟件生命周期中,越晚發現的錯誤越難修改,修改成本越昂貴。盡可能早的做測試是很值得的。
24. 把你的工作歸檔 不值得歸檔的工作往往也不值得做。歸檔你的設想,以及根據設想做出的決定;歸檔軟件模型中很重要但不很明顯的部分。給每個模型一些概要描述以使別人很快明白模型所表達的內容。
25. 技術會變,基本原理不會 如果有人說“使用某種開發語言、某個工具或某某技術,我們就不需要再做需求分析,建模,編碼或測試”。不要相信,這只說明他還缺乏經驗。拋開技術和人的因素,實際上軟件開發的基本原理自20世紀70年代以來就沒有改變過。你必須還定義需求,建模,編碼,測試,配置,面對風險,發布產品,管理工作人員等等。
軟件建模技術是需要多年的實際工作才能完全掌握的。好在你可以從我的建議開始,完善你們自己的軟件開發經驗。以雞湯開始,加入自己的蔬菜。然后,開始享受你自己的豐盛晚餐吧。
作者: Scott Ambler著 樂林峰 譯 來源: umlchina 風之語 轉載
當你使用CASE工具畫出包,類,屬性,方法和關系時,AndroMDA的“概貌”就形成了。然后,你把模型保存為XMI格式,并用AndroMDA和XDoclet產生整個組件模型的Java源代碼。AndroMDA和XDoclet都可以和著名的構建工具Ant進行集成。你通常會使用Ant的命令行版本,但也可以在IDE如Eclipse或JBuilder中使用Ant。無論是哪一種方式,你都要使用自己定制的Ant構建腳本,并在腳本中把AndroMDA定義為其中的一個Task。 在CASE工具中用UML建模 你可以使用UML的圖形符號為現實世界中的事物建模。例如,考慮一個汽車租賃系統,用于管理客戶,司機,汽車和租賃合同。這個系統UML模型的類圖可能是如下的樣子:

將模型保存為XMI格式。某些CASE工具把這稱為“export”,用于區別它本身私有的格式。 代碼生成器 從XMI模型中產生代碼,Ant構建腳本經過以下的步驟:
- Ant Task讀入XMI格式的UML模型,并在內存中生成抽象的語法樹(abstract syntax tree),其中包含包,類,屬性,方法和關系的信息。
- 然后,使用Velocity模板處理引擎來處理entity bean,session bean,Hibernate類或別的代碼生成模板,所有的模板都基于從CASE工具中產生的抽象語法樹。它使用一個腳本helper facade來屏蔽UML元模型的復雜性,因此模板的開發者可以使用容易理解的API來為腳本寫代碼。這些步驟會產生一些源代碼文件。
- 最后,Ant腳本調用XDoclet中的<ejbDoclet>或<hibernateDoclet> Task。對于EJB,XDoclet task讀入所有的bean類信息并生成bean的接口和部署配置文件。對于Hibernate,XDoclet生成包含持久層映射信息的XML文件。
使用Cartridges定制輸出 到此為止,你可能以為AndroMDA是一個EJB或Hibernate JavaBean的生成器。其實,AndorMDA可以生成任何東西! 事實上,AndroMDA對于它生成的東西一無所知。它擁有一個稱為“cartridges”的可插入模塊。一個Cartridge由一套定義生成格式的模板文件組成。目前,AndroMDA包括四個cartridge:
- andromda-java - 生成一般的Java源代碼。
- andromda-ejb - 生成EJB。
- andromda-hibernate - 生成Hibernate ORM工具的持久層類。
- andromda-struts - 生成Jakarta Struts的web頁面,form bean和action類。
你可以選擇使用哪一個cartridge來產生你的應用框架。你也可以編寫你自己的cartridge - 一旦你理解了cartridge的基礎知識及其XML描述文件,編寫一個新的cartridge非常容易! AndroMDA核心自動檢測安裝在類路徑下的cartridge。如需要了解更多cartridge的信息,請參見本網站的其他文檔。 EJB Cartridge生成代碼的例子 從上面汽車租賃系統模型的客戶模型部分,AndroMDA(使用andromda-ejb)和XDoclet將為你產生下面的代碼。Bean類使用
標記,其他類使用
標記。你可以點擊文件名查看文件的內容。
編寫業務方法 你可能知道,使用代碼生成器并沒有完成了所有的工作。編寫Bean的主體即業務邏輯是留給你的工作。AndroMDA為你構建了一個應用框架,你需要往里面填充代碼。這些所謂的“implementation classes”來自bean類,是類繼承結構樹上的葉子。AndroMDA一次性地產生這些代碼并不再修改它們。這能夠確保手工編寫的代碼不被代碼生成器覆蓋。 因此,在實現類中實現你的業務方法,并啟動Ant構建腳本用于編譯Java文件的其他task,并把編譯好的class文件打包到一個ejb-jar文件中。jar文件當然也包含了生成的部署配置文件。 最后的工作 最后的工作當然是發布到應用服務器上。以JBoss為例,只需簡單地將jar文件復制到JBoss的部署路徑中即可。
在中國的同行中經常看到:要么不重視軟件架構,要么過分重視乃至捧為天書。如果要是碰到一個不懂技術的項目經理強行推行新技術有會有何種效果呢?
其實在做系統架構時,有時候會常常忽略以下幾點:
1:軟件的架構在大的方向上是固定的。
這種固定依據某些基本固定的軟件模式(包括設計模式、編碼模式或者某些特定的約定)來強化和固定。這使得軟件開發在某種程度上具有某些可以明顯看得到的風格,這個風格被整個的項目貫穿和堅持,這樣當我們進入通常可怕的維護或者調整的時候,我們不會害怕我們在很多種不同的實現中常常迷失了方向。
2:軟件的架構在具體的應用中可以適度的可控靈活。
毫無疑問,軟件設計開發不可能沒有例外,在某種程度上保留一些適度的靈活時必要的。一方面,它符合軟件開發的實際;一方面,適度的可控靈活體現了一種對實現者的尊重和信任。然而,如何實現可控的靈活呢?通常,我認為可以考慮有限種類的設計選擇并通過有色彩的圖形來表明這種可選擇性。但即便如此,設計者很重要的要考慮這些不同選擇之間的關系,以及這些選擇和整體設計的兼容性,這個時候,面向接口的設計和適度的“粘合”設計是必要的。
3:架構設計的支撐。
架構設計通常會涉及到一些支撐設計,這些設計和實現水準直接的體現了系統的最有價值的部分,更細的劃分我們應該可以看到性能和結構相關的部分,以及必要的基礎類。通常,作為設計人員,我們應該能夠設計并實現系統的性能、結構、擴展、粘合等部分的工作,這部分的工作通常不應該離開設計人員的控制和把握,這些代碼的書寫或者至少積極的關注是設計人員必要的素質:我們不應該讓更多的看到我們無法寫出代碼來(我也反對沒有分工什么都做的設計人員!),實際上,這是軟件最困難也是最有樂趣的地方。特別是在測試結果中發現這些設計實現帶來的性能的極大提高的時候是非常有成就感的事情。至于基礎類,應該是盡可能的減少依賴和耦合的。架構設計的支撐要盡可能的對客戶程序員隱藏不必要的中間細節,對基礎類要盡量簡單、穩定并真正需要。
通常,新興的技術會用在架構設計的支撐設計里面并被封裝以隱藏具體的實現,而通盤應用新興技術的風險是巨大的,并且對人員的獲得也是問題。有些技術是可以提供替代技術的,一些新興的技術實現也是可以參考的(但未必采用她的實現)。要記住軟件開發是需要速度、質量、可維護而不是技術表演,這個度應該由分析設計人員負責任的來把握。
4:面向業務還是面向頁面的。
也許這種說法會招致一些人的反對,認為自然而然的應該是前者,然而,實際的情況是,我們常常看到打著業務的幌子實現為面向頁面的系統,原因很簡單:后者更加的“簡單”并似乎有更少的代碼和工作量。這在某種程度上是對的。然而,區分這兩種不同的設計是必要的,盡管你也可能使用了MVC2的架構,但你可以做出面向頁面的設計的。觀察我們的軟件開發,最先提交的代碼未必是最少的代價的代碼:我們常常可以發現一些項目總是在那些不起眼的地方不斷的“修改”,我們的程序員因此好像很忙,但對我們的項目對公司來說這是糟糕的不必要開銷。因此,考慮這兩種可能的情況,在做出選擇之前加以思考是必要的。
5:用團隊和別人的眼光考慮問題。
實際上,每個項目都是有所差異的,特別是人的差異。很糟糕的是,我們通常不得不面對人力資源的極大壓力,特別是這些人之間常常都沒有共事的經驗也就是常常是臨時組成的,而這些人員也通常也缺乏一個軟件開發的基本共識:對標準的遵從哪怕是最簡單的Java編碼規范和對自己提交的產品的簡單備注和測試都是缺乏的而通常又沒有達到代碼就是文檔的水準。在這個時候,用團隊和別人的眼光考慮問題就是必要的,這實際上就是取技術上的“交集”,也就是走簡單的路線。如果沒有選擇的時候,培訓工作就是非常必要的。
用團隊和別人的眼光考慮問題也會有其它的問題,特別是當項目壓力如進度壓力等來臨的時候或者項目成員根本不考慮公司整體和長期利益的時候,這個問題很突出,有時候作為分析設計人員你甚至很難解決,特別是你面臨剛才我所提到的“沒有Java開發實際經驗甚至缺乏軟件開發經驗的項目經理試圖控制技術的時候”更加如此。
軟件架構的設計說起來簡單,也可以說起來復雜,然而,如何把事情做到簡單并且把其中的針對性能、分層、粘合、擴展等處理好,并提供可控的靈活性不是容易的。通常,只有多一些經驗和教訓并能夠在軟件代碼上加以實現核心的才可能成為好的分析設計人員。
在此演練中,您將在 Sun Java? Studio Creator 應用程序開發環境 (IDE) 中創建和部署一個簡單的 Web 應用程序
"travel center"。向頁面中添加兩個組件,并將那些數據識別組件綁定到本地數據庫。然后,生成應用程序并將其
部署到本地應用服務器,在客戶機 Web 瀏覽器上運行該應用程序。
內容
? 創建項目
? 添加 Dropdown List 組件
? 將組件連接到數據庫
? 運行 Web 應用程序
? 添加 Data Table
? 修改 SQL 查詢
? 控制顯示的行
要完成此演練,系統上應該已經安裝了 IDE,并且您已經閱讀了 Java Studio Creator 入門 教程。
創建項目
開發 Web 應用程序從創建項目開始。就像在入門教程中學習的那樣,項目是 IDE 中的基本工作單元。項目包含
組成應用程序的所有源代碼和資源。
1. 在“歡迎”屏幕上單擊“創建新項目”。
2. 在“新建項目”對話框的“名稱”文本字段中,鍵入 TravelCenter。
3. 選擇“缺省 J2EE Web 應用程序”模板(如果尚未選定),然后單擊“確定”。
通過這些步驟會創建兩個重要的文件,在本教程的其他部分中也將用到這兩個文件。
? Page1.jsp-JavaServer Pages? 中包含組成 Web 應用程序的組件。最初,在應用程序中只有一個 JSP?
頁,但是隨后您可以添加更多的頁面。
? Page1.java-包含頁面狀態并使其在不同的呈現中保持一致的 JavaBeans? Bean。缺省情況下代碼是不
可見的,但是您可以通過右鍵單擊頁面,然后在上下文菜單中選擇“查看 Page1 Java 類”來顯示它。
添加 Dropdown List 組件
接下來,向頁面中添加 Dropdown List 組件。
1. 在組件面板中,選擇“JSF”>“JSF 標準組件”,然后將 Dropdown List 組件拖到頁面上。
Dropdown List 組件將出現在 Page1.jsp 頁面上。您可以通過使用選擇句柄來調整組件的大小,也可以
1
Sun Java Studio Creator
將組件移動到新位置。
2. 右鍵單擊頁面背景,然后在上下文菜單中選擇“查看 Page1 Java 類”。
會在源編輯器中打開頁面的 JavaBeans 源代碼。
3. 在“選擇類成員”下拉列表中選擇 "dropdown1" 以導航到實例變量聲明。(“選擇類成員”下拉列表位于
源編輯器工具欄中。)
初始化 Dropdown List 組件的 Java 代碼已添加到 Page1 類實現。
private HtmlSelectOneMenu dropdown1 = new HtmlSelectOneMenu();
將組件連接到數據庫
在此部分中,使 Dropdown List 組件可以從數據庫表獲得項。
1. 單擊源編輯器頂部的 Page1.jsp 標簽以查看頁面。
2. 從“服務器導航”中,將“數據源”> "Travel" >“表”> "PERSON" 節點拖放到 Dropdown List 組件的上
面。
將出現一個對話框,且 personRowSet 已添加到非可視組件托盤中。
注如果 PointBase Embedded 數據庫沒有運行,則您將看到一個“錯誤”對話框,告訴您這一情況。如果看
到此對話框,請關閉“錯誤”對話框,在“服務器導航”中右鍵單擊“PointBase 數據庫服務器”節點,
然后在上下文菜單中選擇“啟動 PointBase”。然后,右鍵單擊“數據源”>
"Travel",并從上下文菜單中選擇 “刷新”?,F在,您應該能夠定位到 "Travel" 數據源節點。
3. 單擊“填充列表”。
因為 PERSON.NAME 列屬于 SQL 類型 varchar,在 Dropdown List 組件中將顯示文本 "abc",指示所顯
示的數據是一個字符串。
注如果沒看到這個對話框,是因為 PERSON 節點沒有被直接放到 Dropdown List 組件的上面。在這種情況
下,在執行下一步時,請確保如圖 1 所示選定了 PERSON.PERSONID 和 PERSON.NAME 列。
4. 右鍵單擊 Dropdown List 組件,然后從上下文菜單中選擇“從數據庫填充列表”。
“值字段”被綁定到 PERSON.PERSONID 列,該列是 PERSON 表的主鍵。此字段提供由 JSF 組件的
getValue() 方法返回的值。另一方面,“顯示字段”被綁定到 PERSON.NAME 列,是組件運行時所顯
示的內容。
5. 單擊“確定”。
運行 Web 應用程序
現在,您可以部署和運行 Web 應用程序了。IDE 附帶有一個已經安裝的本地部署服務器:
? Sun Java? System Application Server Platform Edition 8
部署服務器是作為“服務器導航”中“部署服務器”節點下的一個節點安裝的。通過部署服務器的上下文菜單
(可通過右鍵單擊它進行訪問),可以啟動或停止它。
部署和運行 Web 應用程序
1. 單擊工具欄中的“全部保存”按鈕。
2. 單擊工具欄中的“運行項目”按鈕。
IDE 將生成、部署和運行 TravelCenter 應用程序。首先,“生成輸出”窗口出現在 IDE 布局的底部。有關
編譯的信息和部署準備將輸出到此窗口。(如果在生成時出現問題,請首先檢查“生成輸出”窗口。)接
下來,將打開一個對話框,其中顯示部署的狀態。
部署之后,將使用 URL
http://localhost:18080/travelcenter/ 為應用程序打開一個新的 Web 瀏覽器
窗口。使用 PERSON 表的 NAME 列中的數據填充下拉列表。
添加 Data Table
接下來,向應用程序中添加一個 Data Table 組件,并將該組件與數據庫表相連。
1. 在組件面板中,單擊“JSF 標準組件”,將 Data Table 拖至頁面,并將它放置在 Dropdown List 組件的下
面。
2. 拖動“數據源”> "Travel" >“表”> "TRIP" 節點,并將其放在 Data Table 上。確保整個 Data Table 組件的輪
廓為藍色時放置節點。如果只有列或列標題的輪廓為藍色,請將節點在組件內四處移動,直到整個組件的
輪廓為藍色。
如果將節點放在列或列標題上,會出現“選擇目標”對話框,而且 tripRowSet 已添加到非可視組件托
盤中。確保選中了 "dataTable1" 單選按鈕,然后單擊“確定”關閉對話框。
3. 右鍵單擊 Data Table 組件,然后選擇“表布局”。
注如果沒有選定 Data Table 組件,或者選定了它的其中一個子組件(在本例中是列),則在右鍵單擊 Data
Table 時,將出現另外的上下文菜單。在這種情況下,請選擇 "dataTable1" >“表布局”。您可以按 Esc
鍵選擇當前所選組件的父組件。
出現“表布局”對話框。這兩個列表表明哪些列可用于顯示以及正在顯示哪些內容。將 TRIP 表放在 Data
Table 組件上時,將選擇所有可用的列進行顯示。
4. 選擇“顯示”列表中的第一列 (TRIP.TRIPID),然后單擊 "<" 按鈕。
將從“顯示”列表中移除該列。
5. 移除 TRIP.PERSONID 和 TRIP.TRIPTYPEID 列。
仍然出現在“顯示”列表中的三列:
? TRIP.DEPDATE
? TRIP.DEPCITY
? TRIP.DESTCITY
使用數據綁定組件訪問數據庫 ?
Sun Java Studio Creator
6. 單擊“確定”。
現在,Data Table 組件中有三個顯示列。
修改 SQL 查詢
在此部分中,將修改 TRIP 行集對象中的 SQL 查詢,以便查詢返回 TRIPTYPE 表中的數據。您還將修改 Data
Table 組件以顯示新列。
1. 右鍵單擊非可視組件托盤中的 tripRowSet,然后選擇“編輯行集查詢”。
在編輯器窗格中將出現查詢編輯器。標簽的名稱是 tripRowSet。
2. 右鍵單擊設計視圖(見圖 4),然后選擇“添加表”。
3. 選擇 TRAVEL.TRIPTYPE 表,然后單擊“確定”。
將出現另一個表格圖,在兩個表格圖之間有一個鏈接。
4. 在指示的表中取消選中以下復選框:
? TRIP 表中的 TRIPID
? 兩個表中的 TRIPTYPEID
會從結果集中刪除上述列。同時會修改源視圖中的 SQL 查詢以反映這些更改。
4 使用數據綁定組件訪問數據庫 ?
圖 2 顯示的列
圖 3 第 1 列處于選定狀態的 Data Table
Sun Java Studio Creator
5. 選擇 Page1.jsp 標簽以返回到可視編輯器。
6. 右鍵單擊 Data Table,然后選擇“表布局”。
將出現“表布局”對話框。由于您已經更改了行集的 SQL 查詢,因此有更多可以顯示的列。
7. 將 TRIPTYPE.DESCRIPTION 列添加到“顯示”列表中。
8. 單擊“確定”。
第四列將出現在 Data Table 組件中。
控制顯示的行
在上一部分中將 TRIP 表放在 Data Table 組件上時,IDE 使用返回表中所有列的所有行的 SQL 查詢創建了一個
行集對象。如果此時部署應用程序,則數據表將包含 TRIP 表中的所有行程信息。
假定您僅希望顯示其名字出現在 Dropdown List 組件中人員的行程信息。您必須通過編輯 TRIP 行集對象的缺省查
詢,在 Dropdown List 組件和 Data Table 組件之間創建主從關系 (Master-Detail)。
1. 雙擊 tripRowSet 對象打開查詢編輯器。
2. 在查詢編輯器的設計網格(電子表格)中,右鍵單擊設計網格 PERSONID 行中的“條件”單元格,然后
選擇“添加查詢條件”。
使用數據綁定組件訪問數據庫 ?
圖 4 查詢編輯器
設計視圖
設計網格
源代碼
Sun Java Studio Creator
3. 將“比較”下拉菜單設置為“=等于”,并選擇“參數”單選按鈕。
4. 單擊“確定”。
在 PERSONID 的“條件”列中您會看到 "=?",它在 SQL 查詢中添加了以下 WHERE 子句:
WHERE TRAVEL.TRIP.PERSONID = ?
5. 通過選擇 Page1.jsp 標簽,返回到可視編輯器,然后雙擊 Dropdown List 組件。
Page1 類的源代碼在編輯器區域中打開,且光標位于 dropdown1_processValueChange() 方法主體
內。此事件處理程序方法存根 (Stub) 是在您首次雙擊 Dropdown List 組件時創建的。
6. 從“組件面板”>“代碼片段”>“演示”拖動 Travel dropdown 代碼片段,將其放在
dropdown1_processValueChange() 方法體中。
6 使用數據綁定組件訪問數據庫 ?
圖 5 “添加查詢條件”對話框
Sun Java Studio Creator
public void dropdown1_processValueChange(ValueChangeEvent vce) {
// User event code here...
try {
dataTable1Model.setObject(1, dropdown1.getValue());
dataTable1Model.execute();
} catch (Exception e) {
log("person change exception", e);
error(“Exception changing person id:”+e);
} // end try catch
}
這段代碼將下拉列表的值綁定到為 dataTable1Model 準備的 SQL 語句中的參數上。
7. 在 Page1 類中找到 Page1() 構造函數。
8. 從“組件面板”>“代碼片段”>“演示”拖動 Travel initialization 代碼片段,并將其放在 Page1() 構造
函數實現的結尾處。
public Page1() {
// other lines of code omitted
catch ( Exception e) {
log("Page1 Initialization Failure", e);
throw new FacesException(e);
}
// Additional user provided initialization code
try {
personRowSet.execute();
personRowSet.next();
dataTable1Model.setObject(1, personRowSet.getObject("PERSONID"));
} catch (Exception ex) {
throw new FacesException(ex);
} // end try catch
}
這段代碼將把下拉列表中當前選定 NAME 的 PERSONID 值綁定到為 dataTable1Model 準備的 SQL 語句
中的參數上。
9. 通過選擇 Page1.jsp 標簽返回到可視編輯器。
10.右鍵單擊 Dropdown List 組件,然后選擇“更改時自動提交”。
在屬性表單中,以下代碼將出現在 "Javascript" > "onchange" 屬性中:
this.form.submit();
現在,當用戶在運行的 Web 應用程序中更改下拉列表選擇時,將重新提交和更新頁面。
11.單擊工具欄上的“全部保存”。
12.單擊工具欄上的“運行項目”。
將重新生成和部署 Web 應用程序。在下拉列表中選擇另一個名字,您會注意到更新了數據表。
使用數據綁定組件訪問數據庫 ? 2004 6 年月 7
Sun Java Studio Creator
請參見
? Java Studio Creator 入門
本文下載地址: http://mail.yl.gov.cn/ftp/yy/jscb2005.rar
基于JSF的Ajax實現AjaxFaces發布了1.0版本。
AjaxFaces項目是由CyberXP.net提供的。該項目使JSF的UI組件具備了Ajax的能力,可以觸發Ajax過程,也可以在Ajax處理過程中更新界面組件。AjaxFaces還提供了一組功能性的組件,包括樹、日歷等,這些組件都內建了Ajax功能。
下載地址:http://cyberxp.net/
作者: Programmer's Life
B/S 作為如今最為流行的體系結構模式,也是受到了廣大開發人員以及客戶的認同,其開發模式也在不斷的發展著,在這里主要就 Java B/S 的開發模式做一番回顧和探討,也算是自己對于 Java B/S 開發模式的一種總結。
Jsp+Jdbc
在 B/S 開發中最簡單的一種開發模式是頁面 + 邏輯處理,映射到技術上反應出來的有 Jsp+Jdbc ,在基于這類的實現中在 View 層也就是 jsp 頁面上負責數據的顯示、邏輯處理,結合 jdbc 完成數據的持久化,在小型的項目中,人們確實發現這種方式是最為方便的,但在復雜的項目以及需求不斷變化的項目中,人們慢慢的發現這種方式造成了不少的問題,首先是調試的問題,想想在一個 jsp 頁面中進行排錯是多么的困難,其次是修改的問題,為了滿足用戶需求的一個小小的變化,都需要去改不少的頁面,而且很多時候由于寫的時間長了,自己都需要回憶很久才能想起是怎么回事,更不用說如果人員流動了會怎么樣,同時還帶來開發效率的問題,由于需要缺少足夠的調試的支持,需要較為熟練的開發人員才能快速的完成,對于一般的人員來說需要一定的適應和學習過程,當然伴隨而來的還有諸如修改界面的時候一不小心少 copy 了點代碼什么造成的錯,最大的問題可能還是重用的問題,通常會造成 N 多同樣的代碼在頁面上 copy 來 copy 去的,總結下來在這種模式下有幾個比較重大的問題就是:
1、 調試問題。
2、 維護問題,顯示和邏輯處理在一起導致了修改顯示的時候較為困難,至于修改代碼則因為之前的調試問題導致了困難,同時由于邏輯均在頁面上后期接手人員需要一段時間去理解。
3、 代碼重用性問題。
但同樣它還是存在優點的,那就是可以很快的上手,但由于調試和維護性問題確實太大了,所以在現在也是基本不再采用這種方式了。
Jsp+JavaBean
在經歷了 jsp+jdbc 階段后,開始考慮怎么樣去解決上面三個問題,這個時候就誕生了諸 JSP+JavaBean 這樣的技術體系,在這個體系中由 jsp 頁面負責顯示以及接收頁面請求,并調用相應的 JavaBean 來完成邏輯處理,在獲取其返回的處理數據后轉到相應的頁面進行顯示。在這樣的技術體系中,由于邏輯是由 JavaBean 來完成的,可以對其進行調試了,代碼的重用性一定程度上也得到了提高。剛開始的時候用這樣的技術體系確實發現比以前用 jsp+jdbc 爽了很多,但隨著用多了,慢慢又發現了問題,那就是在頁面中需要編寫對于頁面請求數據的獲取,還得根據請求去調用相應的 javabean ,并根據 javabean 的處理結果轉入相應的頁面,這同樣造成了修改的麻煩,畢竟是去頁面上修改這些邏輯,總結下來在這種模式下有比較重大的問題就是:
1、 代碼重用性以及維護性問題。但這里的代碼重用性問題和 jsp+jdbc 的就不同,在邏輯處理部分現在已經可以重用了,但現在在各個頁面就不得不重復的寫獲取頁面請求的參數、相應的調用 Model 、根據 Model 的處理結果轉發頁面,這樣的話就導致了在改的時候需要到處去找,造成了維護的復雜。
2、 系統結構不清晰。畢竟仍然是在頁面控制整個響應頁面事件的處理流程,這個時候就造成了很多頁面中出現完全相同的 jsp 代碼,而且控制代碼在頁面,仍然是不便操作,例如對于 JavaBean 的調用等,而且由于獲取 javabean 的數據需要轉發的緣故,其實通常就是在最終的顯示頁面上加上上面的控制事件處理流程的代碼,并沒有真正的做到顯示和處理的分離。
同樣,它的優點在于分離了顯示和業務邏輯處理,增強了可調試以及維護性,而且也是很容易上手的,對于小型項目來說仍然是可選的方案之一。
基于 MVC Framework
在經歷了上面的 Jsp+JavaBean 后,我們發現其實現在最需要的就是在 jsp 、 javabean 之間能有個東西自動完成頁面請求數據的封裝、根據請求調用相應的 javabean 、同時根據 javabean 的處理結果返回至相應的 View ,有了這樣的思想后,發現 smalltalk 中的 MVC 思想很適合這種場景,于是便在 Java B/S 開發中引入了 MVC 思想,在這里也簡單的介紹下 MVC 思想, MVC 強調 View 和 Model 的分離, View 所面對的是 Controller ,由 Controller 負責與 Model 進行交互, View 只負責顯示頁面以及顯示邏輯的處理,顯示邏輯指的是諸如第一行要顯示藍色、第二行要顯示紅色這樣的顯示方面的處理, Controller 負責接受頁面請求,并將其請求數據進行封裝,同時根據請求調用相應的 Model 進行邏輯處理,在 Model 處理后返回結果數據到 Controller , Controller 將根據此數據調用相應的 View ,并將此數據傳遞給 View ,由 View 負責將數據進行融合并最終展現。 MVC 帶來的優點很明顯的體現出來了,基于一個這樣的 MVC Framework 的話開發人員可以按照一種固定的模式進行開發,規范了整個開發過程,提高了質量以及系統結構的清晰性,并由于保證了 View/Model 的分離,使得一個 Model 可以對于多種顯示形式的 View ,需要的僅僅是去改變 View 和 Controller 。
按照 MVC 思想,最容易想到的實現方案莫過于 jsp+servlet+javabean ,在這里面 jsp 對應著 View , servlet 對應著 Controller , javabean 對應著 Model ,因為采用 servlet 可使用 servlet container 已經封裝好的頁面數據請求對象 HttpServletRequest ,這樣就省去了自己封裝頁面請求數據的工作,作為 Controller 同時還需要承擔根據請求調用對應的 javabean ,最簡單的做法無非就是在 Servlet 中直接根據某種邏輯 ( 諸如反射或接口 ) 調用相應的 bean 進行執行,之后將 HttpServletRequest 、 HttpServletResponse 作為參數傳入 javabean 進行處理, javabean 從 HttpServletRequest 中獲取請求數據,將返回的結果數據放入 HttpServletResponse ,整個過程結束后繼續由 Controller 接手進行處理,這個時候作為 Controller 的 servlet 將根據處理的結果返回相應的頁面,在這個模型使用時人們慢慢的發現了一個問題,那就是隨著 jsp 、 javabean 的變化造成了 controller 的不斷修改,需要修改其中調用相應 javabean 以及轉發相應頁面的部分,為了解決這個問題,首先想到的是應該分離根據請求調用相應 javabean 的步驟,這個時候采用了設計模式中的 front controller+application controller 的方法, front controller 負責接受頁面請求并進行封裝,同時將此數據對象傳遞至 application controller ,由 application controller 來負責調用相應的 bean ,這樣的設計其實都是遵循著一個設計原則,就是職責單一,通常實現 application controller 的模式是 Command 模式,在這種情況下 MVC Framework 的結構體系就演變成了 view+controller(front+application)+model 。
在完成了上述演變后慢慢又發現了一個問題,就是 model 依賴于了 httpservletrequest ,這樣造成的一個問題就是沒法測試,仍然要不斷重啟服務器來測試,當然與此同時的發展是 model 層的細化,細化成用于響應頁面請求的 action Layer+Domain Model Layer+Persistent Layer ,在這里不去討論后面層次的問題,因為作為 MVC Framework 它并不管你 Model 層是怎么個處理流程的。
慢慢也發現了另外一個問題,那就是變化經常要影響到 controller 的修改,于是便引入了采用配置文件的解決方法,編寫 action 的配置文件,在配置文件中控制根據 action 的返回結果轉入相應的 View ,這樣的話在將來需要改變的時候只需要去改變這個配置文件就可以了,保證了 Controller 的穩定,這是典型的設計中的重點考慮因素,分離變化和不變化的,讓變化造成的影響最小。
但在引入了上面的配置文件后,慢慢又發現了問題,那就是手寫配置文件總是容易出各種各樣的問題,這個時候采用圖形化的界面來生成配置文件的想法又有了,這也就造就了 page flow 的誕生,當然,這只是 page flow 的一小部分功能。
當然,隨著MVC的發展,也帶動了其他相關技術的發展,如異步請求/響應模式(ajax、amowa,^_^)等。
在 MVC 思想接受后開源界的 MVC Framework 也是如雨后春筍般的冒出,比較知名的有 struts 、 webwork 、 spring mvc 等,這些 MVC Framework 基本都已經做到了上面提及的 MVC 思想演變的一些需求,當然,即使現在的 MVC Framework 是做到了,但在使用這些 MVC Framework 的時候我們通常又開始違背 MVC 思想的基本要素,就是保持 View 僅僅是 View 的原則,所以我比較推薦在 View 使用 Velocity 這之類的東西作為 View ,盡量保持 View 的純潔性,任何技術的發展都是循序漸進的,不站在那個高度的時候是不知道前面還有什么樣的高山的,那么現在我們缺少的又是什么呢?現在的 MVC Framework 中還存在著什么不足呢?這是值得我們思考的。
Frank W. Zametti有一篇文章,向我們展示了對Ajax(Asynchronous Javascript+XML)技術的應用,尤其是Struts的應用。他認為在應用Ajax中有很多有趣的事情,包括Ajax怎樣工作,為什么Ajax會被用到等等。
文章地址:
http://www.omnytex.com/articles/xhrstruts/
產生驗證碼圖片的文件-----image.jsp
<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" %>
<%!
Color getRandColor(int fc,int bc){//給定范圍獲得隨機顏色
Random random = new Random();
if(fc>255) fc=255;
if(bc>255) bc=255;
int r=fc+random.nextInt(bc-fc);
int g=fc+random.nextInt(bc-fc);
int b=fc+random.nextInt(bc-fc);
return new Color(r,g,b);
}
%>
<%
//設置頁面不緩存
response.setHeader("Pragma","No-cache");
response.setHeader("Cache-Control","no-cache");
response.setDateHeader("Expires", 0);
// 在內存中創建圖象
int width=60, height=20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 獲取圖形上下文
Graphics g = image.getGraphics();
//生成隨機類
Random random = new Random();
// 設定背景色
g.setColor(getRandColor(200,250));
g.fillRect(0, 0, width, height);
//設定字體
g.setFont(new Font("Times New Roman",Font.PLAIN,18));
//畫邊框
//g.setColor(new Color());
//g.drawRect(0,0,width-1,height-1);
// 隨機產生155條干擾線,使圖象中的認證碼不易被其它程序探測到
g.setColor(getRandColor(160,200));
for (int i=0;i<155;i++)
{
int x = random.nextInt(width);
int y = random.nextInt(height);
int xl = random.nextInt(12);
int yl = random.nextInt(12);
g.drawLine(x,y,x+xl,y+yl);
}
// 取隨機產生的認證碼(4位數字)
String sRand="";
for (int i=0;i<4;i++){
String rand=String.valueOf(random.nextInt(10));
sRand+=rand;
// 將認證碼顯示到圖象中
g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));//調用函數出來的顏色相同,可能是因為種子太接近,所以只能直接生成
g.drawString(rand,13*i+6,16);
}
// 將認證碼存入SESSION
session.setAttribute("rand",sRand);
// 圖象生效
g.dispose();
// 輸出圖象到頁面
ImageIO.write(image, "JPEG", response.getOutputStream());
%>
---------------使用驗證碼圖片的文件---------a.jsp------------------------------------
<%@ page contentType="text/html;charset=gb2312" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>認證碼輸入頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</head>
<body>
<form method=post action="check.jsp">
<table>
<tr>
<td align=left>系統產生的認證碼:</td>
<td><img border=0 src="image.jsp"></td>
</tr>
<tr>
<td align=left>輸入上面的認證碼:</td>
<td><input type=text name=rand maxlength=4 value=""></td>
</tr>
<tr>
<td colspan=2 align=center><input type=submit value="提交檢測"></td>
</tr>
</form>
</body>
</html>
-----------------驗證的頁面----------check.jsp
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<html>
<head>
<title>認證碼驗證頁面</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
</head>
<body>
<%
String rand = (String)session.getAttribute("rand");
String input = request.getParameter("rand");
%>
系統產生的認證碼為: <%= rand %><br>
您輸入的認證碼為: <%= input %><br>
<br>
<%
if (rand.equals(input)) {
%>
<font color=green>輸入相同,認證成功!</font>
<%
} else {
%>
<font color=red>輸入不同,認證失??!</font>
<%
}
%>
</body>
</html>
JSF在很大程度上類似Struts,而不是類似Tapestry,可以說是一種Struts 2.0,都是采取標簽庫+組件的形式,只是JSF的組件概念沒有象Struts那樣必須繼承ActionForm的限制;JSF在事件粒度上要細膩,不象Struts那樣,一個表單一個事件,JSF可以細化到表單中的每個字段上。
JSF只有在組件和事件機制這個概念上類似Tapestry,但是不似Tapestry那樣是一個完全組件的框架,所以,如果你做一個對頁面要求靈活度相當高的系統,選用Tapestry是第一考慮。
Struts/JSF則適合在一般的數據頁面錄入的系統中,對于Struts和JSF的選用,我目前個人觀點是:如果你是一個新的系統,可以直接從JSF開始;如果你已經使用Struts,不必轉換,如果需要切換,可以將JSF和Tapestry一起考慮。
另外,JSF/Tapestry不只是支持Html,也支持多種客戶端語言如WML或XUI等。
這三者之間關系:如果說Struts是左派;那Tapestry則是右派;而JSF則是中間派,中庸主義是SUN聯盟的一貫策略。
當然,你也可以發表你在實踐中這三者任何一個的使用感受,以使得后來者有一個比較。
我們通過下表來比較這 三種框架在實現上圖各個功能時技術細節,從而得出他們的異同點和偏重點。
|
Struts |
Tapestry3.0 |
JSF |
在View顯示的組件要求 |
組件必須繼承ActionForm |
分顯式調用和隱式調用 組件必須繼承BaseComponent |
普通POJO 無需繼承 Managed Bean |
組件在View顯示粒度 |
View頁面只能顯示與表單對應的ActionForm,配置中Action ActionForm 頁面一般只能1:1:1關系。 |
可將組件嵌入頁面任何一行,對使用組件數量無限制。 |
同Tapestry |
頁面分區tiles |
使用Tiles標簽庫實現,需要另外tiles-def.xml配置文件 |
組件有自己的視圖頁面,通過調用組件即直接實現多個頁面組合。強大自然的頁面組合是其特點。 |
通過組件+標簽庫實現Subview,但如需重用Layout,還要結合Tiles. |
頁面跳轉 |
使用標簽庫html:link中寫明目標URL,URL名稱需要對照配置文件的path命名,與組件Action耦合。 |
URL名稱是目標的組件名稱,不涉及URL和路徑等操作,方便穩固。 |
類似Struts,也需要在配置文件中查找,與組件分離。 |
參數傳遞 |
使用html:link時傳遞參數超過一個以上處理麻煩。 |
直接調用組件,直接賦予參數,沒有參數個數限制 |
參數分離傳遞給組件 |
事件觸發 |
通過表單提交submit激活,不能細化到表單里字段。 |
能夠給于表單每個字段貼一個事件,事件組件必須實現PageListener接口 |
同Tapestry,事件組件必須實習ActionListener 接口 | |
Struts和JSF/Tapestry都屬于表現層框架,這兩種分屬不同性質的框架,后者是一種事件驅動型的組件模型,而Struts只是單純的MVC模式框架,老外總是急吼吼說事件驅動型就比MVC模式框架好,何以見得,我們下面進行詳細分析比較一下到底是怎么回事?
首先事件是指從客戶端頁面(瀏覽器)由用戶操作觸發的事件,Struts使用Action來接受瀏覽器表單提交的事件,這里使用了Command模式,每個繼承Action的子類都必須實現一個方法execute。
在struts中,實際是一個表單Form對應一個Action類(或DispatchAction),換一句話說:在Struts中實際是一個表單只能對應一個事件,struts這種事件方式稱為application event,application event和component event相比是一種粗粒度的事件。
struts重要的表單對象ActionForm是一種對象,它代表了一種應用,這個對象中至少包含幾個字段,這些字段是Jsp頁面表單中的input字段,因為一個表單對應一個事件,所以,當我們需要將事件粒度細化到表單中這些字段時,也就是說,一個字段對應一個事件時,單純使用Struts就不太可能,當然通過結合JavaScript也是可以轉彎實現的。
而這種情況使用JSF就可以方便實現,
<h:inputText id="userId" value="#{login.userId}"> <f:valueChangeListener type="logindemo.UserLoginChanged" /> </h:inputText> |
#{login.userId}表示從名為login的JavaBean的getUserId獲得的結果,這個功能使用struts也可以實現,name="login" property="userId"
關鍵是第二行,這里表示如果userId的值改變并且確定提交后,將觸發調用類UserLoginChanged的processValueChanged(...)方法。
JSF可以為組件提供兩種事件:Value Changed和 Action. 前者我們已經在上節見識過用處,后者就相當于struts中表單提交Action機制,它的JSF寫法如下:
<h:commandButton id="login" commandName="login"> <f:actionListener type=”logindemo.LoginActionListener” /> </h:commandButton> |
從代碼可以看出,這兩種事件是通過Listerner這樣觀察者模式貼在具體組件字段上的,而Struts此類事件是原始的一種表單提交Submit觸發機制。如果說前者比較語言化(編程語言習慣做法類似Swing編程);后者是屬于WEB化,因為它是來自Html表單,如果你起步是從Perl/PHP開始,反而容易接受Struts這種風格。
基本配置
Struts和JSF都是一種框架,JSF必須需要兩種包JSF核心包、JSTL包(標簽庫),此外,JSF還將使用到Apache項目的一些commons包,這些Apache包只要部署在你的服務器中既可。
JSF包下載地址:http://java.sun.com/j2ee/javaserverfaces/download.html選擇其中Reference Implementation。
JSTL包下載在http://jakarta.apache.org/site/downloads/downloads_taglibs-standard.cgi
所以,從JSF的驅動包組成看,其開源基因也占據很大的比重,JSF是一個SUN伙伴們工業標準和開源之間的一個混血兒。
上述兩個地址下載的jar合并在一起就是JSF所需要的全部驅動包了。與Struts的驅動包一樣,這些驅動包必須位于Web項目的WEB-INF/lib,和Struts一樣的是也必須在web.xml中有如下配置:
<web-app> <servlet> <servlet-name>Faces Servlet</servlet-name> <servlet-class>javax.faces.webapp.FacesServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>Faces Servlet</servlet-name> <url-pattern>*.faces</url-pattern> </servlet-mapping> </web-app> |
這里和Struts的web.xml配置何其相似,簡直一模一樣。
正如Struts的struts-config.xml一樣,JSF也有類似的faces-config.xml配置文件:
<faces-config> <navigation-rule> <from-view-id>/index.jsp</from-view-id> <navigation-case> <from-outcome>login</from-outcome> <to-view-id>/welcome.jsp</to-view-id> </navigation-case> </navigation-rule>
<managed-bean> <managed-bean-name>user</managed-bean-name> <managed-bean-class>com.corejsf.UserBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope> </managed-bean> </faces-config>
|
在Struts-config.xml中有ActionForm Action以及Jsp之間的流程關系,在faces-config.xml中,也有這樣的流程,我們具體解釋一下Navigation:
在index.jsp中有一個事件:
<h:commandButton label="Login" action="login" />
action的值必須匹配form-outcome值,上述Navigation配置表示:如果在index.jsp中有一個login事件,那么事件觸發后下一個頁面將是welcome.jsp
JSF有一個獨立的事件發生和頁面導航的流程安排,這個思路比struts要非常清晰。
managed-bean類似Struts的ActionForm,正如可以在struts-config.xml中定義ActionForm的scope一樣,這里也定義了managed-bean的scope為session。
但是如果你只以為JSF的managed-bean就這點功能就錯了,JSF融入了新的Ioc模式/依賴性注射等技術。
Ioc模式
對于Userbean這樣一個managed-bean,其代碼如下:
public class UserBean {
private String name;
private String password;
// PROPERTY: name
public String getName() { return name; }
public void setName(String newValue) { name = newValue; }
// PROPERTY: password
public String getPassword() { return password; }
public void setPassword(String newValue) { password = newValue; }
}
<managed-bean> <managed-bean-name>user</managed-bean-name> <managed-bean-class>com.corejsf.UserBean</managed-bean-class> <managed-bean-scope>session</managed-bean-scope>
<managed-property> <property-name>name</property-name> <value>me</value> </managed-property>
<managed-property> <property-name>password</property-name> <value>secret</value> </managed-property> </managed-bean> |
faces-config.xml這段配置其實是將"me"賦值給name,將secret賦值給password,這是采取Ioc模式中的Setter注射方式。
Backing Beans
對于一個web form,我們可以使用一個bean包含其涉及的所有組件,這個bean就稱為Backing Bean, Backing Bean的優點是:一個單個類可以封裝相關一系列功能的數據和邏輯。
說白了,就是一個Javabean里包含其他Javabean,互相調用,屬于Facade模式或Adapter模式。
對于一個Backing Beans來說,其中包含了幾個managed-bean,managed-bean一定是有scope的,那么這其中的幾個managed-beans如何配置它們的scope呢?
<managed-bean> ... <managed-property> <property-name>visit</property-name> <value>#{sessionScope.visit}</value> </managed-property>
|
這里配置了一個Backing Beans中有一個setVisit方法,將這個visit賦值為session中的visit,這樣以后在程序中我們只管訪問visit對象,從中獲取我們希望的數據(如用戶登陸注冊信息),而visit是保存在session還是application或request只需要配置既可。
UI界面
JSF和Struts一樣,除了JavaBeans類之外,還有頁面表現元素,都是是使用標簽完成的,Struts也提供了struts-faces.tld標簽庫向JSF過渡。
使用Struts標簽庫編程復雜頁面時,一個最大問題是會大量使用logic標簽,這個logic如同if語句,一旦寫起來,搞的JSP頁面象俄羅斯方塊一樣,但是使用JSF標簽就簡潔優美:
<jia:navigatorItem name="inbox" label="InBox" icon="/images/inbox.gif" action="inbox" disabled="#{!authenticationBean.inboxAuthorized}"/>
|
如果authenticationBean中inboxAuthorized返回是假,那么這一行標簽就不用顯示,多干凈利索!
先寫到這里,我會繼續對JSF深入比較下去,如果研究過Jdon框架的人,可能會發現,Jdon框架的jdonframework.xml中service配置和managed-bean一樣都使用了依賴注射,看來對Javabean的依賴注射已經迅速地成為一種新技術象征,如果你還不了解Ioc模式,趕緊補課。
附Jsf核心教程一個JSF案例:login.rar