JSF for Nonbelievers: Clearing the FUD about JSF -- Richard Hightower
來自:http://www-128.ibm.com/developerworks/library/j-jsf1/
翻譯:zhouy
--------------------------------------------------------------------------------
恐懼、不確定和懷疑
JSF
的觀念環繞著
JSF
技術已經有一段時間了,我覺得是阻止這種觀念繼續曼延的時候了——或者至少在兩者這間取得平衡點。關于
JSF
,首當其充的誤解,就是離不開拖拽式所見即所得工具進行
JSF
開發。其二,
JSF
不支持類似
Struts
的
MVC Model 2
框架。而最后一點,也是困擾
JSF
開發最大的一點,就是關于其開發困難度的說法。
在這個四小節的討論中,我將盡我所能,通過教你如何利用JSF進行開發這種最實際的方法,來消除上述所有三種誤解。事實上,如果你覺得JSF開發是件困難的事,那么很有可能是因為你沒有正確的使用它——幸運的是要修正它并不難。我會讓你對JSF有一個大體的觀念,并且利用一個可工作的示例展示MVC和JSF的基本原理。在我們開始所有介紹之前,先花一分鐘時間將事實不符的FUD區分清楚。
不要相信FUD
如前面提到的,關于JSF有三個大的誤解,其一便是JSF要求所見即所得工具進行開發工作。這是錯誤的,就像許多Swing開發人員不使用所見即所得工具構建Swing應用程序一樣,你不必需要所見即所得編輯器來構建JSF應用。事實上,不使用所見即所得工具來開發 JSF 會比傳統的Model 2框架如Struts和WebWork開發來得簡單。在稍后的章節中我會有詳細的解釋,但在這里請記?。篔SF開發比Struts來得簡單,即使不使用所見即所得工具!
關于JSF的另一個誤解是,它不支持Model 2模型?,F在,這種說法只是部分正確。事實是Model 2是一種建立在Servlets基礎上的MVC瀑布模型版本。與Model 2面向無狀態協議(HTTP)所不同的是,JSF支持富MVC模型——一種與傳統的GUI應用更加相似的模型。雖然MVC的基礎概念使得JSF框架的實現比其它框架困難,但在上層結構上許多實現JSF的工作已經為你做好,得到的結果是,付出減少,卻能夠獲得更多的回報。
流傳最廣的關于JSF的誤解是在于JSF的開發難度。我經常從人們口中聽到這樣的說法,他們閱讀了大量的技術文檔,但是并沒有實際動手去嘗試這項技術,所以我認為要消除這個慮慮很簡單。如果你是通過 JSF 浩瀚無邊的規格說明來建立你對JSF的理解,那么這些東西肯定會使你受驚嚇。要明確的是,所有的這些規格本質上是給實現工具使用的,而不是應用程序開發者。如前所述,JSF是為方便應用程序開發者而設計的。
雖然從某種意義上說,JSF的組件基礎和事件驅動的GUI式的開發模型對于Java世界來說是一種新鮮的事物,但是它其實早已在某些領域中存在了。Apple的WebObjects和ASP.net與JSF就十分的相似。Tapestry是一項開源的Web組件框架,它與JSF所采用的方法不同,但也是一種基于Web GUI組件框型的技術。
無論如何,關于FUD的討論或許可以終止。解決關于JSF的編見最快捷的方法便是正確地研究這門技術,這正是我們稍后要做的事情??紤]到這或許是你第一次了解JSF,我將為你介紹它的總體概念。
給JSF初學者
類似于Swing和AWT,JSF提供了一套標準和可重用的GUI組件。JSF被用來構建Web應用表層,它提供如下開發優勢:
-
動作邏輯與表現邏輯的明顯區分
-
有狀態事務的組件級別控制
-
事件與服務端代碼的輕松綁定
-
UI組件及Web層觀念
-
提供多樣的、標準的開發商實現規則
一個典型的JSF應用包括以下幾個部分:
-
供管理應用狀態和動作的JavaBeans組件
-
事件驅動開發(通過與傳統GUI開發類似的監聽器來實現)
-
展示MVC樣式的頁面,通過JSF組件樹引用視圖
雖然你將需要克服使用JSF過程中的觀念上的困難,但是這些努力都將是值得的。JSF的組件狀態管理,方便的用戶輸入校驗,小粒度,組件基礎的事件處理及方便的可擴展框架將使你的Web開發便得簡單。我將在接下來的幾章中用最詳細的解釋說明這些最重要的特征。
組件基礎的框架模式
JSF為標準HTML中每個可用的輸入域提供了組件標簽,你也可以為你應用中的特殊目的定義自己的組件,或者也可以將多項HTML組件組合起來成為一個新的組合——例如一個數據采集組件可以包含三個下拉菜單。JSF組件是有狀態的,組件的狀態由JSF框架來提供,JSF用組件來處理HTML響應。
JSF的組件集包含事件發布模型、一個輕量級的IoC容量、擁有其它普遍的GUI特征的組件,包括可插入的渲染、服務器端校驗、數據轉換、頁面導航控制等等。作為一種基于組件的框架,JSF極具可配置性和可護展性。大部分的JSF功能,比如導航和受管bean查詢,可以被可插入組件所替換。這樣的插入程度給開發人員構建Web應用GUI時提供了極大的彈性,允許開發人員將其它基于組件的技術應用于JSF的開發過程中來。比如說,你可以將JSF的內嵌IoC框架替換為更加全能的Spring的IoC/AOP以供受管bean查詢。
JSF和JSP技術
一個JSF應用的用戶表層被包含在JSP(JavaServer Pages)頁面中。每個JSP頁面包含有JSF組件,這些組件描繪了GUI功能。你可以在JSP頁面里使用 JSF 定制標簽庫來渲染UI組件,注冊事件句柄,實現組件與校驗器的交互及組件與數據轉換器的交互等等。
那就是說,JSF不是固定與JSP技術相關聯。事實上,JSF標簽僅僅引用組件以實現顯示的目的。你會發現當你第一次修改一個JSP頁面中某一JSF組件的屬性,在重新載入頁面的時候并沒有發生應有的變化。這是因為標簽在它自己的當前狀態中進行查詢,如果組件已經存在,標簽就不會改變它的狀態。組件模型允許控制代碼改變一個組件的狀態(例如將一個輸入域置為不可用),當視圖被展現的時候,組件樹的當前狀態也隨著一覽無余。
一個典型的JSF應用在UI層無需任何的Java代碼,只需要很少的一部份JSTL EL( JSP 標準標簽庫,表達式語言)。前面已經提及,有非常多IDE工具可以幫助我們構建JSF應用,并且有越來越多的第三方JSF GUI組件市場。不使用所見即所得工具來編寫JSF也是可行的。
JSF和MVC
JSF技術是在多年Java平臺上的Web開發技術的總結的產物。這種趨勢起源于JSP。JSP是一種很好的表現層,但同時它容易將Java代碼與HTML頁面混淆起來。另一個不好的原因與Model 1架構有關,它使得開發人員通過使用 <jsp:useBean> 標簽將許多原本應該在后端處理的代碼引入到Web頁面中來。這種方法在簡單的Web應用中可以運行得很好,但許多Java開發者不喜歡這種類似C++的靜態引入組合方式,所以Model 2架構隨之被引進。
本質上,Model 2架構是MVC Web應用的一種瀑布模型版本。在Model 2架構中控制器通過Servlets來表現,顯示層則通過JSP頁面來展現。Struts是一種最簡單的Model 2實現,它使用Actions取代了Servlets。在Struts中應用的控制邏輯與數據層(通過ActionForms來展現)相分離。反對Struts的主要的不滿在于,Struts更多偏向程序化,而非面向對象。WebWork和Spring MVC是Model 2的另外兩種框架,它們比起Struts更大的改進在于盡量減少程序化,但是兩者都沒有Struts普及。另外兩者也不像JSF般提供組件模型。
大多數Model 2框架真正的因素在于它們的事件模型顯得過于單薄,留下了太多的工作需要開發人員自己來處理。一個富事件模型使多數用戶所希望的交互變得簡單。許多Model 2技術就像JPS一樣,很容易將HTML布局及格式與GUI標簽相混合,在表現上不像真正的組件。而一些Model 2的架構(如Struts)錯誤地將表現與狀態分離,便得許多Java開發人員感覺他們像是在編寫COBOL程序。
富MVC環境
JSF提供一種組件模型及比其它Model 2實現更為豐富的MVC環境。本質上說,JSF比Model 2架構更接近真正的MVC開發環境,雖然它仍然屬于無狀態協議。JSF能夠構建比起其它Model 2框架更精彩的事件驅動 GUI 。JSF提供一系列事件選項如menu選項的selected事件,button的clicked事件等等,這與在其它Model 2框架中更多地依賴簡單的“request received”不同。
JSF的易于翻轉的事件模型允許應用程序更少地依賴HTTP實現細節,簡化你的開發量。JSF改善了傳統Model 2架構,它更容易將表現層和業務層移出控制器,并將業務邏輯從JSP頁面中移出。事實上,簡單的控制器類根本無需與JSF相關聯,方便了對控制器類的測試。與真正的MVC架構不同,JSF不會在多于一個視點上發出多條事件,我們仍然是在處理一個無狀態的協議,這使得這一點變得無關緊要。系統事件對一個視圖的變動或更新通常來自于用戶的請求。
JSF的MVC實現細節
在JSF的MVC實現中,作為映射的backing bean在視圖和模型間扮演著協調的作用。正因如此,在backing bean里限制業務邏輯和持久層邏輯就顯得猶為重要。一種普遍的做法是將業務邏輯置入應用模型中。這樣的話backing bean仍會映射模型對象以供視圖顯示。另一種選擇是將業務邏輯放入業務代理——一種與模型相作用的表層。
與JSP技術不同,JSF的視圖實現是一種有狀態組件模型。JSF的視圖由兩部分組成:根視圖和JSP頁面。根視圖是UI組件的集合,它負責維護UI的狀態。就如像Swing和AWT,JSF組件使用組合式設計模式來管理組件樹,用按鈕來管理事件句柄及動作方法。
Figure 1 通過MVC角度來透析的示例
?
一個
JSF
例子
在文章剩余的章節里,我將專注于構建一個
JSF
應用的過程。這個例子是
JSF
技術的一個非常簡單的展現,主要表現在以下幾個方面:
-
如何設置
JSF
應用程序的格局
-
如何為
JSF
配置
web.xml
文件
-
如何為程序配置
faces-config.xml
文件
-
編寫模型(即
backing bean
)
-
利用
JSP
技術構建視圖
-
利用傳統標簽庫在根視圖框建組件樹
-
Form
的默認校驗規則
例子是一個簡單的計算器程序,使目標用戶能夠輸入兩個數并計算。因此頁面上有兩個文本域,兩個標簽,兩處錯誤提示和一個提交按鈕。文本域用來輸入數字,標簽用來標示輸入的文本域,錯誤提示用來顯示文本域中的輸入在校驗或數據轉換時出現的錯誤。總共有三個
JSP
頁面:
index.jsp
用來重定向到
calculator.jsp
頁面;
calculator.jsp
用來顯示上面提及的
GUI
;
result.jsp
用來顯示最后結果。一個受管
bean
:
CalculatorController
作為
calculator.jsp
和
result.jsp
的
backing bean
。
?
Figure
2
示例程序的第二張
MVC
視圖
構建應用
?
為了構建計算器程序,你需要如下步驟:
-
?
收集
web.xml
和
faces-config.xml
文件,可以在下面的示例源代碼中找到。
-
在
web.xml
中聲明
Faces Servlet
和
Faces Servlet
映射。
-
在
web.xml
中指定
faces-config.xml
。
-
在
faces-config.xml
中聲明受管于
JSF
的
bean
。
-
在
faces-config.xml
中聲明導航規則。
-
構建模型對象
Calculator
。
-
用
CalculatorController
與
Calculator
交互。
-
創建
index.jsp
頁面。
?
-
創建
calculator.jsp
頁面。
-
創建
results.jsp
頁面。
聲明
Faces Servlet
和
Servlet
映射
?
為了使用
Faces
,你需要在
web.xml
中裝載
Faces Servlet
如下:
<!-- Faces Servlet -->
<servlet>
? <servlet-name>Faces Servlet</servlet-name>
? <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
? <load-on-startup>1</load-on-startup>
</servlet>
這和大多數web.xml描述文件類似,所不同的是將request的掌握權轉向JSF Servlet,而非自定義的Servlet。所有請求引用了f:view的JSP文件的request都將通過此Servlet。因此需要增加相應的映射,并且將允許使用JSF的JSP技術通過映射裝載進來。
<!-- Faces Servlet Mapping -->
<servlet-mapping>
??? <servlet-name>Faces Servlet</servlet-name>
??? <url-pattern>/calc/*</url-pattern>
</servlet-mapping>
以上配置告知Faces
Servlet容器將所有符合/calc/的請求都轉給Faces Servlet處理。這使得JSF能夠初始化JSF內容和根視圖。
定義faces-config.xml文件
如果你將你的faces配置文件命名為faces-config.xml并將其放置在WEB-INF目錄下,Faces Servlet會查找到它并自動使用它?;蛘吣阋部梢酝ㄟ^web.xml?中的一個初始化參數裝載一個或多個應用配置文件——javax.faces.application.CONFIG_FILES——通過逗號將作為參數的文件列表分隔開來?;蛟S你會使用第二種方法為所有的JSF應用程序作配置。
聲明bean管理
接著是聲明哪個bean被JSF GUI組件所使用。在示例中只有一個受管bean,在faces-config.xml中配置如下:
<faces-config>
?? ?...
? <managed-bean>
??? <description>
????? The "backing file" bean that backs up the calculator webapp
??? </description>
??? <managed-bean-name>CalcBean</managed-bean-name>
<managed-bean-class>
?? ?com.arcmind.jsfquickstart.controller.CalculatorController
</managed-bean-class>
??? <managed-bean-scope>session</managed-bean-scope>
? </managed-bean>
</faces-config>
上面的配置告知JSF要往JSF環境中增加一個叫做CalcBean的bean,你也可以把受管bean取任何名字。Bean已經聲明了,然后你要做的就是為應用定義導航規則。
定義導航規則
這樣一個簡單的應用,你只需使導航規則從calculator.jsp到result.jsp頁面即可。如下:
<navigation-rule>
? <from-view-id>/calculator.jsp</from-view-id>
? <navigation-case>
??? <from-outcome>success</from-outcome>
??? <to-view-id>/results.jsp</to-view-id>
? </navigation-case>
</navigation-rule>
上面的代碼表明,如果一個動作從/calculator.jsp頁面返回邏輯輸出為“success”,那么它將用戶轉向/result.jsp頁面。
?視計模型對象
?由于我們的目標是介紹如何開始JSF,所以我將模型對象設計得非常簡單。這個模型包含在一個對象里,如Listing
1所示。
?Listing
1. The Calculator app's model object
package com.arcmind.jsfquickstart.model;
/**
?* Calculator
?*
?* @author Rick Hightower
?* @version 0.1
?*/
public class Calculator {
??? //~Methods------------------------------------------------
??? /**
???? * add numbers.
???? *
???? * @param a first number
???? * @param b second number
???? *
???? * @return result
???? */
??? public int add(int a, int b) {
??????? return a + b;
??? }
??? /**
???? * multiply numbers.
???? *
???? * @param a first number
???? * @param b second number
???? *
???? * @return result
???? */
??? public int multiply(int a, int b) {
??????? return a * b;
??? }
}
這樣,業務邏輯就全部建立了。下一步便是將其顯示在Web表現層上。?結合模型和視圖
?控制器的目的就是將模型與視圖結合在一起。控制器對象的一個作用就是保持模型與視圖的不可知論。(?)如同你在下面所看到的,控制器定義了三個JavaBeans屬性,通過這些屬些控制輸入和輸出結果。這些屬性是:results(作為輸出)、firstNumber(作為輸入)、secondNumber(作為輸入)。Listing 2是CalculatorController的代碼。
?Listing 2. The
CalculatorController
package com.arcmind.jsfquickstart.controller;
import com.arcmind.jsfquickstart.model.Calculator;
/**
?* Calculator Controller
?*
?* @author $author$
?* @version $Revision$
?*/
public class CalculatorController {
??? //~ Instance fields --------------------------------------------------------
??? /**
???? * Represent the model object.
???? */
??? private Calculator calculator = new Calculator();
??? /** First number used in operation. */
??? private int firstNumber = 0;
??? /** Result of operation on first number and second number. */
??? private int result = 0;
??? /** Second number used in operation. */
??? private int secondNumber = 0;
??? //~ Constructors -----------------------------------------------------------
??? /**
???? * Creates a new CalculatorController object.
???? */
??? public CalculatorController() {
??????? super();
??? }
??? //~ Methods ----------------------------------------------------------------
??? /**
???? * Calculator, this class represent the model.
???? *
???? * @param aCalculator The calculator to set.
???? */
??? public void setCalculator(Calculator aCalculator) {
??????? this.calculator = aCalculator;
??? }
??? /**
???? * First Number property
???? *
???? * @param aFirstNumber first number
???? */
??? public void setFirstNumber(int aFirstNumber) {
??????? this.firstNumber = aFirstNumber;
??? }
??? /**
???? * First number property
???? *
???? * @return First number.
???? */
??? public int getFirstNumber() {
??????? return firstNumber;
??? }
??? /**
???? * Result of the operation on the first two numbers.
???? *
???? * @return Second Number.
???? */
??? public int getResult() {
??????? return result;
??? }
??? /**
???? * Second number property
???? *
???? * @param aSecondNumber Second number.
???? */
??? public void setSecondNumber(int aSecondNumber) {
??????? this.secondNumber = aSecondNumber;
??? }
??? /**
???? * Get second number.
???? *
???? * @return Second number.
???? */
??? public int getSecondNumber() {
??????? return secondNumber;
??? }
??? /**
???? * Adds the first number and second number together.
???? *
???? * @return next logical outcome.
???? */
??? public String add() {
???????
??????? result = calculator.add(firstNumber, secondNumber);
??????? return "success";
??? }
??? /**
???? * Multiplies the first number and second number together.
???? *
???? * @return next logical outcome.
???? */
??? public String multiply() {
??????? result = calculator.multiply(firstNumber, secondNumber);
??? ???
??????? return "success";
??? }
}
請注意,在Listing 2中乘法和加法都返回“success”。“success”表明一個邏輯輸出,它不是保留字,它是與faces-config.xml的導航規則相結合的,通過增加或定義操作執行,頁面將轉向result.jsp。?這樣,你已經完成了后臺代碼工作。接下來我們將定義JSP頁面及組件樹以展示應用視圖。
?創建index.jsp頁面
?Index.jsp的目的是保證/calculator.jsp頁面被正確的裁入JSF內容中,使得頁面可以找到正確的根視圖。
<jsp:forward page="/calc/calculator.jsp" />?這個頁面全部所做的工作便是將用戶重定向到/calc/calculator.jsp頁面。這樣便將calculator.jsp頁面導向JSF內容中,使得JSF可以找到根視圖。
?創建calculator.jsp頁面
?Calculator.jsp是整個計算器應用程序的中心視圖。這個頁面獲取用戶輸入的兩個數字,如Figure
3所示。
Figure 3. The Calculator
page

