A first look at JavaServer Faces(jsf 1)
Summary?In??September?2002,??the?early??access?(EA)??draft?of?the?JavaServer?Faces?specification?was?released?under?Java?Specification?Request?(JSR)?127.?JavaServer?Faces,??with?a??well-defined?request??processing?lifecycle??and?a?rich?component?hierarchy,?will?profoundly??affect?the?development?of?Java??2?Platform,?Enterprise?Edition?(J2EE)?applications.?In?Part?1?of?this?two-part?series,?David?Geary?introduces?JavaServer?Faces?and?explores?its?fundamental?concepts.?(3,000?words;?November?29,?2002)?????
摘要:在2002年9月的127次JSR會議上發表了JavaServer?Faces規范的早期草稿版本。具有良好定義的請求處理生命周期和豐富的組件層次結構的JSR將會深遠的影響到J2EE應用的開發。在本篇分為兩部分的文稿的第一部分中,David?Geary將介紹JSR并初步探討它的基本概念。
????
????Recently,?I?had?the?good?fortune?of?training?and?mentoring?a?group?of?novice?Java?developers??as?we?implemented??a?complex?Web?application?using??Struts,??Enterprise??JavaBeans?(EJB),?servlets,?JavaServer??Pages?(JSP),?and??the?JSP??Standard??Tag?Library?(JSTL).?As?it??turned?out,?the?project?was?a??success;??it??came?in??under?budget??and?on???time,?and???had?numerous???features?not?originally??envisioned.??As??you?might??imagine,??we???faced?many??technical?challenges?along?the??way;?the?most?significant?were:?
最近,我在使用Struts、EJB、JSP和JSTL開發一個復雜的Web應用的過程中能有幸培訓和指導一組共同參與開發的初級Java開發人員。當開發完成以后,整個項目非常成功并且是在經費預算和進度規劃內完成的,而且實現了很多原先沒有設想到的功能特性。當然我們在開發的過程中也遇到了相當多的技術挑戰,最典型的有:
????1.?Implementing?custom??components,?Which???included?a???tree/table?viewer???and?a??query??builder???that??lets????users??dynamically??add???and??remove?fundamental??components?such?as???text????fields?and??drop-down?lists?used??to?build?database?queries.?
????1.?實現客戶端組件,諸如樹型、列表的視圖和允許用戶在創建數據庫查詢時動態的增加和刪除類似于文本輸入框或者下拉列表等基本元素的查詢構造器的客戶端組件。
????2.?Supporting?hand-held?devices,?such?as?PDAs?and?radio?frequency?devices.?
????
????2.?支持手持設備,例如PDA和射頻設備。
????3.?Lack??of??an??IDE???for??effective??rapid??application???development??(RAD).
????
????3.?缺乏有效的能夠支持快速應用開發的集成環境。
????
????Implementing?custom?components?and?supporting?hand-held??devices—especially??the?latter—consumed??a?great??deal?of??our?time??and?effort.?Also,?although?some??of?the??developers?used??the?Eclipse??open?source??IDE,?we??lacked?an?effective?RAD?tool?for?implementing?the?Web?application's?user?interface.?
????實現客戶端組件和支持手持設備消耗了大量的時間精力。盡管一部分開發人員使用了開????放源碼的Eclipse基層開發環境,但是我們在Web應用的客戶界面開發方面還是沒有有效的RAD工具。
????Unless?you've?been?living?in?a?cave?for?the?past?few?years,?I'm?sure??you're??aware?that??tools?exist??for?creating??custom?Web??components?and?supporting??markup?languages?other?than?HTML,?all?of?which?are?wrapped?up?in?a?very?nice?IDE.?That?software,?of?course,?is?Microsoft's?.Net?with?WebForms;?the?IDE?is?Visual?Studio.?
????我確信除非你不韻世事,否則你肯定知道用于開發用戶Web組件和支持HTML以外的標記語言的工具已經被集成到了一個非常不錯的開發工具中了。當然這個工具就是Microsoft's?.Net?with?WebForms,而這個開發環境就是Visual?Studio。
????In??spite?of??those?attractive??.Net?features,??the?company??I?was??working
for—like?many?software?development?companies?nowadays—opted?to?go?with?the?Java??2?Platform,??Enterprise?Edition??(J2EE)?because??of?its??platform?and
vendor?independence??and?the??wealth?of??available?open??source?software?for???Java?and?J2EE.?
????盡管.NET具有很多引人矚目的特性,我所工作的公司和目前的許多軟件開發公司一樣,因為J2EE的平臺無關性和大量可以利用的開放源碼的軟件而傾向于在J2EE上進行開發
????Wouldn't?it??be?nice??if?you??could?take??advantage?of??Java?and?.Net's?best?features,?platform?and?vendor?independence,?open?source?products?such?as?Ant?and?log4j,?and?the?ability?to?easily?create?custom?Web?components?and?render?them?to?multiple?devices,?all?wrapped?up?in?a?killer?IDE??That's?the?promise?of?JavaServer?Faces.?
????如果我們能把所有這些Java和.NET各自的優點,平臺無關的特性,類似Ant和Log4j這樣優秀的開放源碼的軟件產品以及能夠簡便的生成客戶Web組件并發布到多種設備上的能力組合到一個獨一無二的集成開發環境中,那這個開發環境將是非常的優秀啊?這就是????JSF將提供給我們的東西。
JSF是什么?
????JavaServer?Faces?(JSF)??is?an?application??framework?for?creating??Web-based?user?interfaces.??If?you?are??familiar?with??Struts?(a?popular???open?source?JSP-based?Web??application??framework)??and?Swing???(the?standard?Java??user?interface??framework?for?desktop??applications),??think?of?JavaServer??Faces?as?a??combination?of??those?two??frameworks.?Like??Struts,??JSF?provides?Web?application?lifecycle??management?through??a?controller???servlet;?and??like?Swing,?JSF??provides?a??rich?component??model?complete??with?event??handling?and?component?rendering.?
JSR是生成基于Web的用戶界面的應用程序框架。如果你對Struts(流行的開放源碼的Web應用程序框架)和Swing(標準的用于桌面應用的Java用戶界面框架)都很熟悉的話,可以認為JSF是他們二者的集成。類似于Struts,JSF通過一個控制器Servlet提供了Web應用的生命周期管理;同時類似于Swing,JSF提供了包括事件處理和組件生成在內的豐富的組件模型。
????In?a?nutshell,?JSF?eases?Web-based?application?development?because?it:?
????Lets?you?create?user?interfaces?from?a?set?of?standard,?reusable?server-side?components???Provides??a??set??of???JSP??tags??to??access??those?components?Transparently??saves??state??information??and??repopulates??forms??when?they?redisplay??Provides??a???framework??for???implementing??custom???components??Encapsulates?event?handling?and?component?rendering?so?you?can?use??standard??JSF?components?or?custom?components??to?support?markup?languages?other??than??HTML?Lets?tool?vendors?develop?IDEs?for?a?standard?Web?application?framework
????
簡單的說,JSF基于以下的原因簡化了基于Web的應用的開發:
◆使你能夠利用一些標準的可重用的服務器端組件來創建客戶界面。?
◆提供了一組JSP?標簽來獲取(訪問)這些組件。?
◆開發人員不用關心當頁面刷新的時候頁面狀態數據的存儲和重現。?
◆提供了一個用于實現定制組件的框架?
◆封裝了事件處理和組件顯示,所以你可以使用標準的或者定制的JSF組件支持HTML以外的標記語言。
◆開發工具提供商可以開發針對標準Web應用框架的集成環境。
????Besides?being?a?conceptual?combination?of?Struts?and?Swing,?JSF?is?a??direct?competitor?to?Microsoft's?WebForms.?The?frameworks?are?very?similar,?both?in?concept?and?implementation.?And?because??JSF?represents?a?standard?for??Java-based??Web??application??frameworks,???tool??vendors??can??concentrate???on??developing??IDEs??for??JSF??instead???of??developing??an??IDE??for???one??of?approximately?35?existing??Java-based?Web?application??frameworks,?including?Struts.?
????
除了作為Struts和Swing概念上的統一體外,JSF還將成為Microsoft的WebForms的直接????競爭對手。這兩種框架不論從概念或者實現上都非常相似。由于JSF作為基于Java的Web????應用框架的標準,工具開發商們可以專注于為JSF開發集成環境,而不僅僅為包括Struts在內的大約35種基于Java的Web應用框架的其中之一開發集成環境。
????
????Note:?Struts?developers?needn't?worry;?although?JSF?and?Struts?have?much??in?common,?JSF?will?not?make?Struts?obsolete.?See?Resources?for?a?discussion?of?an?integration?strategy?for?Struts?and?JavaServer?Faces.?
????
注:Struts開發人員不用擔憂;盡管JSF和Struts很相像,但JSF并不會放棄Struts。在參考資料中有關于集成兩者的討論。
????Currently,??JSF??is?an??early??access?(EA)??release,??and,?as??a??result,?is?somewhat?immature.?The?specification?leaves?some?functionality??unspecified,?and??the?specification??and?reference??implementation?are??currently?out??of?sync,?with??the?former??specifying?new??syntaxes?and??functionality?not??yet?implemented?in?the?latter.?On?the??other?hand,?JSF?is?mature?enough??for?you?to??write?code??against—although?much??of?that??code?is??guaranteed?to??be?obsolete?(see??the?disclaimer??below)—and?the??reference?implementation??is?fairly??complete??and??relatively???bug-free.??You??can??download???the??JSF?specification,?the?reference?implementation,?two?sample?applications,?and??a?JSF?tutorial?from?Resources.?
????
目前JSF還僅僅是EA版本,所以不是很成熟。規范當中還有很多功能沒有闡述,規范和????參考實現也不同步,規范中描述的語法和功能還沒有得到實現。另一方面,JSF已經足夠成熟得讓你根據它進行編程——盡管有些代碼將會被廢棄(參看下文聲明)——而且參考實現已經基本完成而且比較可靠。你可以從參考資源中下載JSF的規范、參考實現、兩個樣例應用和一份JSF教程。
????The?two??articles?in??this?series??provide?a??code-intensive?introduction?to?JavaServer?Faces.?In?this??article,?I?begin?with??a?short?discussion?of??the?JSF??lifecycle??and??then??dive??into??some??example??code??that?illustrates?implementation?of?Web-based??user?interfaces?with??JSF?and?how??you?can?take?advantage?of?built-in??validation.?In?Part??2,?I?will??explain?more?advanced?JSF?concepts?such?as:??implementing?custom?validation;?using??model?objects;?internationalization;?creating??custom?components;??and?finally,??delegating??event?handling?and??rendering?so?you??can?use?components??to?generate?markup?languages?other?than?HTML.?
本系列的兩篇文章提供的是并不偏重編碼的JSF介紹。在本篇中,我在簡短的介紹了JSF的生命周期以后將通過一些示例代碼來說明如何通過JSF來實現基于Web的用戶界面以及如何利用內建的驗證功能。下一篇中,我將闡述一些JSF的高級概念:實現定制驗證、使用模型對象、國際化支持、生成定制組件和便于你使用組件生成HTML以外的標記語言的事件的代理和處理機制。
????Disclaimer:?The?code?discussed?in??this?article?was?written?against??the?EA2?JSF??reference?implementation.??As?mentioned??above,?the??specification?and??reference?implementation?are?in?a?state?of?flux,?and?therefore,?the?code??in??this?article?is?guaranteed?to?be??obsolete?in?the?near?future;?however,??the??code??works?as??advertised?with??the?EA2??reference?implementation??and?was??tested?with?both?Tomcat?4.0.6?(the?latest?production?release?of?Tomcat)??and??Resin?2.1.6.?Furthermore,?you?can?read?the?JSF?specification?until?the??cows?come?home,?but??to?really?grasp??the?concepts,?you??must?ruminate?over??some?code.?
????聲明:本文中的代碼均針對EA2版本的JSF參考實現編寫。前面已經說明,規范和參考實現目前還在修訂當中,這些代碼將很快會被廢棄;然而這些代碼可以在EA2版本的參考實現上運行,并且在Tomcat?4.0.6和Resin?2.1.6上通過了測試。當然你也可以研讀規范直至領會,但是如果你想真正掌握概念,就應該做一些深入的編碼實踐。
JSF的運行周期(The?JavaServer?Faces?lifecycle)
????JSF?handles?HTTP?requests?with?seven?distinct?phases,?as?shown?in?Figure??1.??The?normal?flow?of?control?is?shown?with?solid?lines,?whereas??dashed??lines?show?alternate??flows?depending??on??whether??a?component??requests??a??page?redisplay??or?validation??or??conversion?errors?occur.?
????
JSF通過7個步驟來處理一個HTTP請求,如圖1。正常的處理流程通過實線標識,虛線表示一些諸如刷新顯示、驗證錯誤、轉換錯誤等特殊情況的可選的處理流程。

