介: 最近发布的 Google Web Toolkit (GWT) 是一组全面的 API 和工具,它支持用户几乎完全使用 Java™ 代码来创建动态 Web 应用程序。Philip McCarthy 回到了他广受欢迎的面向 Java 开发人员的 Ajax 系列,向您展示 GWT 能做什么。
GWT(请参阅 参考资料)采用了一种不寻常的方式进行 Web 应用程序开发。它没有采用客户端和服务器端代码库的普通隔离,而是提供了一个 Java API,该 API 允许创建基于组件的 GUI,然后编译它们,从而在用户的 Web 浏览器上显示它们。与一般的 Web 应用程序开发体验相比,使用 GWT 更接近于使用 Swing 或 SWT 进行开发,它还试图将 HTTP 协议和 HTML DOM 模型抽象出去。实际上,应用程序最终几乎总是会呈现在 Web 浏览器中。
GWT 是通过代码生成来实现这些功能的,它利用其编译器从客户端 Java 代码生成 JavaScript。GWT 支持 java.lang
和 java.util
包的子集,还支持 GWT 自身提供的 API。编译后的 GWT 应用程序由 HTML、XML 和 JavaScript 片段组成。但是,这些片段很难区分,所以最好把编译后的应用程序当成是黑盒子 —— Java 字节码的 GWT 等价物。
在这篇文章中,我将创建一个简单的 GWT 应用程序,用该程序从远程 Web API 获得天气报告,并在浏览器中显示它。在整个过程中,我将简要介绍尽可能多的 GWT 功能,还将提到一些可能遇到的潜在问题。
从简单的开始
清单 1 显示了可以用 GWT 制作的最简单的应用程序的 Java 源代码:
清单 1. 最简单的 GWT 示例
public class Simple implements EntryPoint { public void onModuleLoad() { final Button button = new Button("Say 'Hello'"); button.addClickListener(new ClickListener() { public void onClick(Widget sender) { Window.alert("Hello World!"); } }); RootPanel.get().add(button); } } |
这个代码看起来非常像使用 Swing、AWT 或 SWT 编写的 GUI 代码。不出所料,清单 1 创建了一个按钮,在单击此按钮时会显示消息 “Hello World!”。该按钮被添加到 RootPanel
,这是一个环绕 HTML 页面主体的 GWT 包装对象。图 1 显示了应用程序在 GWT Shell 中运行时的情况。GWT Shell 是一个包含在 GWT SDK 中的调试宿主环境(debugging hosting environment),与一个简单的浏览器组合在一起。
构建 Weather Reporter 应用程序
我将用 GWT 创建一个简单的 Weather Reporter 应用程序。该应用程序的 GUI 向用户显示了一个用于输入 ZIP 代码的输入框,还显示了一个使用摄氏温度还是华氏温度来表示温度的选项。当用户单击 Submit 按钮时,该应用程序用 Yahoo! 的免费天气 API 获得所选定地区的 RSS 格式的报告。然后提取这个文档的 HTML 部分,并将它显示给用户。
GWT 应用程序被打包成模块,并且必须符合特定的结构。名为 module-name.gwt.xml 的配置文件定义了充当应用程序入口点的类,并指明是否要从其他 GWT 模块继承资源。在应用程序的源包结构中,必须将配置文件放在与 client
包和 public 目录相同的级别上,所有客户端 Java 代码都在 client 包中,而 public 目录包含项目的 Web 资源,比如图片、CSS 和 HTML。最后,public 目录中必须包含一个 HTML 文件,该文件中必须有一个包含模块的限定名称的 meta
标记。GWT 的运行时 JavaScript 库使用这个文件来初始化应用程序。
在指定了入口点类的情况下,GWT 的 applicationCreator
会替您生成这个基本结构。所以可以将调用 applicationCreator developerworks.gwt.weather.client.Weather
生成一个项目框架作为创建 Weather Reporter 应用程序的起点。在该应用程序的源代码下载中包含的 Ant 构建文件中,有一些有用的目标(target),可使用它们让 GWT 项目符合这个结构。(请参阅 下载)。
开发基本的 GUI
首先,我将开发应用程序的用户界面小部件(widget)的基本布局,且不添加其他任何行为。Widget
类是可以呈现在 GWT UI 中的几乎所有类的超类。Widget
总是包含在 Panel
中,Panel 本身也是 Widget
,所以可以被嵌套。不同类型的面板提供了不同的布局行为。所以,GWT Panel
扮演的角色与 AWT/Swing 中的 Layout
或 XUL 中的 Box
类似。
所有小部件和面板最终都要附加到包含它们的 Web 页面上。如 清单 1 所示,可以直接把它们附加到 RootPanel
上。或者,可以用RootPanel
获得对使用 ID 或类名标识的 HTML 元素的引用。在这个示例中,我将使用两个独立的 HTML DIV
元素,它们的名称分别是input-container
和 output-container
。第一个元素包含 Weather Reporter 应用程序的 UI 控件,第二个元素显示天气报告本身。
清单 2 显示了设置基本布局所需的代码;它应当是自解释的。HTML
小部件只是 HTML 标记的容器,来自 Yahoo! 天气种子(weather feed)的 HTML 输出将显示在这里。这些代码都位于 Weather
类的 onModuleLoad()
方法中,这个方法由 EntryPoint
接口提供。在将包含天气模块的 Web 页面装入客户机的 Web 浏览器时,将调用这个方法。
清单 2. Weather Reporter 应用程序的布局代码
public void onModuleLoad() { HorizontalPanel inputPanel = new HorizontalPanel(); // Align child widgets along middle of panel inputPanel.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE); Label lbl = new Label("5-digit zipcode: "); inputPanel.add(lbl); TextBox txBox = new TextBox(); txBox.setVisibleLength(20); inputPanel.add(txBox); // Create radio button group to select units in C or F Panel radioPanel = new VerticalPanel(); RadioButton ucRadio = new RadioButton("units", "Celsius"); RadioButton ufRadio = new RadioButton("units", "Fahrenheit"); // Default to Celsius ucRadio.setChecked(true); radioPanel.add(ucRadio); radioPanel.add(ufRadio); // Add radio buttons panel to inputs inputPanel.add(radioPanel); // Create Submit button Button btn = new Button("Submit"); // Add button to inputs, aligned to bottom inputPanel.add(btn); inputPanel.setCellVerticalAlignment(btn, HasVerticalAlignment.ALIGN_BOTTOM); RootPanel.get("input-container").add(inputPanel); // Create widget for HTML output HTML weatherHtml = new HTML(); RootPanel.get("output-container").add(weatherHtml); } 呈现的 Web 页面看起来很傻,所以它将从 CSS 样式规则中汲取一些优点。可以用两种方式为 GWT 应用程序添加样式。首先,默认情况下,每个小部件都有一个 CSS 类名,其形式为 每个小部件类型一个类名(classname-per-widget-type)的默认方法使得在整个应用程序中一致地设置小部件样式变得非常容易。当然,普通的 CSS 选择器规则也可以应用,所以可以根据小部件的上下文,用选择器规则在同一小部件上应用不同的样式。要得到更多的灵活性,则可以调用小部件的 清单 3 组合了这些方法,把样式应用到 Weather Reporter 应用程序的输入面板上。通过对 清单 3. 将 CSS 样式应用到 Weather Reporter 应用程序的输入面板
|