|
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- this content will be automatically generated across all content areas --><!-- END RESERVED FOR FUTURE USE INCLUDE FILES-->
|
級別: 中級
David Geary
, 總裁, Clarity Training, Inc.
2009 年 8 月 03 日
Java?Server Faces (JSF) 2 專家組成員 David Geary 將在這一期文章中結(jié)束這部有關(guān) JSF 2 新特性的
系列文章(共 3 部分)
。本文介紹如何使用該框架的新事件模型和內(nèi)置 Ajax 支持來增強(qiáng)可重用組件的功能。
<!-- START RESERVED FOR FUTURE USE INCLUDE FILES--><!-- include java script once we verify teams wants to use this and it will work on dbcs and cyrillic characters --> <!-- END RESERVED FOR FUTURE USE INCLUDE FILES-->
JSF 的最大賣點(diǎn)在于它是一種基于組件的框架。這意味著您可以實(shí)現(xiàn)供其他人重用的組件。這種強(qiáng)大的重用機(jī)制在 JSF 1 中基本上是不可能實(shí)現(xiàn)的,因?yàn)樵?JSF 1 中實(shí)現(xiàn)組件是非常困難的事情。
然而,正如
第 2 部分
所述,JSF 2 通過一種名為
復(fù)合組件
的新特性簡化了組件的實(shí)現(xiàn) — 無需 Java 代碼和配置。這一特性可以說是 JSF 2 中最重要的部分,因?yàn)樗嬲龑?shí)現(xiàn)了 JSF 組件的潛力。
在這份有關(guān) JSF 2 的第三篇也是最后一篇文章中,我將展示如何利用新的 Ajax 和事件處理功能(也在 JSF 2 中引入)構(gòu)建復(fù)合組件特性,要從 JSF 2 中獲得最大收益,需要遵循下面的技巧:
-
技巧 1:組件化
-
技巧 2:Ajax 化
-
技巧 3:展示進(jìn)度
對于第一個(gè)技巧,我將簡要回顧已在
第 2 部分
中詳細(xì)描述過的兩個(gè)組件。對于后面的技巧,我將展示如何使用 Ajax 和事件處理功能來改造這些組件。
技巧 1:組件化
我在
第 1 部分
中引入的 places 應(yīng)用程序包含有大量復(fù)合組件。其中之一便是
map
組件,它顯示一個(gè)地址地圖,其中包含一個(gè)縮放級別下拉菜單,如圖 1 所示:
圖 1. places 應(yīng)用程序的
map
組件
清單 1 顯示了經(jīng)過刪減的
map
組件列表:
清單 1.
map
組件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns="http://www.w3.org/1999/xhtml"
...
xmlns:composite="http://java.sun.com/jsf/composite"
xmlns:places="http://java.sun.com/jsf/composite/components/places">
<!-- INTERFACE -->
<composite:interface>
<composite:attribute name="title"/>
</composite:interface>
<!-- IMPLEMENTATION -->
<composite:implementation">
<div class="map">
...
<h:panelGrid...>
<h:panelGrid...>
<
h:selectOneMenu
onchange="submit()"
value="#{cc.parent.attrs.location.
zoomIndex
}"
valueChangeListener="#{cc.parent.attrs.location.zoomChanged}"
style="font-size:13px;font-family:Palatino">
<f:selectItems value="#{places.zoomLevelItems}"/>
</h:selectOneMenu>
</h:panelGrid>
</h:panelGrid>
<
h:graphicImage
url="#{cc.parent.attrs.location.mapUrl}"
style="border: thin solid gray"/>
...
</div>
...
</composite:implementation>
</html>
|
組件的一大優(yōu)點(diǎn)就是可以使用更有效的替代方法替換它們,同時(shí)不會影響到相關(guān)的功能。比如,在圖 2 中,我使用一個(gè) Google Maps 組件替換了
清單 1
中的
image
組件,Google Maps 組件由 GMaps4JSF 提供(見
參考資料
):
圖 2. GMaps4JSF 的 map 圖像
map
組件的更新后的代碼(進(jìn)行了刪減)如清單 2 所示:
清單 2. 使用一個(gè) GMaps4JSF 組件替換 map 圖形
<h:selectOneMenu
onchange="submit()"
value
="#{cc.parent.attrs.location.
zoomIndex
}"
valueChangeListener="#{cc.parent.attrs.location.zoomChanged}"
style="font-size:13px;font-family:Palatino">
<f:selectItems value="#{places.zoomLevelItems}"/>
</h:selectOneMenu>
...
<
m:map
id="map" width="420px" height="400px"
address="#{cc.parent.attrs.location.streetAddress}, ..."
zoom
="#{cc.parent.attrs.location.
zoomIndex
}"
renderOnWindowLoad="false">
<m:mapControl id="smallMapCtrl"
name="GLargeMapControl"
position="G_ANCHOR_TOP_RIGHT"/>
<m:mapControl id="smallMapTypeCtrl" name="GMapTypeControl"/>
<m:marker id="placeMapMarker"/>
</m:map>
|
要使用 GMaps4JSF 組件,我從 GMaps4JSF 組件集合中使用
<m:map>
標(biāo)記替換了
<h:graphicImage>
標(biāo)記。將 GMaps4JSF 組件與縮放下拉菜單連接起來也很簡單,只需為
<m:map>
標(biāo)記的
zoom
屬性指定正確的 backing-bean 屬性。
關(guān)于縮放級別需要注意一點(diǎn),那就是當(dāng)一名用戶修改縮放級別時(shí),我將通過
<h:selectOneMenu>
的
onchange
屬性強(qiáng)制執(zhí)行表單提交,如
清單 1
中第一處使用粗體顯示的代碼行所示。這個(gè)表單提交將觸發(fā) JSF 生命周期,這實(shí)際上將把新的縮放級別推入到保存在父復(fù)合組件中的
location
bean 的
zoomIndex
屬性中。這個(gè) bean 屬性被綁定到輸入組件,如
清單 2
中的第一行所示。
由于我沒有為與縮放級別修改相關(guān)的表單提交指定任何導(dǎo)航,JSF 在處理請求后刷新了同一頁面,重新繪制地圖以反映新的縮放級別。然而,頁面刷新還重新繪制了整個(gè)頁面,即使只修改了地圖圖像。在
技巧 2:Ajax 化
中,我將展示如何使用 Ajax,只對圖像部分重新繪制,以響應(yīng)縮放級別的修改。
login
組件
places 應(yīng)用程序中使用的另一個(gè)組件是
login
組件。圖 3 展示了這個(gè) login 組件的實(shí)際使用:
圖 3.
login
組件
清單 3
展示了創(chuàng)建
圖 3
所示的
login
組件的標(biāo)記:
清單 3. 最基礎(chǔ)的
login
:只包含必需的屬性
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:util="http://java.sun.com/jsf/composite/components/util">
<util:login
loginAction
="#{user.login}"
managedBean
="#{user}"/>
</ui:composition>
|
login
組件只包含兩個(gè)必需的屬性:
-
loginAction
:登錄 action 方法
-
managedBean
:包含名稱和密碼屬性的托管
清單 3
中指定的托管 bean 如清單 4 所示:
清單 4. User.groovy
package com.clarity
import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
@ManagedBean()
@SessionScoped
public class User {
private final String VALID_NAME = "Hiro"
private final String VALID_PASSWORD = "jsf"
private String
name, password
;
public String getName() { name }
public void setName(String newValue) { name = newValue }
public String getPassword() { return password }
public void setPassword(String newValue) { password = newValue }
public String
login()
{
"/views/places"
}
public String logout() {
name = password = nameError = null
"/views/login"
}
}
|
清單 4
中的托管 bean 是一個(gè) Groovy bean。在這里使用 Groovy 替代 Java 語言并不會帶來多少好處,只是減少了處理分號和返回語句的麻煩。然而,在技巧 2 的
Validation
部分中,我將展示一個(gè)對
User
托管 bean 使用 Groovy 的更有說服力的原因。
大多數(shù)情況下,您將需要使用提示和按鈕文本來配置登錄組件,如圖 4 所示:
圖 4. 充分配置的
login
組件
清單 5 展示了生成
圖 4
所示的
login
組件的標(biāo)記:
清單 5. 配置
login
組件
<ui:composition xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:util="http://java.sun.com/jsf/composite/components/util">
<util:login loginPrompt="#{msgs.loginPrompt}"
namePrompt="#{msgs.namePrompt}"
passwordPrompt="#{msgs.passwordPrompt}"
loginButtonText="#{msgs.loginButtonText}"
loginAction="#{user.login}"
managedBean="#{user}"/>
</ui:composition>
|
在
清單 5
中,我從一個(gè)資源包中獲取了用于提示的字符串和登錄按鈕的文本。
清單 6 定義了
login
組件:
清單 6. 定義
login
組件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- Usage:
<util:login loginPrompt="#{msgs.loginPrompt}"
namePrompt="#{msgs.namePrompt}"
passwordPrompt="#{msgs.passwordPrompt}"
loginButtonText="#{msgs.loginButtonText}"
loginAction="#{user.login}"
managedBean="#{user}">
<f:actionListener for="loginButton"
type="com.clarity.LoginActionListener"/>
</util:login>
managedBean must have two properties: name and password.
The loginAction attribute must be an action method that takes no
arguments and returns a string. That string is used to navigate
to the page the user sees after logging in.
This component's loginButton is accessible so that you can
add action listeners to it, as depicted above. The class specified
in f:actionListener's type attribute must implement the
javax.faces.event.ActionListener interface.
-->
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:composite="http://java.sun.com/jsf/composite">
<!-- INTERFACE -->
<
composite:interface
>
<!-- PROMPTS -->
<composite:attribute name="loginPrompt"/>
<composite:attribute name="namePrompt"/>
<composite:attribute name="passwordPrompt"/>
<!-- LOGIN BUTTON -->
<composite:attribute name="loginButtonText"/>
<!-- loginAction is called when the form is submitted -->
<composite:attribute name="loginAction"
method-signature="java.lang.String login()"
required="true"/>
<!-- You can add listeners to this actionSource: -->
<composite:actionSource name="loginButton" targets="form:loginButton"/>
<!-- BACKING BEAN -->
<composite:attribute name="managedBean" required="true"/>
</composite:interface>
<!-- IMPLEMENTATION -->
<
composite:implementation
>
<div class="prompt">
#{
cc.attrs.loginPrompt
}
</div>
<!-- FORM -->
<h:form id="form">
<h:panelGrid columns="2">
<!-- NAME AND PASSWORD FIELDS -->
#{
cc.attrs.namePrompt
}
<h:inputText id="name"
value="#{
cc.attrs.managedBean.name
}"/>
#{
cc.attrs.passwordPrompt
}
<h:inputSecret id="password" size="8"
value="#{
cc.attrs.managedBean.password
}"/>
</h:panelGrid>
<p>
<!-- LOGIN BUTTON -->
<h:commandButton id="loginButton"
value="#{
cc.attrs.loginButtonText
}"
action="#{
cc.attrs.loginAction
}"/>
</p>
</h:form>
</composite:implementation>
</html>
|
和
map
組件一樣,
login
也可以使用一個(gè) Ajax 升級。在下一個(gè)技巧介紹
Validation
時(shí),我將展示如何將 Ajax 驗(yàn)證添加到 login 組件中。
技巧 2:Ajax 化
與非 Ajax HTTP 請求相比,Ajax 請求通常需要額外執(zhí)行兩個(gè)步驟:在服務(wù)器中對表單進(jìn)行局部處理,接著在客戶機(jī)上對 Document Object Model (DOM) 進(jìn)行局部呈現(xiàn)。
局部處理和呈現(xiàn)
通過將 JSF 生命周期分解為兩個(gè)不同的邏輯部分 —— 執(zhí)行和呈現(xiàn),JSF 2 現(xiàn)在支持局部處理和局部呈現(xiàn)。圖 5 突出顯示了執(zhí)行部分:
圖 5. JSF 生命周期的執(zhí)行部分
圖 6 突出顯示了 JSF 生命周期的呈現(xiàn)部分:
圖 6. JSF 生命周期的呈現(xiàn)部分
將生命周期劃分為執(zhí)行和呈現(xiàn)部分的原理很簡單:您可以指定 JSF 在服務(wù)器上執(zhí)行(處理)的組件,以及在返回 Ajax 調(diào)用時(shí) JSF 呈現(xiàn)的組件。將使用 JSF 2 中新增的
<f:ajax>
實(shí)現(xiàn)這個(gè)目的,如清單 7 所示:
清單 7. 一個(gè) Ajax 縮放菜單
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
value
="#{cc.parent.attrs.location.zoomIndex}"
style="font-size:13px;font-family:Palatino">
<f:ajax event="change" execute="@this" render="map"/>
<f:selectItems value="#{places.zoomLevelItems}"/>
</h:selectOneMenu>
<m:map id="
map
"...>
|
清單 7
對
清單 2
中的第一行所示的菜單進(jìn)行了修改:我從
清單 2
中刪除了
onchange
屬性,并添加了一個(gè)
<f:ajax>
標(biāo)記。這個(gè)
<f:ajax>
標(biāo)記指定了以下內(nèi)容:
-
觸發(fā) Ajax 調(diào)用的事件
-
在服務(wù)器上執(zhí)行的組件
-
在客戶機(jī)上呈現(xiàn)的組件
當(dāng)用戶從縮放菜單中選擇一個(gè)菜單項(xiàng)時(shí),JSF 將對服務(wù)器發(fā)出 Ajax 調(diào)用。隨后,JSF 將菜單傳遞給生命周期的執(zhí)行部分(
@this
表示
<f:ajax>
周圍的組件),并在生命周期的 Update Model Values 階段更新菜單的
zoomIndex
。當(dāng) Ajax 調(diào)用返回后,JSF 呈現(xiàn)地圖組件,后者使用(新設(shè)置的)縮放指數(shù)重新繪制地圖,現(xiàn)在您就有了一個(gè) Ajax 化的縮放菜單,其中添加了一行 XHTML。
但是還可以進(jìn)一步簡化,因?yàn)?JSF 為
event
和
execute
屬性提供了默認(rèn)值。
每個(gè) JSF 組件都有一個(gè)默認(rèn)事件,當(dāng)在組件標(biāo)記內(nèi)部嵌入
<f:ajax>
標(biāo)記時(shí),該事件將觸發(fā) Ajax 調(diào)用。對于菜單,該事件為
change
事件。這意味著我可以刪除
清單 7
中的
<f:ajax>
的
event
屬性。
<f:ajax>
的
execute
屬性的默認(rèn)值是
@this
,這表示圍繞在
<f:ajax>
周圍的組件。在本例中,該組件為菜單,因此還可以刪除
execute
屬性。
通過對
<f:ajax>
使用默認(rèn)屬性值,我可以將
清單 7
簡化為清單 8:
清單 8. 簡化后的 Ajax 縮放菜單
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
value="#{cc.parent.attrs.location.zoomIndex}"
style="font-size:13px;font-family:Palatino">
<f:ajax render="map"/>
<f:selectItems value="#{places.zoomLevelItems}"/>
</h:selectOneMenu>
<m:map id="map"...>
|
這演示了使用 JSF 2 向組件添加 Ajax 有多么容易。當(dāng)然,前面的例子非常簡單:我僅僅是在用戶選擇某個(gè)縮放級別時(shí)重新繪制了地圖而不是整個(gè)頁面。驗(yàn)證表單中的各個(gè)字段等操作要更加復(fù)雜一些,因此接下來我將討論這些用例。
驗(yàn)證
當(dāng)用戶移出某個(gè)字段后對字段進(jìn)行驗(yàn)證并提供即時(shí)的反饋,這始終是一個(gè)好的做法。例如,在圖 7 中,我使用了 Ajax 對名稱字段進(jìn)行了驗(yàn)證:
圖 7. Ajax 驗(yàn)證
該名稱字段的標(biāo)記如清單 9 所示:
清單 9. 名稱字段
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:panelGrid columns="2">
#{cc.attrs.namePrompt}
<h:panelGroup>
<h:inputText id="name" value="#{cc.attrs.managedBean.name}"
valueChangeListener
="#{cc.attrs.managedBean.validateName}">
<
f:ajax
event="
blur
" render="
nameError
"/>
</h:inputText>
<h:outputText id="
nameError
"
value="#{cc.attrs.managedBean.
nameError
}"
style="color: red;font-style: italic;"/>
</h:panelGroup>
...
</h:panelGrid>
|
我再一次使用了
<f:ajax>
,只不過這一次沒有執(zhí)行輸入的默認(rèn)事件 —
change
,因此我將
blur
指定為觸發(fā) Ajax 調(diào)用的事件。當(dāng)用戶移出名稱字段時(shí),JSF 將對服務(wù)器發(fā)出 Ajax 調(diào)用并在生命周期的執(zhí)行部分運(yùn)行
name
輸入組件。這意味著 JSF 將在生命周期的 Process Validations 階段調(diào)用
name
輸入的值修改監(jiān)聽程序(在
清單 9
中指定)。清單 10 展示了這個(gè)值修改監(jiān)聽程序:
清單 10.
validateName()
方法
package com.clarity
import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
import javax.faces.event.ValueChangeEvent
import javax.faces.component.UIInput
@ManagedBean()
@SessionScoped
public class User {
private String name, password, nameError;
...
public void
validateName
(ValueChangeEvent e) {
UIInput nameInput = e.getComponent()
String name = nameInput.getValue()
if (name.contains("_"))
nameError
= "Name cannot contain underscores"
else if (name.equals(""))
nameError
= "Name cannot be blank"
else
nameError
= ""
}
...
}
|
這個(gè)修改值的監(jiān)聽程序(
user
托管 bean 的
validateName()
方法)將驗(yàn)證名稱字段并更新
user
托管 bean 的
nameError
屬性。
返回 Ajax 調(diào)用后,借助
清單 9
中的
<f:ajax>
標(biāo)記的
render
屬性,JSF 呈現(xiàn)
nameError
輸出。該輸出顯示了
user
托管 bean 的
nameError
屬性。
多字段驗(yàn)證
在前面的小節(jié)中,我展示了如何對單一字段執(zhí)行 Ajax 驗(yàn)證。但是,有些情況下,需要同時(shí)對多個(gè)字段進(jìn)行驗(yàn)證。比如,圖 8 展示了 places 應(yīng)用程序同時(shí)驗(yàn)證名稱和密碼字段:
圖 8. 驗(yàn)證多個(gè)字段
我在用戶提交表單時(shí)同時(shí)驗(yàn)證了名稱和密碼字段,因此對這個(gè)例子不需要用到 Ajax。相反,我將使用 JSF 2 的新事件系統(tǒng),如清單 11 所示:
清單 11. 使用
<f:event>
<h:form id="form" prependId="false">
<
f:event
type="
postValidate
"
listener="#{cc.attrs.managedBean.validate}"/>
...
</h:form>
<div class="error" style="padding-top:10px;">
<h:messages layout="table"/>
</div>
|
在
清單 11
中,我使用了
<f:event>
— 類似于
<f:ajax>
,它是 JSF 2 中新增的內(nèi)容。
<f:event>
標(biāo)記在另一方面還類似于
<f:ajax>
:使用起來很簡單。
將一個(gè)
<f:event>
標(biāo)記放到組件標(biāo)記的內(nèi)部,當(dāng)該組件發(fā)生指定的事件(使用
type
屬性指定)時(shí),JSF 將調(diào)用一個(gè)使用
listener
屬性指定的方法。因此,
<f:event>
標(biāo)記在
清單 11
中的含義就是:對表單進(jìn)行驗(yàn)證后,對用戶傳遞給這個(gè)復(fù)合組件的托管 bean 調(diào)用
validate()
方法。該方法如清單 12 所示:
清單 12.
validate()
方法
package com.clarity
import javax.faces.context.FacesContext
import javax.faces.bean.ManagedBean
import javax.faces.bean.SessionScoped
import javax.faces.event.ValueChangeEvent
import javax.faces.component.UIInput
@ManagedBean()
@SessionScoped
public class User {
private final String VALID_NAME = "Hiro";
private final String VALID_PASSWORD = "jsf";
...
public void
validate
(ComponentSystemEvent e) {
UIForm form = e.getComponent()
UIInput nameInput = form.findComponent("name")
UIInput pwdInput = form.findComponent("password")
if ( ! (nameInput.getValue().equals(VALID_NAME) &&
pwdInput.getValue().equals(VALID_PASSWORD))) {
FacesContext fc = FacesContext.getCurrentInstance()
fc.addMessage(form.getClientId(),
new FacesMessage("Name and password are invalid. Please try again."))
fc.renderResponse()
}
}
...
}
|
JSF 將一個(gè)組件系統(tǒng)事件傳遞給
清單 12
中的
validate()
方法,方法從這個(gè)事件中獲得對(適用于事件的)組件的引用 — 登錄表單。對于這個(gè)表單,我使用
findComponent()
方法獲得名稱和密碼組件。如果這些組件的值不為 Hiro 和 jsf,那么我將把一條消息存儲到 faces 上下文并要求 JSF 繼續(xù)處理生命周期的 Render Response 階段。通過這種方法,就可以避免 Update Model Values 階段,后者會將壞的名稱和密碼傳遞給模型(見
圖 5
)。
您可能已經(jīng)注意到,
清單 10
和
清單 12
中的驗(yàn)證方法是使用 Groovy 編寫的。與
清單 4
不同,后者使用 Groovy 的惟一好處就是避免了分號和返回語句,
清單 10
和
清單 12
中的 Groovy 代碼使我不必進(jìn)行類型轉(zhuǎn)換。例如,在
清單 10
中,
ComponentSystemEvent.getComponent()
和
UIComponent.findComponent()
都返回類型
UIComponent
。對于 Java 語言,我需要轉(zhuǎn)換這些方法的返回值。Groovy 為我做了這一轉(zhuǎn)換工作。
技巧 3:展示進(jìn)度
在
Ajax 化
中,我展示了如何為
map
組件 Ajax 化縮放菜單,因此,當(dāng)用戶修改縮放級別時(shí),places 應(yīng)用程序?qū)⒅恢匦吕L制頁面的地圖部分。另一個(gè)常見 Ajax 用例是向用戶提供反饋,表示一個(gè) Ajax 事件正在處理中,如圖 9 所示:
圖 9. 進(jìn)度條
在
圖 9
中,我將使用一個(gè)動(dòng)畫 GIF 替換縮放菜單,這個(gè)動(dòng)畫 GIF 將在 Ajax 調(diào)用期間顯示。當(dāng) Ajax 調(diào)用完成后,我將使用縮放菜單替換進(jìn)度指示器。清單 13 展示了這一過程:
清單 13. 監(jiān)視 Ajax 調(diào)用
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<h:selectOneMenu id="menu"
value="#{cc.parent.attrs.location.zoomIndex}"
style="font-size:13px;font-family:Palatino">
<f:ajax render="map"
onevent="zoomChanging"
/>
<f:selectItems value="#{places.zoomLevelItems}"/>
...
</h:selectOneMenu>
...
<h:graphicImage id="
progressbar
" style="display: none"
library="images" name="orange-barber-pole.gif"/>
|
在
清單 13
中,我添加了一個(gè)進(jìn)度條圖像(該圖像最初不會顯示出來),并為
<f:ajax>
指定了
onevent
屬性。該屬性引用一個(gè) JavaScript 函數(shù),如
清單 14
所示,這個(gè)函數(shù)將在
清單 13
中的 Ajax 調(diào)用被初始化時(shí)由 JSF 調(diào)用:
清單 14. 響應(yīng) Ajax 請求的 JavaScript
function zoomChanging(data) {
var menuId = data.source.id;
var progressbarId = menuId.substring(0, menuId.length - "menu".length)
+ "progressbar";
if (data.name == "begin") {
Element.hide(menuId);
Element.show(progressbarId);
}
else if (data.name == "success") {
Element.show(menuId);
Element.hide(progressbarId);
}
}
|
JSF 向
清單 14
中的函數(shù)傳遞一個(gè)對象,該對象中包含有一些信息,比如觸發(fā)了事件的組件的客戶機(jī)標(biāo)識符(在本例中為縮放級別菜單),以及 Ajax 請求的當(dāng)前狀態(tài),使用
name
屬性表示。
清單 14
中的
zoomChanging()
函數(shù)計(jì)算進(jìn)度條圖像的客戶機(jī)標(biāo)識符,然后使用 Prototype
Element
對象在 Ajax 調(diào)用期間隱藏和顯示對應(yīng)的 HTML 元素。
結(jié)束語
在過去幾年中,人們認(rèn)為 JSF 1 是一個(gè)難以使用的框架。在許多方面上,這種評價(jià)是有一定道理的。JSF 1 在開發(fā)期間完全沒有考慮到實(shí)際使用中遇到的問題。因此,JSF 在實(shí)現(xiàn)應(yīng)用程序和組件方面比預(yù)先設(shè)想更加困難。
另一方面,JSF 2 經(jīng)歷了那些在 JSF 1 基礎(chǔ)之上實(shí)現(xiàn)過開源項(xiàng)目的開發(fā)人員的實(shí)際體驗(yàn)。總結(jié)經(jīng)驗(yàn)之后,JSF 2 是一個(gè)更加合理的框架,可以輕松地實(shí)現(xiàn)健壯的、Ajax 化的應(yīng)用程序。
貫 穿本系列文章,我展示了一些最突出的 JSF 2 特性,比如注釋和替換配置約定、簡化后的導(dǎo)航、資源支持、復(fù)合組件、內(nèi)置 Ajax 以及內(nèi)嵌的事件模型。但是仍然有許多 JSF 2 特性未在本系列提及,比如 View 和 Page 范圍、為頁面添加書簽的支持和 Project Stage。所有這些特性以及其他更多特性讓 JSF 2 在 JSF 1 的基礎(chǔ)上實(shí)現(xiàn)了巨大的改進(jìn)。
下載
描述 名字 大小 下載方法
本文示例的源代碼
j-jsf2-fu-3.zip
|
7.7MB
|
HTTP
|
參考資料
學(xué)習(xí)
獲得產(chǎn)品和技術(shù)
討論
關(guān)于作者
|
|
|
David Geary 是一名作家、演講家和顧問,也是
Clarity Training, Inc.
的總裁,他指導(dǎo)開發(fā)人員使用 JSF 和 Google Web Toolkit (GWT) 實(shí)現(xiàn) Web 應(yīng)用程序。他是 JSTL 1.0 和 JSF 1.0/2.0 專家組的成員,與人合作編寫了 Sun 的 Web Developer 認(rèn)證考試的內(nèi)容,并且為多個(gè)開源項(xiàng)目作出貢獻(xiàn),包括 Apache Struts 和 Apache Shale。David 的
Graphic Java Swing
一直是關(guān)于 Java 的暢銷書籍,而
Core JSF
(與 Cay Horstman 合著)是關(guān)于 JSF 的暢銷書。David 經(jīng)常在各大會議和用戶組發(fā)表演講。他從 2003 年開始就一直是 NFJS tour 的固定演講人,并且在 Java University 教授課程,兩次當(dāng)選為 JavaOne 之星。
|
|