?
這一頁較為復雜,我將一步一步進行講解。首先你需要聲明供JSF使用的標簽庫:
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
上述代碼告訴JSP引擎你將使用兩個JSF標簽庫:html和core。Html標簽庫包含所有與forms和其它HTML規范有關的標簽。Core標簽庫包含所有邏輯、校驗、控制等JSF標簽。?一旦將頁面展示在普通的HTML中,你會告訴JSF系統你將使用JSF來管理你的組件。通過使用<f:view>標簽來實現這點,它會告知容器你將使用JSF來管理所有包含在它里面的組件。
?少了<f:view>,JSF將無法構建組件樹,稍后也無法在已經創建起來的組件樹中進行查詢。通過以下代碼使用<f:view>:
<f:view>
? <h:form id="calcForm">
???? ...?? ?
? </h:form>
</f:view>
上面的第一行是<f:view>的聲明,告知容器它受管于JSF。下一行是<h:form>標簽,它告知JSF你需要在此建一個HTML FORM。在位于FORM組件內的組件容器的語法渲染期間,所有的組件將會被問詢自動渲染,這樣它們將會生成標準的HTML代碼。
接下來,你告知JSF在FORM里所需的其它組件。在<h:form>中定義了一個panelGrid。panelGrid是一個組合組件——也就是一個組件里包含有其它的組件。panelGrid定義其它組件的布局,Listing 3顯示如何定義panelGrid的代碼:
Listing 3. Declaring the
panelGrid
<h:panelGrid columns="3">
? <h:outputLabel value="First Number" for="firstNumber" />
? <h:inputText id="firstNumber" value="#{CalcBean.firstNumber}" required="true" />
? <h:message for="firstNumber" />???
? <h:outputLabel value="Second Number" for="secondNumber" />
? <h:inputText id="secondNumber" value="#{CalcBean.secondNumber}" required="true" />
? <h:message for="secondNumber" />
</h:panelGrid>屬性columns被定義為3表明所有組件將被布置在擁有3列空間的格局中。我們在panelGrid中加入了6個組件,共占2行。每一行包含一個outputLabel,一個inputText和一條message。Label和message都和inputText組件關聯,因此當一個校驗錯誤或或誤信息關聯到textField時,信息將會顯示在message組件上。兩個文本輸入域都要求有,如果在提交的時候檢測到無值,錯誤信息將會被創建,控制也將會轉到這個視圖來。
注意到兩個inputFields都使用一條JSF表達式來做數值綁定。乍一看這很像一條JSTL表達式。但是,JSF表達式確實與綁定著后臺代碼相應字段的輸入域相關聯。這種關聯是反向的,如果firstNumber是100,那么在form顯示的時候100也會被顯示。同樣,如果用戶提交一個有效的值,例如200,那么200也將作為firstNumber的新值。
一個更加實用的目的是,后臺代碼通過綁定模型對象的屬性的值到輸入域中,從而將模型對象展現出來。你將在此節稍后看到關于此目的的例子。
除了輸入域,calForm通過panelGroup中的兩個commandButton與兩個動作關聯:
<h:panelGroup>
??? <h:commandButton id="submitAdd" action="#{CalcBean.add}"? value="Add" />
??? <h:commandButton id="submitMultiply" action="#{CalcBean.multiply}" value="Multiply" />
</h:panelGroup>
panelGroup的概念與panelGrid很相似,除了它們顯示方式的不同。命令按鈕利用action=”#{CalcBean.add}”將按鈕與后臺動作綁定在一起。因此當這個form通過這個按鈕提交的時候,相關聯的方法便開始執行。
創建results.jsp頁面
Results.jsp頁面是用來顯示最后計算結果。如Listing 4所示:
Listing 4. The
results.jsp page
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
...
<f:view>
? First Number: <h:outputText id="firstNumber" value="#{CalcBean.firstNumber}"/>
? <br />
? Second Number: <h:outputText id="secondNumber" value="#{CalcBean.secondNumber}"/>
? <br />
? Result: <h:outputText id="result" value="#{CalcBean.result}"/>
? <br />
</f:view>
Results.jsp是一個相對簡單的頁面,將加法運算的結果顯示給用戶。通過<h:outputText>標簽來完成這一功能。<h:outputText>標簽帶有id和value屬性,value屬性輸出值,它在渲染的時候將被當作string看待。Value屬性通過JSF將要輸出的值與后臺代碼的屬性綁定在一起。?運行程序!
運行war文件所映射的程序。Index.jsp頁面將調用calculator.jsp,如果你在firstNumber域或secondNumber域中輸入非法文本(如“abc”)提交,你將返回到/calculator.jsp視圖并且相應的錯誤信息將會顯示在頁面上。如果你將firstNumber或secondNumber放空提交你也將會獲得相應的錯誤結果。由此可以看出在JSF許多校驗幾乎是自動定義,只要你將輸入域定義為required并且綁定相應的int屬性的字段即可。
Figure 4顯示應用程序如何處理校驗和數據轉換數據。
Figure 4. Validation and
data conversion errors

