在這個(gè)分五部分的教程系列的前兩期中,研究了 JavaServer? Faces(JSF),這是一種新的基于 Java? 的框架,可以簡(jiǎn)化為 Java Platform, Enterprise Edition(Java EE)應(yīng)用程序構(gòu)建圖形用戶界面(GUI)的過程。我們構(gòu)建并成功地在 Apache Geronimo 上部署了一個(gè)簡(jiǎn)單的 JSF 應(yīng)用程序,并學(xué)習(xí)了如何將 Apache Tomahawk(它提供幾個(gè)與 JSF 100% 兼容的組件)與應(yīng)用程序進(jìn)行集成以改進(jìn)界面。在本教程(第 3 部分)中,將了解 Sun Ajax4jsf 開放源碼框架,這個(gè)框架為 JSF 應(yīng)用程序添加 Asynchronous JavaScript? + XML(Ajax)功能,而無(wú)需編寫任何 JavaScript 代碼。將使用 Ajax4jsf 改進(jìn)示例應(yīng)用程序并創(chuàng)建一個(gè)啟用 Ajax 的前端。
開始之前
本教程向 Java 程序員講解如何使用 JSF 組件構(gòu)建高度交互性的部署在 Apache Geronimo 上的 Java EE 應(yīng)用程序。本教程假設(shè)讀者將使用 Eclipse IDE 作為開發(fā)平臺(tái)。
關(guān)于本教程
本教程講解 Sun Ajax4jsf 開放源碼框架,這個(gè)框架為 JSF 應(yīng)用程序添加 Ajax 功能,而無(wú)需編寫任何 JavaScript 代碼。我們將繼續(xù)改進(jìn) 第 2 部分 開發(fā)的示例應(yīng)用程序,增加一個(gè)對(duì)溫度進(jìn)行轉(zhuǎn)換并以圖形化方式顯示結(jié)果的實(shí)用程序。
關(guān)于本系列
本教程是關(guān)于使用 JSF 構(gòu)建 Apache Geronimo 應(yīng)用程序的分五部分的教程系列的第 3 部分。整個(gè)系列教程包括以下幾個(gè)部分:
第 1 部分:使用 Eclipse 和 Apache MyFaces Core 構(gòu)建基本的應(yīng)用程序 介紹如何使用 JSF 標(biāo)準(zhǔn)的 Apache MyFaces 實(shí)現(xiàn)以及 Geronimo(一種也是來(lái)自 Apache 的免費(fèi)應(yīng)用服務(wù)器)。這個(gè)教程講解如何使用 Eclipse IDE 的 Web Tool Platform(WTP)來(lái)構(gòu)建 JSF 應(yīng)用程序。
第 2 部分:在 JavaServer Faces 中使用 Tomahawk 展示如何在 Geronimo 應(yīng)用程序中集成 Apache Tomahawk。Tomahawk 提供了幾個(gè)與 JSF 100% 兼容的定制組件。
第 3 部分:在 JavaServer Faces 中使用 ajax4jsf 演示如何使用 Sun 的免費(fèi)開放源碼框架 ajax4jsf 在 Geronimo 應(yīng)用程序中添加 Asynchronous JavaScript + XML(Ajax)功能。
第 4 部分:使用 Application Development Framework(ADF)Faces 擴(kuò)展 JSF 講解怎樣將 ADF Faces 中的組件集成到 Geronimo 應(yīng)用程序中。Oracle 的 ADF Faces 是構(gòu)建于 JSF 之上的一組非常豐富的 UI 組件(它是用 Trinidad 這個(gè)名稱捐獻(xiàn)給 Apache 的代碼的一部分)。
第 5 部分:將 JSF 應(yīng)用程序與 Spring 集成 展示如何將 JSF 應(yīng)用程序與 Spring 框架集成。Spring 是一個(gè)流行的框架,它使 Geronimo 開發(fā)者能更容易地構(gòu)建 Java EE 應(yīng)用程序。
系統(tǒng)需求
為了學(xué)習(xí)本教程,需要有下列工具:
第 2 部分 源代碼,我們將對(duì)這個(gè)應(yīng)用程序進(jìn)行改進(jìn)。
Geronimo,Apache 的 Java EE 服務(wù)器項(xiàng)目。根據(jù)需要,Geronimo 提供 Tomcat 和 Jetty 兩種風(fēng)格。我們采用的是 Jetty 風(fēng)格(1.1 版),因?yàn)樗∫稽c(diǎn)兒。
MyFaces,Apache 的 JSF 實(shí)現(xiàn)。請(qǐng)從 Apache 下載核心版本(不帶 Tomcat)。本教程中使用的版本是 1.1.3 版。
Tomahawk,它提供用于 MyFaces 的額外組件和輸入驗(yàn)證器,同時(shí)與 JSF 100% 兼容。
Eclipse,這是一個(gè)可支持大量語(yǔ)言和平臺(tái)的可擴(kuò)展開放源碼 IDE。
Eclipse Web Tools Platform(WTP),它給 Eclipse 添加了對(duì) XML 和 JavaScript 編輯的支持以及對(duì) JSF 的基本支持。
Ajax4jsf,這是 Sun 的開放源碼框架,用于在現(xiàn)有的 JSF 應(yīng)用程序中添加 Ajax 功能。在編寫本文時(shí)的當(dāng)前版本是 1.0rc4。
將 Java 1.4 或更新版本 安裝到您的系統(tǒng)中。Eclipse 二進(jìn)制文件中帶有自己的 Java 運(yùn)行時(shí),但 Geronimo 和 MyFaces 則沒有(帶運(yùn)行時(shí)會(huì)使下載歸檔文件的尺寸顯著變大)。
Ajax4jsf —— 概述
Ajax4jsf 允許開發(fā)人員將 Ajax 功能添加到 JSF 應(yīng)用程序中,而不需要 JavaScript 或用 Ajax 圖形部件替換現(xiàn)有的組件。這個(gè)包還允許在使用 Java 2D 庫(kù)時(shí)動(dòng)態(tài)地生成圖像。Ajax 是一種編程技術(shù),它處理只有頁(yè)面的一部分需要處理而不需要重新裝載整個(gè)頁(yè)面的情況。這種方式的好處包括減少服務(wù)器上的處理時(shí)間以及加快客戶端的響應(yīng)速度。
與 Tomahawk 相似,Ajax4jsf 提供了一套可以很容易地與 JSF 標(biāo)記一起使用的標(biāo)記。在本教程后面對(duì) Developer Forum Signup 示例應(yīng)用程序進(jìn)行改進(jìn)時(shí),將討論這些標(biāo)記的示例以及如何將 Ajax4jsf 與 Eclipse 進(jìn)行集成。接下來(lái),將學(xué)習(xí)組成這個(gè)庫(kù)的每個(gè)組件、在使用它時(shí)必須記住的限制以及如何在 Eclipse 項(xiàng)目中添加 Ajax4jsf。
組件
Ajax4jsf 組件被設(shè)計(jì)成可以輕松地與現(xiàn)有的 JSF 應(yīng)用程序進(jìn)行集成,同時(shí)提供了改進(jìn)性能的 Ajax 功能。表 1 中描述了 Ajax4jsf 庫(kù)中包含的所有標(biāo)記。
表 1. Ajax4jsf 庫(kù)標(biāo)記
Ajax4jsf 組件 | 描述 |
<a4j:actionListener> | 其效果類似于 JSF 中的 <f:actionListener> 或 <f:valueChangeListener> 標(biāo)記,但是它用于 Ajax 容器。 |
<a4j:actionparam> | 結(jié)合了 <f:actionListener> 和 <f:param> JSF 標(biāo)記的功能。 |
<a4j:commandButton> | 效果類似于被點(diǎn)擊時(shí)的表單 Submit 按鈕,但是呈現(xiàn)為 HTML <input> 標(biāo)記。 |
<a4j:commandLink> | 效果類似于被點(diǎn)擊時(shí)的表單 Submit 按鈕,但是呈現(xiàn)為 HTML <a> 錨標(biāo)記。 |
<a4j:loadBundle> | 裝載當(dāng)前視圖的本地化資源束。 |
<a4j:mediaOutput> | 允許創(chuàng)建動(dòng)態(tài)生成的內(nèi)容。 |
<a4j:outputPanel> | 在頁(yè)面上創(chuàng)建一個(gè)啟用 Ajax 的部分,允許這個(gè)區(qū)域中的內(nèi)容重新呈現(xiàn)(即使導(dǎo)致 Ajax 請(qǐng)求的組件沒有專門提到這個(gè)區(qū)域)。 |
<a4j:page> | 呈現(xiàn)完整的 HTML 頁(yè)面結(jié)構(gòu)。但是,它必須是 JSF <f:view> 標(biāo)記的第一個(gè)和惟一的子元素,在它外邊不能有 HTML 代碼。 |
<a4j:region> | 決定 JSF <f:view> 的哪個(gè)部分將通過為相關(guān)聯(lián)的 Ajax 請(qǐng)求提供內(nèi)容來(lái)處理。這會(huì)只更新頁(yè)面中需要更新的部分,從而改進(jìn)性能。 |
<a4j:status> | 通過指出請(qǐng)求何時(shí)開始或結(jié)束,提供關(guān)于指定區(qū)域的 Ajax 請(qǐng)求的客戶端狀態(tài)。 |
<a4j:support> | 將 Ajax 功能添加到與 JSF 相關(guān)的組件中。這個(gè)標(biāo)記可能是最常用的。 |
根據(jù)場(chǎng)景,某些組件會(huì)比其他組件更常用。接下來(lái),將學(xué)習(xí)在使用 Ajax4jsf 時(shí)必須記住的條件。
條件
根據(jù) Ajax4jsf 文檔所述,開發(fā)人員必須記住某些限制才能創(chuàng)建正確的 Ajax 和 JSF 應(yīng)用程序:
Ajax4jsf 框架并不在頁(yè)面上追加或刪除元素,它只會(huì)替換頁(yè)面上的元素。要想在頁(yè)面上追加代碼,應(yīng)該使用一個(gè)空元素標(biāo)出它的位置。
應(yīng)該只創(chuàng)建嚴(yán)格的符合標(biāo)準(zhǔn)的 HTML 和 XHTML 代碼,不要省略任何必需的元素或?qū)傩?,因?yàn)?Ajax 請(qǐng)求由 XMLHttpRequest 函數(shù)以 XML 格式創(chuàng)建。但是,這些請(qǐng)求的 XML 格式可能會(huì)避開瀏覽器中的大多數(shù)檢驗(yàn)和任何糾正處理。
最后,大多數(shù) Ajax4jsf 標(biāo)記有一個(gè)屬性,它指定在發(fā)出 Ajax 請(qǐng)求之后要處理的元素的 ID。這些元素的 ID 必須匹配在 Ajax4jsf 標(biāo)記的屬性中指定的 ID,只有這樣更新才會(huì)成功。
既然已經(jīng)了解了組件和使用 Ajax4jsf 的條件,就需要將這個(gè)庫(kù)添加到 Eclipse 項(xiàng)目中,然后才能對(duì) Developer Forum Signup 應(yīng)用程序進(jìn)行改進(jìn)。
將 Ajax4jsf 添加到 Eclipse 項(xiàng)目中
本教程中的 第 2 部分 介紹了將 Tomahawk 作為 JSF 組件庫(kù)添加進(jìn)項(xiàng)目中的步驟。使用同樣的步驟將 Ajax 作為 JSF 組件庫(kù)添加進(jìn)項(xiàng)目中。
右擊 devSignup 項(xiàng)目,并在上下文菜單中選擇 Properties。Eclipse 顯示 Properties 對(duì)話框,見 圖 1。
圖 1. devSignup 的 Properties 對(duì)話框
訪問 JSF Library References 面板,見 圖 2。
圖 2. JSF Library References 面板
點(diǎn)擊面板中間偏下的 Component Libraries 部分中的 New 按鈕,顯示 Create JSF Library 對(duì)話框(見 圖 3)。
在 Library Name 字段中輸入庫(kù)名(例如,Ajax4jsf)。
圖 3. Create JSF Library 窗口
點(diǎn)擊 Add 按鈕,然后選擇發(fā)布版存檔中的以下 Ajax4jsf JAR:
ajax4jsf.jar
oscache-2.3.2.jar
根據(jù)需要重復(fù)這個(gè)步驟。
點(diǎn)擊 Finish 將新的 Ajax4jsf 庫(kù)添加到項(xiàng)目 Properties 的 JSF Library References 面板中的列表中。這個(gè)新的 Ajax4jsf 庫(kù)添加到右邊的列表中,它會(huì)自動(dòng)地包含在項(xiàng)目的 .war 文件中?,F(xiàn)在對(duì)話框應(yīng)該與 圖 4 相似。
點(diǎn)擊 OK 應(yīng)用修改并關(guān)閉項(xiàng)目 Properties 對(duì)話框。
圖 4. Ajax4jsf 和 Tomahawk 作為組件庫(kù)列出
為了啟用 Ajax4jsf 組件,必須在應(yīng)用程序的 web.xml 文件中聲明相應(yīng)的 <filter> 標(biāo)記。
打開 devSignup 項(xiàng)目下面的 WebContent/WEB-INF/web.xml。如果編輯器仍然處于 Design 模式,那么必須點(diǎn)擊編輯器底部的 Source 選項(xiàng)卡,切換到 Source 模式。
將 清單 1 中的代碼添加到 web.xml 文件中。<filter> 和 <filter-mapping> 元素應(yīng)該是 <web-app> 元素的子元素。
清單 1. 在 web.xml 中啟用 Ajax4jsf 組件
<filter>
<display-name>Ajax4jsf Filter</display-name>
<filter-name>ajax4jsf</filter-name>
<filter-class>org.ajax4jsf.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>ajax4jsf</filter-name>
<servlet-name>Faces Servlet</servlet-name>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
</filter-mapping>
一定要將 <filter> 和 <filter-mapping> 標(biāo)記放在 web.xml 文件中其他任何過濾器的前面。根據(jù)文檔所述,必須這樣做才能防止 web.xml 中其他任何過濾器與 Ajax4jsf 沖突。
<filter> 元素僅僅聲明 Ajax4jsf 過濾器類。<filter-mapping> 元素將 Ajax4jsf 過濾器與這個(gè)文件中其他地方聲明的 Faces Servlet 關(guān)聯(lián)起來(lái)。
既然已經(jīng)在項(xiàng)目中添加并配置了 Ajax4jsf,就可以開始改進(jìn) Developer Forum Signup 應(yīng)用程序了。下一節(jié)通過討論 Temperature Conversion 實(shí)用程序的細(xì)節(jié)來(lái)討論這個(gè)問題。
Temperature Conversion 實(shí)用程序
對(duì)于在 Developer Forum 應(yīng)用程序中登錄后的成員,提供 Temperature Conversion 實(shí)用程序作為實(shí)際功能。這個(gè)實(shí)用程序?qū)囟葟臄z氏溫度轉(zhuǎn)換為華氏溫度,或者相反。每種溫度轉(zhuǎn)換的結(jié)果顯示為一個(gè)動(dòng)態(tài)生成的溫度計(jì)圖像。首先,學(xué)習(xí)如何用 Ajax4jsf 實(shí)現(xiàn)這個(gè)用戶界面。然后,看看實(shí)現(xiàn)這個(gè)實(shí)用程序的 bean。
使用 Ajax4jsf 實(shí)現(xiàn)溫度轉(zhuǎn)換器頁(yè)面
本系列的 第 2 部分 擴(kuò)展了 Developer Forum Signup 應(yīng)用程序,添加了字段驗(yàn)證器和彈出式日歷來(lái)幫助用戶選擇生日。這些改進(jìn)都集中在注冊(cè)頁(yè)面上。現(xiàn)在,將創(chuàng)建一個(gè)新頁(yè)面,它允許用戶輸入攝氏或華氏溫度,然后就會(huì)看到轉(zhuǎn)換后的溫度顯示為數(shù)字和圖像。
首先,需要提供一個(gè)鏈接,它允許成員在成功登錄之后訪問這個(gè)實(shí)用程序。更新后的 signup-success.jsp 頁(yè)面使用與 清單 2 相似的一行代碼提供這個(gè)鏈接。
清單 2. 更新后的 signup-success 頁(yè)面的部分清單
*New* The Temperature Converter is
<a href="temperature-converter.faces">here</a>!
這個(gè)清單中惟一有意思的東西是溫度轉(zhuǎn)換器頁(yè)面的擴(kuò)展名。在 Eclipse 中,這個(gè)文件實(shí)現(xiàn)為 JSP。當(dāng)部署這個(gè)頁(yè)面時(shí),必須用 .faces 擴(kuò)展名引用它,從而讓 Faces Servlet 處理它。
現(xiàn)在看看溫度轉(zhuǎn)換器頁(yè)面的實(shí)現(xiàn)。清單 3 中給出這個(gè)頁(yè)面的部分清單。
清單 3. temperature-converter.jsp 的部分清單
<%@ taglib uri="https://ajax4jsf.dev.java.net/ajax" prefix="a4j"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Temperature Converter</title>
</head>
<body>
<h1>Temperature Converter</h1>
<hr/>
<p>The Temperature Converter is provided as a benefit for our
members in the Developer Forum!</p>
<f:view>
<a4j:region id="CtoF" selfRendered="true">
<a4j:mediaOutput element="img" cacheable="false" session="true"
createContent="#{temperature.drawFahrenheitThermometer}"
value="#{thermometer}" mimeType="image/jpeg" />
<a4j:status startText="Processing..." stopText="" for="CtoF"/>
<h:form>
<h:panelGrid columns="2">
<h:outputText value="Temperature in Fahrenheit:" />
<h:outputText id="tempFahr"
value="#{temperature.outputFahrenheit}"/>
<h:outputText value="Temperature in Celsius:" />
<h:inputText size="5" value="#{temperature.inputCelsius}">
<a4j:support event="onkeyup" reRender="tempFahr" />
</h:inputText>
</h:panelGrid>
</h:form>
</a4j:region>
</f:view>
<hr/>
<p>Thank you for using the Temperature Converter!</p>
</body>
</html>
這個(gè) JSP 清單中有幾個(gè)有意思的元素。第一個(gè)是開頭的 a4j <taglib> 聲明。對(duì)于任何使用 Ajax4jsf 組件庫(kù)的 JSP,這個(gè)聲明都是必需的。
<a4j:region> 標(biāo)記聲明 Ajax 區(qū)域的開頭和結(jié)尾。selfRendered 屬性設(shè)置為 true,這意味著當(dāng)發(fā)出相關(guān)聯(lián)的 Ajax 請(qǐng)求時(shí)將處理這個(gè)區(qū)域。
<a4j:mediaOutput> 標(biāo)記允許創(chuàng)建動(dòng)態(tài)生成的內(nèi)容,在這個(gè)示例中就是反映轉(zhuǎn)換后的華氏溫度的溫度計(jì)圖像。createContent 屬性指定負(fù)責(zé)創(chuàng)建此內(nèi)容的 bean 方法。value 屬性指定一個(gè)對(duì)象,這個(gè)對(duì)象包含著 createContent 中的 bean 方法所需的數(shù)據(jù)。注意,value 中的數(shù)據(jù)對(duì)象必須實(shí)現(xiàn) java.io.Serializable 類。
<a4j:status> 標(biāo)記提供 Ajax 請(qǐng)求的客戶端狀態(tài)。當(dāng)請(qǐng)求開始時(shí),顯示消息 "Processing..."。當(dāng)請(qǐng)求停止時(shí),不顯示消息。for 屬性將這個(gè)狀態(tài)與指定的 ID 關(guān)聯(lián)起來(lái)。這正好是前面定義的 "CtoF" 區(qū)域。
最后,<a4j:support> 標(biāo)記將 Ajax 支持添加到 JSF <h:inputText> 標(biāo)記中。event 屬性指出哪個(gè) JavaScript 事件將觸發(fā) Ajax 請(qǐng)求。reRender 屬性包含在發(fā)出請(qǐng)求之后將重新呈現(xiàn)的對(duì)象的 ID 列表。在這個(gè)示例中,當(dāng)用戶輸入攝氏溫度值時(shí),在每次釋放鍵盤鍵之后,發(fā)出一個(gè) Ajax 請(qǐng)求,從而用轉(zhuǎn)換后的華氏溫度重新呈現(xiàn)匹配的 JSF <h:outputText> 標(biāo)記。圖 5 給出頁(yè)面的樣子。
圖 5. 運(yùn)行時(shí)的 Temperature Conversion 實(shí)用程序
這就是在溫度轉(zhuǎn)換器頁(yè)面上使用 Ajax 的方式。正如 清單 3 所示,這個(gè)庫(kù)提供的組件很容易與 JSF 標(biāo)記進(jìn)行集成。接下來(lái),研究一下處理實(shí)際溫度轉(zhuǎn)換和圖像創(chuàng)建的代碼。
溫度轉(zhuǎn)換器 bean
溫度轉(zhuǎn)換器 bean 是實(shí)現(xiàn) Temperature Conversion 實(shí)用程序的模塊。負(fù)責(zé)進(jìn)行溫度轉(zhuǎn)換和圖像創(chuàng)建的所有方法都保存在 TemperatureConverter.java 文件中。下面幾個(gè)清單給出令人感興趣的幾個(gè)方法,首先是 清單 4。
清單 4. 對(duì)輸入的溫度進(jìn)行轉(zhuǎn)換
public void setInputCelsius(String inputCelsius)
{
Float tmpCelsius = null;
this.inputCelsius = inputCelsius;
// convert C to F
tmpCelsius = new Float(inputCelsius);
fahrenheitValue = new Float(celsiusToFahrenheit(tmpCelsius.floatValue()));
setOutputFahrenheit(fahrenheitValue.toString());
} // end setInputCelsius
public void setInputFahrenheit(String inputFahrenheit)
{
Float tmpFahrenheit = null;
this.inputFahrenheit = inputFahrenheit;
// convert F to C
tmpFahrenheit = new Float(inputFahrenheit);
celsiusValue = new Float(fahrenheitToCelsius(tmpFahrenheit.floatValue()));
setOutputCelsius(celsiusValue.toString());
} // end setInputFahrenheit
當(dāng)用戶在溫度轉(zhuǎn)換器頁(yè)面上的文本字段中輸入一個(gè)值之后,會(huì)調(diào)用對(duì)應(yīng)的 set 方法。這些方法調(diào)用代碼來(lái)轉(zhuǎn)換對(duì)應(yīng)的溫度并相應(yīng)地設(shè)置輸出值。清單 5 給出實(shí)際的轉(zhuǎn)換公式。
清單 5. 包含轉(zhuǎn)換公式的支持方法
private float celsiusToFahrenheit(float celsius)
{
float fahrenheit = 0.0f;
fahrenheit = ((9.0f / 5.0f) * celsius) + 32.0f;
System.out.println("celsius: " + celsius + "\tfahrenheit: "
+ fahrenheit);
return fahrenheit;
} // end celsiusToFahrenheit
private float fahrenheitToCelsius(float fahrenheit)
{
float celsius = 0.0f;
celsius = (5.0f / 9.0f) * (fahrenheit - 32.0f);
System.out.println("fahrenheit: " + fahrenheit + "\tcelsius: "
+ celsius);
return celsius;
} // end fahrenheitToCelsius
這兩個(gè)方法相當(dāng)簡(jiǎn)單明了。輸入一個(gè)溫度,輸出轉(zhuǎn)換后的溫度。System.out.println 語(yǔ)句在啟動(dòng)時(shí)顯示的 Geronimo 控制臺(tái)上顯示字符串。這適合進(jìn)行快速調(diào)試,但是真正的日志記錄實(shí)用程序適合更復(fù)雜的應(yīng)用程序。清單 6 包含負(fù)責(zé)創(chuàng)建華氏溫度計(jì)圖像的方法。
清單 6. 生成華氏溫度計(jì)圖像的方法
public void drawFahrenheitThermometer(OutputStream out, Object object)
throws IOException
{
BufferedImage thermometerImage = null;
Graphics2D image = null;
Thermometer thermometer = null;
if (object instanceof Thermometer)
{
thermometer = (Thermometer) object;
}
else
{
return;
} // end if
thermometerImage = new BufferedImage(
thermometer.getWidth().intValue(),
thermometer.getHeight().intValue(),
BufferedImage.TYPE_INT_RGB);
image = thermometerImage.createGraphics();
image.setBackground(thermometer.getThermometerColor());
image.clearRect(0, 0, thermometer.getWidth().intValue(),
thermometer.getHeight().intValue());
drawMercury(fahrenheitValue, thermometer, image);
drawThermometerUnits(thermometer, image);
ImageIO.write(thermometerImage, "jpeg", out);
} // end drawFahrenheitThermometer
這就是在 <a4j:mediaOutput> 的 createContent 屬性中指定的方法。它需要兩個(gè)參數(shù),而且 Object 類型的第二個(gè)參數(shù)必須實(shí)現(xiàn) java.io.Serializable。這個(gè)方法使用標(biāo)準(zhǔn)的 Java 2D 圖形庫(kù)來(lái)創(chuàng)建溫度計(jì)圖像。尺寸存儲(chǔ)在數(shù)據(jù)對(duì)象 thermometer 中。drawMercury 和 drawThermometerUnits 方法見 清單 7。
清單 7. 繪制刻度和更新水銀柱的支持方法
private void drawThermometerUnits(Thermometer thermo, Graphics2D image2D)
{
Integer tmpInteger = null;
int blockCounter = 0;
int textCounter = 0;
int unitCounter = 0;
for (int x = 0; x < thermo.getWidth().intValue(); x++)
{
if (x == blockCounter)
{
image2D.drawLine(x,0,x,30);
tmpInteger = new Integer(textCounter);
image2D.setColor(thermo.getThermometerTextColor());
image2D.drawChars(tmpInteger.toString().toCharArray(),
0, tmpInteger.toString().length(), x, 45);
blockCounter = blockCounter + BLOCK_INCREMENT;
textCounter = textCounter + TEXT_INCREMENT;
unitCounter = unitCounter + UNIT_INCREMENT;
}
else if (x == unitCounter)
{
image2D.drawLine(x, 0, x, 10);
unitCounter = unitCounter + UNIT_INCREMENT;
} // end if
} // end for
} // end drawThermometerUnits
private void drawMercury(Float temperature, Thermometer thermo, Graphics2D image2D)
{
int mercuryValue = 0;
if (temperature == null)
{
temperature = new Float(0.0f);
} // end if
// Scale temperature to thermometer units in image2D
mercuryValue = temperature.intValue() * SCALE_TEMP;
image2D.setColor(thermo.getMercuryColor());
image2D.fill3DRect(0, 11, mercuryValue,
thermo.getMercuryHeight().intValue(), true);
System.out.println("temp.intVal: " + temperature.intValue() +
"\t" + "mercuryValue: " + mercuryValue);
} // end drawMercury
drawThermometerUnits 方法繪制溫度計(jì)的刻度來(lái)表示單位。這個(gè)方法逐一處理圖像寬度上的每個(gè)像素。每隔一定的間距,繪制一條短刻度線或長(zhǎng)刻度線。短刻度線代表 2 度,長(zhǎng)刻度線代表 10 度并在它下面繪制對(duì)應(yīng)的數(shù)字。drawMercury 方法將轉(zhuǎn)換后的溫度乘以一個(gè)縮放因子,得出要繪制的水銀柱的像素?cái)?shù)。
這就是轉(zhuǎn)換溫度和創(chuàng)建溫度計(jì)圖像所需的代碼。清單 8 給出數(shù)據(jù)對(duì)象 Thermometer.java。這個(gè)支持 bean 包含創(chuàng)建溫度計(jì)圖像所需的圖像信息。
清單 8. Thermometer.java 數(shù)據(jù)對(duì)象的部分清單
// Thermometer.java - Contains dimensions and color for thermometer
// image
package devSignup;
import java.awt.Color;
import java.io.Serializable;
public class Thermometer implements Serializable
{
private static final long serialVersionUID = 1L;
private static final int MERCURY_HEIGHT = 20;
private static final int THERMOMETER_WIDTH = 600;
private static final int THERMOMETER_HEIGHT = 50;
private Color thermometerColor = new Color(235, 235, 235);
private Color thermometerTextColor = new Color(0, 0, 0);
private Color mercuryColor = new Color(135, 135, 135);
private Integer mercuryValue = null;
private Integer mercuryHeight = null;
private Integer thermometerWidth = null;
private Integer thermometerHeight = null;
public Thermometer()
{
mercuryValue = new Integer(0);
mercuryHeight = new Integer(MERCURY_HEIGHT);
thermometerWidth = new Integer(THERMOMETER_WIDTH);
thermometerHeight = new Integer(THERMOMETER_HEIGHT);
} // end Thermometer
public Color getThermometerColor()
{
return thermometerColor;
} // end getThermometerColor
// ...additional get/set methods trimmed here...
public void setThermometerColor(Color thermometerColor)
{
this.thermometerColor = thermometerColor;
} // end setThermometerColor
} // end Thermometer
Thermometer 就是 <a4j:mediaOutput> 標(biāo)記的 value 屬性中指定的數(shù)據(jù)對(duì)象。正如前面提到的,這個(gè)數(shù)據(jù)對(duì)象必須實(shí)現(xiàn) Serializable Java 類。注意,溫度計(jì)圖像所需的所有顏色和尺寸都在這個(gè)模塊中定義,但是 mercuryValue 除外。這個(gè)值實(shí)際上是未定義的,因?yàn)樗俏┮灰粋€(gè)根據(jù)用戶輸入而改變的值。
在使用這兩個(gè) bean 之前,需要在 faces-config.xml 部署描述符中定義它們。打開這個(gè)文件,確保選擇 Source 選項(xiàng)卡。確保在這個(gè)文件中輸入 清單 9 的內(nèi)容。
清單 9. 更新的 faces-config.xml 內(nèi)容
<managed-bean>
<description>Temperature Converter Bean</description>
<managed-bean-name>temperature</managed-bean-name>
<managed-bean-class>devSignup.TemperatureConverter</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<description>Thermometer Bean</description>
<managed-bean-name>thermometer</managed-bean-name>
<managed-bean-class>devSignup.Thermometer</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
這兩個(gè)標(biāo)記聲明兩個(gè) bean 并讓它們?cè)诒徽{(diào)用時(shí)對(duì) JSF 庫(kù)可用。這樣就行了!Temperature Conversion 實(shí)用程序現(xiàn)在已經(jīng)可以進(jìn)行構(gòu)建并部署到 Geronimo 上了,下面就來(lái)完成這些任務(wù)。
測(cè)試和故障排除
本節(jié)簡(jiǎn)要地討論如何構(gòu)建和部署 Temperature Conversion 實(shí)用程序并在 Developer Forum 應(yīng)用程序中訪問它。還討論在開發(fā)期間遇到的一些問題。
測(cè)試
首先需要在 Eclipse 中構(gòu)建示例應(yīng)用程序。
右擊 devSignup 項(xiàng)目,然后選擇 Build Project。
在 Eclipse 編譯并驗(yàn)證代碼之后,再次右擊 devSignup 項(xiàng)目。這一次選擇 Export。
在 Export 窗口中,展開 Web 文件夾,選擇 WAR file 并點(diǎn)擊 Next。
在 WAR Export 面板中,點(diǎn)擊 Browse 選擇一個(gè)目標(biāo),輸入 Web 存檔的文件名(例如,devSignup.war)并點(diǎn)擊 Save。
返回 WAR Export 面板之后,點(diǎn)擊 Finish 導(dǎo)出 .war 文件。如果需要的話,選中覆蓋現(xiàn)有文件的復(fù)選框。
既然已經(jīng)將示例應(yīng)用程序?qū)С鰹?Web 存檔,就可以將它部署到 Geronimo 上了。有兩種部署方法:熱部署和通過 Geronimo 的 Console 應(yīng)用程序進(jìn)行部署。在 geronimo-1.1 安裝文件夾下面有一個(gè)稱為 deploy 的文件夾。復(fù)制到這個(gè)文件夾中的任何存檔文件(比如 EAR 或 WAR)都由 Geronimo 自動(dòng)地進(jìn)行部署。反之,如果從這個(gè)目錄中刪除存檔文件,那么 Geronimo 就會(huì)卸載它們。前面的教程使用 Console 應(yīng)用程序,所以我們繼續(xù)使用這種部署方法。
改進(jìn)后的 Developer Forum 應(yīng)用程序已經(jīng)準(zhǔn)備好了。用 URL http://localhost:8080/devSignup 訪問這個(gè)應(yīng)用程序。
第一個(gè)頁(yè)面與 第 2 部分 中創(chuàng)建的注冊(cè)頁(yè)面相同。創(chuàng)建一個(gè)論壇賬號(hào)。成功之后,向用戶顯示一個(gè)與 圖 6 相似的屏幕。
圖 6. 成功!
在這個(gè)頁(yè)面上,論壇成員現(xiàn)在可以點(diǎn)擊 here 鏈接來(lái)訪問 Temperature Conversion 實(shí)用程序。在訪問這個(gè)實(shí)用程序之后,輸入攝氏或華氏溫度值。應(yīng)該會(huì)出現(xiàn)兩個(gè)現(xiàn)象。首先,在輸入每個(gè)值之后,溫度立刻被轉(zhuǎn)換。其次,在輸入值時(shí),在溫度計(jì)旁邊顯示狀態(tài)消息 Processing...。在輸入所希望的溫度之后,按 Enter 鍵來(lái)更新溫度計(jì)圖像。恭喜!Ajax4jsf 提供的 Ajax 功能已經(jīng)發(fā)揮作用了。
故障排除
請(qǐng)您自己試試。但是要記住兩個(gè)問題。正如前面所提到的,Ajax4jsf 的過濾器必須列在 web.xml 描述符文件中其他任何過濾器的前面。必須這樣做才能防止同一個(gè)文件中聲明的其他任何過濾器與 Ajax4jsf 過濾器沖突。根據(jù)文檔所述,這個(gè)條件和解決方案只適用于在 Apache MyFaces 中使用 Ajax4jsf。
Geronimo 提供了兩種部署應(yīng)用程序的方法:熱部署和 Geronimo Console。這兩種機(jī)制看起來(lái)是相互獨(dú)立工作的。當(dāng)總是只使用其中一種方法進(jìn)行部署時(shí),開發(fā)人員很容易管理應(yīng)用程序的安裝。但是,熱部署的應(yīng)用程序不會(huì)出現(xiàn)在 Geronimo Console 的 Web App WAR 鏈接中。同樣,通過 Geronimo Console 的 Deploy New 鏈接部署的應(yīng)用程序也不會(huì)出現(xiàn)在為熱部署保留的 geronimo-1.1/deploy 文件夾中。因此,有可能在 Geronimo 上部署了同一應(yīng)用程序的多個(gè)實(shí)例,而您卻不知道。這種情況可能會(huì)導(dǎo)致不可預(yù)測(cè)的結(jié)果。強(qiáng)烈建議您選擇一種部署方法并堅(jiān)持使用它。
結(jié)束語(yǔ)
在這個(gè)教程中,通過添加 Temperature Conversion 實(shí)用程序改進(jìn)了 Developer Forum Signup 應(yīng)用程序。我們研究了 Ajax4jsf 庫(kù)并使用幾個(gè) Ajax4jsf 組件創(chuàng)建了一個(gè)啟用 Ajax 的前端。還學(xué)習(xí)了如何將這個(gè)庫(kù)添加到 Eclipse Web 應(yīng)用程序項(xiàng)目中。
本系列的第 4 部分將研究 Oracle 的 ADF Faces,這是構(gòu)建于 JSF 之上的另一組 UI 組件,它最近被捐獻(xiàn)給了 Apache。這個(gè)教程將講解如何集成這個(gè)庫(kù)中的組件,從而進(jìn)一步改進(jìn) Developer Forum Signup 應(yīng)用程序。敬請(qǐng)期待!
下載
描述 | 名字 | 大小 | 下載方法 |
第 3 部分源代碼 | devSignup-p3src.zip | 19KB | HTTP |
第 3 部分 WAR 文件 | devsignup-p3war.zip | 4240KB | HTTP |
聯(lián)系客服