top
Loading...
使用GWT開發AJAX應用程序
一、 引言

如果你是一個Java軟件和Ajax開發者,那么,Google Web Toolkit(GWT)應該已經引起你的關注。

Google公司已經于2006年5月在Apache許可協議下發布了這種免費的開發工具包。GWT的設計目的是為了簡化用Java語言開發Ajax應用程序。Google初始發行的beta版本可以適用于Windows和Linux平臺,并許諾稍后要發行一個Mac OS X版本。

本文將探討在Mac OS X上使用GWT和熟悉的Java工具,例如Apache Ant,Tomcat 5.0 servlet容器和IntelliJ IDEA集成開發環境開發一個簡單的Ajax應用程序的完整過程。

注 本文假定讀者具有一定的Java和Ant使用基礎。

二、 與GWT一起使用Ant

我下載的是GWT的Linux beta版本,并選用Java開發應用程序,然后使用一個Ant構建文件進行編譯,最后在一個Tomcat 5.0實例上發布該應用程序。注意,這個Ant文件運行的是GWT Java-to-JavaScript編譯器。其實,這個“編譯器”只是一個執行一個GWT Java類的命令行腳本,該Java類負責為應用程序編寫JavaScript。

使用GWT beta包括兩種開發方式:主機方式和web方式。

主機方式是使用一個嵌入式的GWT瀏覽器和中間開發步驟;在這個方式中,你的編譯代碼繼續運行于一個Java虛擬機(JVM)中。然而,主機方式無法應用于我們這些使用Linux版本操作系統的Mac OS X用戶。只有Google發行了一個Mac OS X版本,我們才可以使用主機方式。

三、 不同風格的Web開發

在創建遠程過程調用(RPC)服務的同時,本文將詳細討論一些典型的GWT開發者可能面對的web開發有關的任務。RPC是一個軟件模型的一部分,主要為使用面向服務的架構(SOA)的應用程序而設計。這些開發任務包括:

· 使用一個構建文件(構建運行GWT編譯器,然后發布編譯器的輸出,并且把你的服務器端的Java類文件發布到一個servlet容器,例如Tomcat,Jetty或Resin)來自動化開發和發布步驟。

· 使用Firefox的DOM Inspector來觀察由該GWT應用程序生成的HTML。

· 重新設置頁面中的各部件而不必存取內在的HTML(既然你在使用GWT的Java API)。

· 確保HTML是有效的標記,例如,你的組織可能需要基于一個特別的XHTML文檔類型。

四、 服務功能

首先,我將簡短描述本文示例應用程序要創建的服務,設計這個示例是為了展示GWT使用的模型。

該應用程序在瀏覽器中顯示一個表單,要求用戶輸入他們的姓名、年齡和原籍國家。當用戶通過點按按鈕提交表單時,該應用程序在一個文本域中顯示一個服務器響應,而不必初始化一個頁面刷新。圖1顯示了在Safari瀏覽器中該應用程序看上去的樣子。


圖1.一個由GWT生成的簡單視圖

例如,當用戶保留一個文本框為空而點擊OK,Submit按鈕時將顯示出圖2所示結果。


圖2:該應用程序用紅色顯示一條錯誤消息

五、 巧妙的服務機制

在Ajax應用程序中使用RPC可以消除顯式地處理XMLHttpRequest和相關的服務器返回值的必要性,因為GWT對象能夠為你處理復雜任務。

你的應用程序定義的每個服務都要求實現兩個Java接口和一個Java類。為了編譯這些類,你必須確保gwt-user.jar庫位于你的classpath(由一個Ant文件入口負責實現這項任務)中。下列代碼示例展示了定義我們的服務的Java接口。

package com.parkerriver.gwt.testapp.client;
import com.google.gwt.user.client.rpc.RemoteService;
public interface ShowRespService extends RemoteService{
String displayResponse(String req);
}

這個服務接口要求擴展GWT接口RemoteService。它定義了單個方法displayResponse()。

另外,你還必須定義一個客戶端(或使用最終下載的JavaScript代碼)用于調用這個服務方法的接口。當我顯示客戶端代碼時(請參考MyForm.java),該GWT使用一個我描述的回調設計模式。

package com.parkerriver.gwt.testapp.client;
import com.google.gwt.user.client.rpc.AsyncCallback;
public interface ShowRespServiceAsync {
public void displayResponse(String s,AsyncCallback callback);
}

這個AsyncCallback對象負責(作為GWT API的一部分)為客戶端處理服務響應。

六、 一個Servlet

最后,你必須定義一個實現遠程服務接口的Java類。這個類將位于你的Ajax應用程序的服務器端。