?
總結
在這篇關于JSF的介紹中是否使你有些頭暈?不用擔心,你已經跨過了最壞的一道坎。了解JSF的框架概念是這場戰役的一半,有過之而無不及,而且你將會很快意識到它的價值。
如果在閱讀的過程中你想象使用Struts實現上述代碼會更加簡單,我估計它會耗費至少兩倍精力。用Struts構建同樣的應用,你需要為兩個按鈕創建兩個action類,各自需要自己的對應的動作映射。而且需要一個動作映射來裝載首頁(假設你遵守Model 2的建議)。另外,模仿JSF默認的錯誤獲取和校驗機制,你需要為Struts配置校驗框架或者實現在ActionForm中實現等值的validate方法。你還必須在Struts配置中定義DynaValidatorForm或者建立一個ActionForm重寫validate方法,或者使用ValidatorForm的子類。最終,你或許(必須)需要為所有的action定義forward或者全局forward。
不止雙倍的代碼工作,Struts對于初學者來說意味著需要花費更多的精力。我之所以知道這點,是因為我寫過關于Struts和JSF課程的教材并且為我的學員們上過課。開發人員通常非常容易掌握JSF,但在學習Struts的過程中卻倍受折磨。我相信更多有遠見的人選擇JSF,而非Struts。直覺上說,JSF更加合理。Struts已經被擱置,JSF被列入技術清單。在我的書中,JSF開發過程是簡便的,并且比Struts更具有生產率。
這是JSF系列的第一篇文章的總結。在下一篇文章里我會繼續這篇文章的話題,內容覆蓋JSF的request處理生命周期,指明生命周期中同一應用程序的不同部分。我還將介紹immediate
event handling的概念,并且讓你對JSF的組件事件模型有更全面了解,包括關于許多內嵌組件的討論。我還將談談有關JSF與JavaScript相結合的話題,請關注下個月的文章。