Noel Rappin (noelrappin@gmail.com), 高级软件工程师, Motorola, Inc.
2007 年 8 月 09 日
使用 Google Web Toolkit (GWT),Java 程序员可以使用纯 Java™ 编程语言编写富 Asynchronous JavaScript + XML (Ajax) 应用程序。专为 Eclipse IDE 设计的 Cypal Studio for GWT 将支持对 GWT 结构的管理。了解如何使用 Cypal Studio for GWT 创建新的 GWT 模块,支持创建远程过程调用,并使您可以轻松地查看和部署 Web 应用程序。
GWT 是一组可以让 Java 程序员使用纯 Java 编程语言编写动态 Ajax Web 应用程序而无需使用 JavaScript 的工具。GWT 应用程序可以在所有主流浏览器中运行,允许与用户进行充分的交互,并且可以在 Java 开发环境内进行全面的测试和调试。
GWT 框架有四个主要组件。一组用 Java 语言实现的部件集合,用于提供所有的标准用户界面 (UI) 功能 —— 通常由比 Swing 更简单的应用程序编程接口 (API) 提供这些功能。一个远程过程调用机制,允许在客户机与服务器之间进行通信,其中由 GWT 处理所有的管道和数据转换。一个完全集成的浏览器仿真器,使 GWT 在开发过程中独立运行,包括能够在 GWT 调试会话期间在编辑器中设定断点等优点。最后还有一个编译器,用于将 Java 代码转换为在客户机浏览器中实际执行的跨浏览器 JavaScript 代码,帮助您处理浏览器不兼容的问题。
虽然 GWT 简化了创建 Ajax 应用程序的过程,但是它仍有几个部分必须保持同步才能正常运行。撰写本文时,对 GWT 的高级工具支持已经开始出现在主流的 Java 开发环境中。
Cypal Studio for GWT 是 Eclipse 的一个插件,它可用于简化在 GWT 开发过程中执行的许多常见任务。本文并不旨在全面介绍 GWT。有关深入的介绍性文档(包括 GWT 如何工作以及如何创建简单的应用程序),请参阅 参考资料。
在 Eclipse Web Tools Platform 中安装 Cypal Studio
要使用 Cypal Studio for GWT,必须先下载它(请参阅 参考资料)。撰写本文时的最新 GWT 版本是 1.3,并且提供了针对 Microsoft® Windows®、Mac OS X 和 Linux® 系统的不同文件。只需下载适用于您的操作系统的文件,将其解压缩,并将得到的文件夹放置在便于访问的位置。
接下来,您需要配有 Web Tools Platform (WTP) 插件的 Eclipse 版本。WTP 是支持 Web 应用程序开发的精选工具集。它包括各种 Web 标准的编辑器支持,比如 HTML 和层叠样式表(Cascading Style Sheet,CSS)、JavaServer Page (JSP) 编辑器支持,支持创建和维护 Web 应用程序中使用的数据库,以及在开发过程中在 Web 服务器上运行应用程序。
那些功能都很棒,但是有些超出本文的范围。现在,我们对 WTP 比较感兴趣,因为 Cypal Studio for GWT 需要使用它运行;有关 WTP 的更多信息,请参阅 参考资料。
获得启用了 WTP 的 Eclipse 系统的最简单方法是一次性下载所有文件。如果您是首次下载 Eclipse,则尤其推荐使用这种方法。WTP 下载页面将提供所有 WTP 插件以及一些必备插件的 all-in-one 下载。页面会有一点乱:请查找 Web Tools Platform; All-in-one。在撰写本文时,当时的 WTP 版本是 1.5.4。有适用于 Windows、Linux 和 Mac OS X 的版本;下载适于您平台的一个版本。
如果一次性下载所有文件让您觉得过于简单或者 —— 更有可能的是 —— 您已经有 Eclipse 并且不希望重新下载所有文件,则可以将 WTP 作为插件下载。下载页面列出了一些必备插件。下载、解压缩那些插件,并将其放入 Eclipse 安装的插件目录中。然后下载文件名类似于 wtp-R-1.5.4.zip 的 Web Tools Platform(WTP、JST 和 WST 的组合)。将该文件也解压缩到插件目录中。
上述文件都下载完后,最后准备下载最新版本的 Cypal Studio for GWT。在撰写本文时,当时的版本名称为 cypal.studio.for.gwt-beta.zip。将该文件解压缩到 Eclipse 目录,在功能和插件目录中得到这些文件。
注:如果已经安装了旧的 Googlipse 插件,您可能必须删除该插件,以便可以干净地安装 Cypal Studio for GWT 插件。
现在所有文件均已下载,仍有一个配置选项必须设定,然后才能启动。启动并运行 Eclipse,然后访问 Preferences 窗口,如图 1 所示。如果一切运行正常,Cypal Studio 应当在左侧有一个条目。只需将 GWT Home 设置设为先前创建的 GWT 安装的顶级目录。
图 1. Cypal Studio Preferences 窗口
该操作应当为您安装了所需的所有文件。让我们开始吧!
|
要使用 Cypal Studio for GWT,必须创建一个新的 Dynamic Web Project 或将 Cypal Studio 添加到现有项目中。要启动新项目,选择 File > New。选择 Web 标题下的 Dynamic Web Project Wizard。您将看到如下所示的窗口。
图 2. New Dynamic Web Project 窗口
要创建项目,请执行以下步骤:
- 在 Project name 框中键入项目的名称。
- 从 Configurations 列表中,选择 Default Googlipse Project,然后单击 Next(撰写本文时,它仍叫做 Googlipse)。您将看到需要为项目启用的 Project Facets 列表。由 Dynamic Web Module、Googlipse 和 Java 构成的默认列表就足够了。
- 单击 Next。您将有机会配置 Cypal Studio 将要创建的一些目录的名称。本文的其余部分将引用默认名称,但是如果觉得非常有必要更改这些名称,那么更改便是。
- 单击 Finish。
Cypal Studio for GWT 将开始创建一批文件,然后系统可能提示您接受一到两个文档类型定义 (DTD) 的许可协议。结果,Eclipse Project Explorer 应当类似图 3 所示。
图 3. Cypal Studio Project Explorer
Deployment Descriptor 是 WTP 之类的内容,我不准备详细研究它。Cypal Studio for GWT 已经创建了源代码目录、经过编译的 Java 代码目录(在有了那部分内容时)以及 WebContent 目录(到目前为止主要包含一个十分独立的 web.xml 文件)。
现在,您已经创建了一个新的 Cypal Studio 项目。您若需要向现有 Eclipse Dynamic Web Project 中添加 Cypal Studio 支持,请在 Project Explorer 中右击项目,然后单击 Properties。在其中选择 Project Facets > Add/Remove Project Facets。您将看到一个可用层面的列表;单击 Cypal's GWT Facet。
|
您有了一个不错的项目框架,但是没有实际代码。让我们来解决该问题。GWT 代码的基本单元是模块。模块大致上对应于用户从其客户机浏览器中调用的页面。模块通常由一个或多个 Entry Point
类组成,这些类将在模块本身载入时被载入。此外,您可以指定模块的源代码、公共 Web 文件和必需的 JavaScript 或 CSS 文件(如果有)的非标准位置。
要在 Cypal Studio for GWT 中创建模块,请选择 File > New。如果有带 Cypal Studio 工具箱图标的 Module 清单,请选择该清单。如果没有,则从显示的窗口中选择 Other > Cypal Studio > Module。最后,您将看到如下所示的窗口。
图 4. New GWT Module 窗口
在默认情况下,Source folder 是现有项目的源代码文件夹。但是,您必须自己设定 Package 文件夹。一般惯例是模块的顶级 Package.Name。您还必须设定模块的名称、Superclass 和默认的 Interfaces,如图所示。
单击 Finish 之后,Cypal Studio 将创建以下元素(那些曾经使用过 GWT 的用户将会记得,这是大致从 GWT 的命令行工具获得的,只是附带了一个优秀的易于使用的图形用户界面 [GUI])。
- 三个包 client、server 和 public,位于指定源目录中的顶级包
- client 包中的 FirstModule.java 文件,用作模块的初始入口点
- public 包中的 FirstModule.html 文件,用于渲染实际页面的 HTML
|
最初,Java 和 HTML 文件包含编译所需的最少存根代码。但是,您可以在其中放入更丰富的内容:将清单 1 中显示的代码插入 HTML 文件的 body 部分。
清单 1. 创建和运行代码
<table align=center> <tr> <td id="button"></td> <td id="count"></td> </tr> </table> |
然后将清单 2 中显示的 Java 代码放入 Java 文件。您还需要让 Eclipse 为导入类生成 import 语句。
清单 2. 向 Java 文件中添加 Java 代码
int count = 0; public void onModuleLoad() { final Button button = new Button("Count Your Clicks!"); final Label label = new Label(String.valueOf(count)); button.addClickListener(new ClickListener() { public void onClick(Widget sender) { count += 1; label.setText(String.valueOf(count)); } }); RootPanel.get("button").add(button); RootPanel.get("count").add(label); } |
由于这段代码位于 onModuleLoad()
方法中,因此它将在模块载入时自动运行。这段代码将不会过多地深入 GWT 部件集的细节,而是创建按钮和标签。它将向按钮添加侦听程序,然后将按钮和标签都放入文档对象模型 (DOM) ID 匹配传递给 RootPanel.get()
的字符串的 HTML 元素。
要运行系统,请单击 Run。从 Run 窗口中,选择 Gwt Hosted Mode Application > New_configuration。将显示下面的窗口(您可能必须右击 GWT Hosted Mode Application,然后单击 New 以查看新配置)。
图 5. 创建运行配置
您必须指定所需的项目以及该项目的模块。幸运的是,Eclipse 使您可以轻松地浏览现有项目空间。单击 Apply 将保存新配置(首先需要给它提供一个惟一名称),然后单击 Run 来运行它。这样做将调用项目的 GWT 托管模式(完成一次此操作后,单击 Run 将像任何其他 Eclipse 运行目标一样运行)。如果您尝试了在不使用 Cypal Studio 的情况下在 Eclipse 中设定运行目标,则会为使用 Cypal Studio 时可以简化大概七个步骤而欣喜不已。
运行时,页面应当类似于图 6。
图 6. 第一个 Cypal Studio 模块
|
与远程服务器进行通信是所有 Web 应用程序的核心,并且 GWT 提供了客户端 GWT 代码与 Java 远程服务器进行通信的框架。这种机制(有关更详细的说明,请参阅 “使用 Google Web Toolkit、Apache Derby 和 Eclipse 构建 Ajax 应用程序,第 3 部分: 通信”)是多个类和接口的 Enterprise JavaBean (EJB) 合并。它比从头构建每个连接更容易,但是仍有很多部分需要跟踪。
Cypal Studio for GWT 有一些便捷的特性,使您可以更轻松地创建和管理远程连接。通过选择 New > Remote Service 启动进程(如果 Remote Service 不在菜单中,请选择 Other > Cypal Studio,就像创建模块所做的操作一样)。您将看到如下所示的窗口。
图 7. GWT 远程服务
您必须填写 Name(这是 Java 服务器端类的实际名称)和 Extended interfaces 服务 URI(这是客户机将实际调用的服务器端 URL)。然后单击 Finish 并让 Cypal Studio 执行一些任务。
Cypal Studio 将为您创建三个文件。在 client 包中,它将创建 NumberGenerator.java,这是此远程连接的主接口,如清单 3 所示:
清单 3. NumberGenerator.java
public interface NumberGenerator extends RemoteService { public static final String SERVICE_URI = "/numbergenerator"; public static class Util { public static NumberGeneratorAsync getInstance() { NumberGeneratorAsync instance = (NumberGeneratorAsync) GWT .create(NumberGenerator.class); ServiceDefTarget target = (ServiceDefTarget) instance; target.setServiceEntryPoint(GWT.getModuleBaseURL() + SERVICE_URI); return instance; } } } |
注意,该文件此时是一个空接口,但是 Cypal Studio 已经创建了实用程序对象以返回适用于远程调用的 GWT 完全认证的实例。“使用 Google Web Toolkit、Apache Derby 和 Eclipse 构建 Ajax 应用程序,第 3 部分: 通信” 包含类似的代码,以及可能对创建样本代码的一般方法有用的建议。
该实用程序的返回值实际上属于 NumberGeneratorAsync
类型,这是主接口的异步版本。主接口的每种方法在异步接口中都有相匹配的条目,但是附带了 void
返回类型和 AsyncCallback
类的附加参数。当您从客户机页面调用这段代码时,实际上使用的是异步接口,然后 GWT 将把它转换为服务器端将看到的主接口。然后,使用 AsyncCallback
对象对服务器响应执行一些实际操作。
在服务器端,Cypal Studio 已经创建了实现类 NumberGeneratorImpl
,该类将扩展 GWT 类 RemoteServiceServlet
并实现 NumberGenerator
接口。此外,GWT 已经修改了 web.xml 文件来注册新远程服务器以供在部署的应用程序中使用。新代码行类似清单 4。
清单 4. NumberGenerator.java 的附加行
<servlet> <servlet-name>NumberGenerator</servlet-name> <servlet-class> com.ibm.firstmodule.server.NumberGeneratorImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>NumberGenerator</servlet-name> <url-pattern>numbergenerator</url-pattern> </servlet-mapping> |
要实际创建远程调用,首先需要将方法签名添加到 NumberGenerator
中。您将实现的方法将玩 “猜数字” 游戏。方法签名为:
public Integer getNumber(int maxNumber); |
把该签名保存到 NumberGenerator
接口中,然后会发生一些有趣的事:Cypal Studio 已经把匹配的方法添加到 NumberGeneratorAsync
中:
public void getNumber(int maxNumber, AsyncCallback callback); |
这是十分便捷的,因为手动使这两个接口保持同步会有一定的负担。现在,您还必须转到 NumberGeneratorImpl
类。Eclipse 将把此类标记成红色,因为不再完全实现 NumberGenerator
接口。幸运的是,您可以通过添加以下代码解决该问题,在您提出疑问之前,我可以告诉您,这段代码是出于最简单情况的考虑。
public Integer getNumber(int maxNumber) { return new Integer((new Random()).nextInt()); } |
为了发出调用,我已经将其添加到模块中,如清单 5 所示。注意,为使此调用正常工作,我向 HTML body 中添加了另一个有两个单元格的行,第一个单元格 ID 为 sender
,第二个单元格 ID 为 response
。模块现在有一个按钮,它用于从服务器中检索随机数并将其与单击次数相比较。
清单 5. 添加了调用的模块
public class FirstModule implements EntryPoint { int count = 0; private Button button; private Button sender; private Label label; private Label response; public void onModuleLoad() { button = new Button("Count Your Clicks!"); sender = new Button("Send Your Count!"); label = new Label(String.valueOf(count)); response = new Label("No Guess Yet"); button.addClickListener(new CountButtonClickListener()); sender.addClickListener(new SendClickListener()); RootPanel.get("button").add(button); RootPanel.get("count").add(label); RootPanel.get("sender").add(sender); RootPanel.get("response").add(response); } public class CountButtonClickListener implements ClickListener { public void onclick(Widget sender) { count += 1; label.setText(String.valueOf(count)); } } public class SendClickListener implements ClickListener { public void onClick(Widget sender) { NumberGeneratorAsync async = NumberGenerator.Util.getInstance(); async.getNumber(10, new NumberCallback()); } } public class NumberCallback implements AsyncCallback { public void onFailure(Throwable error) { response.setText("Oops"); } public void onSuccess(Object resp) { int intResp = ((Integer) resp).intValue(); if (intResp == count) { response.setText("Got It!"); } else if (intResp < count) { response.setText("Too Low"); } else if (intResp > count) { response.setText("Too High"); } } } } |
代码的核心部分包括 SendClickListener
和 NumberCallback
。在 SendClickListener
中,您将使用 Cypal Studio 生成的 Util
类来获得异步接口的实例并从该接口调用 getNumber()
方法。
调用的第二个参数是 NumberCallback
的实例,GWT 将在服务器完成响应时自动调用。回调有两个分支:onFailure()
和 onSuccess()
—— 这取决于服务器是否在不出现异常的情况下完成了请求。在本例中,如果服务器成功完成请求,则将结果与计数相比较并在一个标签中设定文本(您可以像这样设计,以便调用把当前计数值发送给服务器并在服务器端完成比较;完全取决于您对复杂性的要求)。
这段代码就绪后,启用 GWT 托管模式,一切应当运行正常。
|
Cypal Studio 的一个可能还不太成熟的领域是结合使用 Web 应用程序与外部服务器。该操作无论是在 Eclipse 内部还是在 Eclipse 外部肯定都可以完成,但是可能会多出一两个不必要的步骤。
要在 Eclipse 中运行 Web 应用程序,需要有一个支持 Eclipse WTP 的 servlet 引擎。Apache Tomcat 始终是最佳选择。接下来,编译 GWT 应用程序。完成此操作的最简单方法是以上述的托管模式运行应用程序,然后单击 Compile/Browse。这样做将把所有 GWT 代码编译成 JavaScript 文件并可能在计算机中打开外部浏览器,对此您不必在意。
接下来,您可以通过在 Project Explorer 中右击项目名称,触发在外部服务器上运行的进程。选择 Run As > Run On Server。将显示用于定义新服务器的窗口。保留主机名 localhost。选择您计划使用的服务器类型。如果您先前没有设置该类型的服务器,系统还将提示您设置服务器的运行时目录。
设置了运行时目录后,Eclipse 将在工作区中打开一个 HTML 页面。如果 Eclipse 尝试访问系统的根目录,请不必惊慌,在本例中,这样做将出错,因为您尚未指定类似 index.html 的任何文件。只需把浏览器指向刚创建的 HTML 文件(本例中为 http://localhost:8080/GooglipseProject/FirstModule.html),然后您将看到类似图 8 所示的页面。
图 8. 在外部服务器上的项目
如果需要将 GWT 项目部署到外部浏览器中,您可以通过在 Project Explorer 中右击项目并选择 Export > WAR 轻松地完成该操作。系统将提示您指定放置 Web Archive (WAR) 文件的位置(您还必须编译以上描述的 GWT 代码)。您随后可以将 WAR 文件放在所选服务器的适当位置中,然后一切就绪。
|
|