package com.parkerriver.gwt.testapp.server;
import com.parkerriver.gwt.testapp.client.ShowRespService;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import java.util.Date;
public class ShowRespServiceImpl extends RemoteServiceServlet
implements ShowRespService {
public String displayResponse(String req) {
if(req.length() < 1) {
throw new IllegalArgumentException(
"Blank submissions from the client are invalid.");
}
StringBuffer buf = new StringBuffer("Your submission: ");
Date date = new Date();
String serverInfo = this.getServletContext().getServerInfo();
buf.append(req);
buf.append("");
buf.append("Server response: ");
buf.append(date.toString());
buf.append("");
buf.append(serverInfo);
return buf.toString();
}
}

這個類必須繼承RemoteServiceServlet(這是本身繼承自javax.servlet.http.HttpServlet的一個GWT API對象)。也就是說,這個類及其實現的接口必須被發布到你的servlet容器中。

七、 步驟

現在,既然定義了服務,那么讓我們來回顧一個這個應用程序的目錄結構。GWT包括一個命令行腳本applicationCreator,它能夠為你生成一個框架性的工程目錄結構。在你解壓下載的GWT后,你會在頂級目錄下發現該applicationCreator。我使用下列命令行作為開始:

applicationCreator -out /Users/bruceperry/1gwt/secondapp/ com.parkerriver.gwt.testapp.client.MyForm

圖3展示了該目錄看上去的樣子。


圖3:一個GWT和IntelliJ工程目錄

applicationCreator生成./src目錄以及MyForm-compile和MyForm-shell腳本。我的Ant文件執行的是MyForm-compile;另一個腳本將在GWT模式下啟動主機方式。這個./src目錄中包括了嵌套的目錄以匹配你的包名,如圖4所示。


圖4.一個GWT應用程序的Java包和模塊

MyForm.gwt.xml文件是一個生成的配置文件,它其實是GWT調用的一個“模塊”。它指定描述你的應用程序“入口點”的Java類(這是一個類似于一個包含一個main()方法的Java類)。

<module>
<!—繼承核心Web Toolkit。-->
<inherits name='com.google.gwt.user.User'/>
<!--指定應用程序入口點類。-->
<entry-point class='com.parkerriver.gwt.testapp.client.MyForm'/>
</module>

其它的文件或目錄,包括./classes、./WEB-INF和./gwtproj.ipr,都是一個IntelliJ Web應用程序工程的必要組成部分;因此,你不必特別注意它們。

另外,直到生成你的應用程序代碼的GWT編譯器時,./www目錄才出現(除非你自己創建它)。我的工程使用了Ant文件gwtproj.xml,還有定義在gwtproj.properties中的屬性。在我向你展示Ant構建文件前,我們先來看一下描述應用程序入口點的MyForm.java類。

八、 入口點

這個MyForm.java類實現了GWT API接口EntryPoint;因此,該類必須實現onModuleLoad()方法,當瀏覽器加載你的Ajax應用程序時此方法為瀏覽器的JavaScript引擎所調用。

也就是說,GWT編譯器把這個類編譯成JavaScript代碼。MyForm.java類為瀏覽器視圖建立表單widget。該類還決定了點擊OK和Submit按鈕時用戶的響應。代碼中的注釋已經作了詳細的描述,所以在此不再多言。

注意,這個類中的大部分代碼是處理GWT API。有意思的是,如果你必須實現JavaScript DOM編程(就象在showRpcStatus()方法中所展示的),那么你可以用Java來實現com.google.gwt.user.client.DOM類。

九、 構建文件

下面是Ant構建文件的主要功能;這個構建文件:

1. 把Java文件編譯到工程目錄的./classes目錄下。

2. 執行GWT編譯腳本(在這個例子中是MyForm-compile)。

3. 把在./www目錄下生成的結果代碼移動到一個較大的已經發布到Tomcat上的web應用程序。

4. 把編譯的Java servlet及相關接口(ShowRespService)復制到同一個web應用程序下。

注意,這里的兩個目標:編譯Java類和初始化到JavaScript的轉換有可能使整個構建過程失敗,如果期間發生任何錯誤的話。

十、 Ant XML

下面是gwtpoj.properties文件包含的內容(省略了其它的內容):

web.deploy.location=/users/bruceperry/parkerriver/gwt
web.classes.location=/users/bruceperry/parkerriver/WEB-INF/classes

下列XML描述了剛才的Ant文件的主要功能:

<?xml version="1.0" encoding="UTF-8"?>
<project name="gwtproj" default="all">
<property file="gwtproj.properties"/>

<!—工程的頂級目錄與ant文件存在的位置-->
<dirname property="module.gwtproj.basedir" file="${ant.file}"/>

<!--目錄在頂級目錄內的./classes-->
<property name="gwtproj.output.dir" value=
"${module.gwtproj.basedir}/classes"/>