????The??Reconstitute??Request??Tree??phase?creates??a??component??tree??for?the??requested?page.?If?that?page??previously?displayed?and?JSF?saved??the?page's??state?information,?the?state?information?is?added?to?the?request.?This?means?that?JSF?automatically?retains?form?information?when?a?form?redisplays;??for?example,?when?a?user?does?not?correctly?fill?out?a?form.?This?handy??feature?is??a??fundamental??capability??provided??by??Microsoft's??WebForms,??but?is?otherwise?absent?from?J2EE.?
????
重建請求樹階段為被請求的頁面創建組件樹。如果這個頁面曾經被訪問過,JSF會保存????上次訪問時的狀態信息和數據,在此時將這些狀態數據加入到當前的請求。這意味著當重復訪問某個表單的時候JSF將自動的恢復表單數據。這個便利的功能在Microsoft的WebForms中是基本功能,但是在J2EE中則被遺漏了。
????During?the?Apply?Request?Values?phase,?the?JSF?implementation?iterates??over?the?components??in?the??component?tree??and?calls??each?component's?decode()??method.?That?method?extracts?information??from?the?request?and?stores??it?in??the?component.?Optionally,?components?may?delegate?decoding?to?a?renderer.?
????
在請求數據解析階段中,JSF實現遍歷組件樹中所有的組件調用所有組件的decode()方????法。decode()方法將從請求中提取信息并存儲到組件當中。某些情況下,組件可用于為響應合成器提取數據。
????In?addition?to?decoding?request?information?during?the?Apply?Request??Values??phase,?components?or?their??renderers?may?create?request??events.?Typically,??request??events?signal??a?visual??change?for??one?or??more?components;??for??example,?clicking?on?a?graphic?in?a?tree?control?may?expand?a?branch?of??the??tree.??Alternatively,??an??event??in?one??component??may??update??the?visual??representation?of?another?component;?for?example,?clicking?on?a?leaf?node?in??a?tree?may?cause?an?associated?list?to?change?its?contents?and?redisplay.?In?either?situation,?a?request?event?is?generated?and?added?to?the?JSF?context.?
????
另外在請求數據解析階段提取請求信息的過程中,組件或者他們的響應合成器可能會生成一些請求事件。最典型的有請求事件可能會觸發了一個或多個組件的顯示變化;例如當點擊一個樹型控件可能會展開它的分支。另外,某個組件的事件可能會更新另一個組件的顯示;例如當點擊一個樹型控件的葉節點可能會導致和它關聯的列表控件改變它的內容和顯示。在任何一種情況下,都會產生一個請求事件加入到JSF的運行環境中。
????Request?events,?which?are?generated??during?the?Apply?Request?Values??phase,?are??handled??during?the??Handle??Request?Events??phase.??During?the??Handle?Request??Events??phase,??the?JSF??implementation??calls??the?processEvents()??method?for?each??component?that?has??one?or?more??request?events.?Components??may?handle?request?events?themselves,??or?they?may?choose?to??delegate?event?handling?to??an?event??handler.?The??processEvents()?method??is?a??boolean()?method.?If?that?method?returns??false,?lifecycle?processing?advances?to??the?Process?Validations?phase;?otherwise,?lifecycle?processing?advances?directly?to?the?Render?Response?phase.?
請求數據解析階段產生的請求事件都在請求事件處理階段處理。在請求事件處理階段JSF實現為那些有一個或多個請求事件的組件調用processEvents()方法。這些組件將自行處理這些事件或者提交給某個事件處理器代理處理。processEvents()方法返回值為boolean。如果返回false,處理周期將前進到驗證處理階段,否則將直接跳轉至響應合成階段。
????During??the??Reconstitute?Request??Tree??phase,?the??JSF??implementation?may?register?one?or?more?validators?for??any?of?the?components?in?the??component??tree.?In?the?Process?Validations??phase,?the?JSF?implementation?invokes??the?validate()?method?for?each?validator.?Validators?perform?correctness??checks?and?return??a?boolean??value?from??their?validate()??method;?if??that?method?returns??true,??the??JSF?lifecycle??proceeds??normally;??otherwise,?the??JSF?implementation?invokes?the?Render?Response?phase?directly.?
在重建請求樹階段,JSF實現會為請求樹上的組件注冊一個或多個驗證器。在驗證處理階段,JSF實現調用每一個驗證器的validate()方法。驗證器執行validate()方法進行正確性檢驗以后返回一個boolean值;如果為true,JSF處理周期將繼續前進;否則將直接跳轉至響應合成階段。
????Each?JSF?user?interface?component?can??be?associated?with?a?field?in??a?Java?object?(known?as?a?model??object).?During?the?Update?Model??phase,?component?values??are??copied???to??the??component's???model??object.??A???component's?updateModel()?method?carries?out??that?data?transfer.?Conversion??errors?can?occur?during?this??phase?because?request??parameters?are?strings,??but?model?values?can?represent?any?type?of?Java?object.?If?a?conversion?error??occurs,?the?JSF?implementation?invokes?the?Render?Response?phase?directly.?
????
每一個JSF用戶界面組件都關聯于一個Java對象(被稱為模型對象)的某個字段。在模型更新階段,組件的值將被復制到對應的組件當中。數據傳遞通過模型對象的updateModel()方法調用完成。由于請求參數都是字符串而模型對象字段有可能是任何Java對象類型,如果發生轉換錯誤,JSF實現將直接跳轉至響應合成階段。
????In?a?JSF?application,?if?you?submit?a?form?or?click?on?a?link?(both?of?which?must?be??represented?by??JSF?components),??the?JSF??implementation?creates?a??form?event?or?a?command?event,?respectively.?Those?events?are?handled?in?the??Invoke??Application??phase?by??an??application-specific?handler.??Typically,??those??handlers??specify?a??URL,??and?the??JSF??implementation?forwards??the?request?to??that?URL.??Currently,?application-specific??handlers?handle?form?and?command?events??in?a?single??method,?typically?with??a?switch?statement.?The?JSF?expert??group?is?aware??of?this?approach's??ugliness,?and?therefore,?it's?almost?certain?to?change?in?the?JavaServer?Faces?1.0?release.?
????
在JSF應用中,如果你通過提交一個表單或者點擊一個連接(都需要是通過JSF組件提供的),JSF實現將分別生成一個表單事件和命令事件。這些事件將在調用Web應用階段由一個應用聲明的處理器進行處理。典型的情況是處理器聲明了一個URL,JSF實現將這個請求前轉到這個URL中。目前應用聲明的處理器對此的處理都是通過一個包含一個switch語句的單一方法進行的。JSF專家組意識到這樣的方案不是很合理,因此在JSF?1.0的正式發行版將肯定會有所改變。
????Finally,?the??Render?Response??phase?creates??a?response??component?tree?and?forwards?the??response.?When??a?user??submits?a??form,?clicks??on?a?link,?or?otherwise?generates?a?request,?the?cycle?starts?anew.?
????
最后,響應合成階段生成一個響應組件樹并發送響應。當用戶再次提交一個表單或點擊一個鏈接,總之生成一個請求,那么處理流程將重新開始。
????Now?that?we?have??a?general?overview?of??JavaServer?Faces?and?a??rudimentary?understanding?of?the?JSF?lifecycle,?let's?take?a?look?at?some?code.?
現在我們已經對JSF和處理流程有了一個粗略的認識,下面將研究一些代碼。
Seegeris,Bruce