<!--這個目標調用MyForm-compile以創建./www目錄下的所有的內容-->
<target name="gwt-compile" depends=
"compile.production.classes"
description="use gwt's compiler">
<delete>
<fileset dir="${web.deploy.location}" includes="**/*"/>
</delete>
<exec executable=
"${module.gwtproj.basedir}/MyForm-compile"
failonerror="true"/>
<copy todir="${web.deploy.location}">
<fileset dir=
"${module.gwtproj.basedir}/www">
</fileset>
</copy>
</target>
<target name="compile.production.classes" description=
"Compile the gwtproj production classes">
<mkdir dir="${gwtproj.output.dir}"/>
<javac destdir="${gwtproj.output.dir}" debug=
"on" failonerror="true" nowarn=
"off" memoryMaximumSize="128m" fork=
"true" executable="${module.jdk.home.gwtproj}/bin/javac">
<classpath refid="gwtproj.module.classpath"/>
<src refid="gwtproj.module.sourcepath"/>
</javac>
</target>

<!--把Java servlet類復制到web應用程序-->
<target name="deploy.classes" depends="gwt-compile"
description="copy classes to web directory">
<copy todir="${web.classes.location}">
<fileset dir="${gwtproj.output.dir}">
</fileset>
</copy>
</target>

<target name="all" depends="deploy.classes"
description="build all"/>
</project>

你可以從IDE(在IntelliJ中)中或在包含該構建文件的目錄下使用下列命令行來運行這個Ant文件:

ant -buildfile gwtproj.xml

大部分情況下,在修改應用程序和運行Ant后,你都可以通過重載瀏覽器頁面而在瀏覽器中看到這些變化。

十一、 安裝

注意,在安裝時,你必須把gwt-user.jar庫添加到你的web應用程序的/WEB-INF/lib目錄下。

我把創建的JAR文件,還有javax包(gwt-user-deploy.jar)都添加到/WEB-INF/lib目錄下。這是因為Tomcat不會加載單個的web應用程序的庫文件,如果它已經包含servlet API類的話。

十二、 難點

applicationCreator還會為你創建Ajax應用程序的HTML前端,在這個例子中是MyForm.html。

如果你的應用程序的HTM必須滿足一種標準(例如XHTML Transitional 或Strict),那么該怎么辦呢?對于XHTML transitional,我首先把要求的DOCTYPE添加到MyForm.html的頂部以及該html標簽的相關屬性中:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/2000/REC-xhtml1-20000126/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">

然后,我把MyForm.html上傳到WWW協會的HTM驗證程序(位于http://validator.w3.org/)。

在運行該驗證程序后,我略微修改了一下該HTML,例如適當關閉meta標簽并且把一個type="text/javascript"添加到腳本標簽。

然而,如果你想滿足XHTML Strict標準,那么還需要進行更為復雜的修改。例如,W3C的驗證程序將把iframe標簽顯示為“undefined element”,而這個標簽是GWT的歷史支持功能(提供與一個瀏覽器back按鈕相同的功能)必需的。XHTML Strict中已經刪除了iframe元素。

這個對你來說可能不是個問題(可能會在GWT的未來版本中得到解決,還有任何其它明顯的問題);然而,你還可以實現其它可選策略,例如擴展GWT的類并創建你自己的兼容widget等。

十三、 位置對齊問題

一個在web開發中普通存在的問題就是應用程序的可視化設計問題。工程的設計者可能想使頁面看上去如其在Adobe Illustrator創建一樣的效果,對不對?

盡管當你開發一個復雜的Ajax工程時你可能無法實現這種理想的視覺效果;但是,你至少可以使用Firefox的DOM Inspector來觀察你的Java類最終生成的HTML。然后,再從這里進行修改。

例如,轉到Firefox的“Tools=>DOM Inspector”菜單項(見圖5)。


圖5:使用DOM Inspector觀察后臺實現內容。

上圖顯示了,你在Java代碼中使用的com.google.gwt.user.client.ui.Grid對象被實現為一個HTML table標簽。這個table中的包含OK,Submit按鈕的TD標簽與一個style屬性(其值為"verticle-align:top")相關聯。

下面是在MyForm.java類中相關的初始化適當格式的Java代碼:

//設置OK按鈕單元格的垂直位置
grid.getCellFormatter().setVerticalAlignment(3,0,
HasVerticalAlignment.ALIGN_TOP);

如果在代碼中不進行這個調用,那么該按鈕可能會在文本域的中間部分上下浮動。

十四、 總結

Google公司發布的Google Web Toolkit(GWT)已經引起業界的普遍關注。既然GWT的設計目的是為了簡化用Java語言開發Ajax應用程序,而Ajax是Web 2.0時代的技術基礎,所以GWT發行所引起的轟動應該在意料之中。

本文僅給出使用GWT和熟悉的Java工具開發一個簡單的Ajax應用程序的示例,而有關GWT的更多的探究剛剛開始,還依賴于廣大讀者的努力。
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