GWT简介

2025/04/07

1. 简介

GWT(或Google Web Toolkit)是一个使用Java构建高性能Web应用程序的框架

在本教程中,我们将重点介绍它的一些关键功能。

2. GWT SDK

SDK包含Java API库、编译器和开发服务器。

2.1 Java API

GWT API具有用于构建用户界面、进行服务器调用、国际化、执行单元测试的类。要了解更多信息,请查看此处的Java文档。

2.2 编译器

简单来说,GWT编译器就是一个将Java代码转换成Javascript的源翻译器,编译的结果就是一个Javascript应用程序。

其工作逻辑包括从代码中修剪未使用的类、方法、字段并缩短Javascript名称。

由于这个优点,我们不再需要在Javascript项目中包含Ajax库。当然,也可以在编译代码时设置提示。

这里有一些有用的GWTCompiler参数:

  • -logLevel:设置ERROR、WARN、INFO、TRACE、DEBUG、SPAM、ALL日志级别之一
  • -workdir:编译器的工作目录
  • -gen:写入生成文件的目录
  • -out:输出文件目录
  • -optimize:将编译器优化级别从0设置为9
  • -style:脚本输出样式OBF、PRETTY或DETAILED
  • -module[s]:要编译的模块的名称

3. 设置

最新的SDK可在下载页面上获取,其余设置可在入门页面上获取。

3.1 Maven

要使用Maven设置项目,我们需要向pom.xml添加以下依赖:

<dependency>
    <groupId>com.google.gwt</groupId>
    <artifactId>gwt-servlet</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>com.google.gwt</groupId>
    <artifactId>gwt-user</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>com.google.gwt</groupId>
    <artifactId>gwt-dev</artifactId>
    <scope>provided</scope>
</dependency>

gwt-servlet库支持用于调用GWT-RPC端点的服务器端组件;gwt-user包含我们将用来构建Web应用程序的Java API;gwt-dev具有用于编译器、部署或托管应用程序的代码

为了确保所有依赖使用相同的版本,我们需要包含父GWT依赖:

<dependency>
    <groupId>com.google.gwt</groupId>
    <artifactId>gwt</artifactId>
    <version>2.8.2</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

所有工件均可在Maven Central下载。

4. 应用程序

让我们构建一个简单的Web应用程序,它将向服务器发送一条消息并显示响应。

一般来说,GWT应用程序由服务器和客户端部分组成,客户端发出HTTP请求以连接服务器。为了实现这一点,GWT使用远程过程调用(或简称RPC机制)。

5. GWT和RPC

回到我们的应用程序,让我们看看如何进行RPC通信。为此,我们创建一个服务来从服务器接收消息。

我们首先创建一个接口:

@RemoteServiceRelativePath("greet")
public interface MessageService extends RemoteService {
    String sendMessage(String message) throws IllegalArgumentException;
}

@RemoteServiceRelativePath注解将服务映射到模块的/message相对URL,MessageService应从RemoteService标记接口扩展以执行RPC通信

MessageService的实现在服务器端:

public class MessageServiceImpl extends RemoteServiceServlet implements MessageService {

    public String sendMessage(String message) throws IllegalArgumentException {
        if (message == null) {
            throw new IllegalArgumentException("message is null");
        }

        return "Hello, " + message + "!<br><br> Time received: " + LocalDateTime.now();
    }
}

我们的服务器类扩展自RemoteServiceServlet基Servlet类,它将自动反序列化来自客户端的传入请求并序列化来自服务器的传出响应

现在让我们看看如何从客户端使用它,MessageService只是我们服务的一个最终版本

为了在客户端执行,我们需要创建服务的异步版本:

public interface MessageServiceAsync {
    void sendMessage(String input, AsyncCallback<String> callback) throws IllegalArgumentException;
}

这里我们可以看到getMessage()方法中有一个额外的参数,我们需要async来在异步调用完成时通知UI,这样我们就可以避免阻塞正在工作的UI线程。

6. 组件及其生命周期

SDK提供了一些用于设计图形界面的UI元素和布局。

一般来说,所有UI组件都从Widget类扩展而来。从视觉上看,我们有可以在屏幕上看到、单击或移动的元素小部件:

  • 组件小部件-TextBox、TextArea、Button、RadioButton、CheckBox等…

还有用于组成和组织屏幕的布局或面板小部件:

  • 面板小部件-HorizontalPanel、VerticalPanel、PopupPanel、TabPanel等…

每次我们向代码添加小部件或任何其他组件时,GWT都会努力将视图元素与浏览器的DOM链接起来

构造函数始终初始化根DOM元素,当我们将子窗口小部件附加到父组件时,它也会导致在DOM级别进行绑定。入口点类包含将首先调用的加载函数,这是我们定义窗口小部件的地方。

7. 入口点

让我们仔细看看该应用程序的主要入口点:

public class Google_web_toolkit implements EntryPoint {

    private MessageServiceAsync messageServiceAsync = GWT.create(MessageService.class);

    public void onModuleLoad() {
        Button sendButton = new Button("Submit");
        TextBox nameField = new TextBox();
        nameField.setText("Hi there");

        sendButton.addStyleName("sendButton");

        RootPanel.get("nameFieldContainer").add(nameField);
        RootPanel.get("sendButtonContainer").add(sendButton);
    }
}

每个UI类都实现了com.google.gwt.core.client.EntryPoint接口,将其标记为模块的主入口。它连接到相应的HTML文档,Java代码在该文档中执行。

我们可以定义GWT UI组件,然后将其分配给具有相同给定ID的HTML标签。入口点类覆盖入口点onModuleLoad()方法,该方法在加载模块时自动调用

在这里我们创建UI组件、注册事件处理程序、修改浏览器DOM。

现在,让我们看看如何创建远程服务器实例。为此,我们使用GWT.create(MessageService.class)静态方法。

它在编译时确定请求的类型;通过这种方法,GWT编译器在编译时生成多个版本的代码,在运行时引导期间,特定客户端只需要加载其中一个版本。此功能在RPC调用中被广泛使用。

这里我们还定义了Button和TextBox小部件,为了将它们添加到DOM树中,我们使用RootPanel类。它是根面板,并返回一个单例值来绑定小部件元素:

RootPanel.get("sendButtonContainer").add(sendButton);

首先,它获取标记为sendButtonContainer id的根容器,之后我们将sendButton附加到容器。

8. HTML

在/webapp文件夹中,我们有Google_web_toolkit.html文件。

我们可以用特定的id来标记标签元素,以便框架可以将它们绑定到Java对象中

<body>
    <h1>Sample GWT Application</h1>
    <table align="center">
        <tr>
            <td colspan="2" style="font-weight:bold;">Please enter your message:</td>
        </tr>
        <tr>
            <td id="nameFieldContainer"></td>
            <td id="sendButtonContainer"></td>
        </tr>
    </table>
</body>

具有nameFieldContainer和sendButtonContainer id的<td>标签将映射到Button和TextBox组件。

9. 主模块描述符

让我们看一下Google_web_toolkit.gwt.xml主模块描述符文件的典型配置:

<module rename-to='google_web_toolkit'>
    <inherits name='com.google.gwt.user.User'/>
    <inherits name='com.google.gwt.user.theme.clean.Clean'/>
    <entry-point class='cn.tuyucheng.taketoday.client.Google_web_toolkit'/>
</module>

通过包含com.google.gwt.user.User接口,我们可以访问核心GWT内容。此外,我们可以为我们的应用程序选择一个默认样式表。在本例中,它是*.clean.Clean。

其他可用的样式选项包括*.dark.Dark、*.standard.Standard、*.chrome.Chrome。cn.tuyucheng.taketoday.client.Google_web_toolkit也在此处用标签标记。

10. 添加事件处理程序

为了管理鼠标或键盘输入事件,GWT将使用一些处理程序,它们都从EventHandler接口扩展,并具有带有事件类型参数的方法

在我们的示例中,我们注册了鼠标单击事件处理程序。

每次按下按钮时都会触发onClick()方法:

closeButton.addClickHandler(new ClickHandler() {
    public void onClick(ClickEvent event) {
        vPanel.hide();
        sendButton.setEnabled(true);
        sendButton.setFocus(true);
    }
});

在这里我们可以修改小部件的状态和行为,在我们的示例中,我们隐藏了vPanel并启用了sendButton。

另一种方法是定义一个内部类并实现必要的接口:

class MyHandler implements ClickHandler, KeyUpHandler {

    public void onClick(ClickEvent event) {
        // send message to the server
    }

    public void onKeyUp(KeyUpEvent event) {
        if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
            // send message to the server
        }
    }
}

除了ClickHandler之外,我们还在此处包含了KeyUpHandler接口来捕获按键事件。在这里,在onKeyUp()方法中,我们可以使用KeyUpEvent来检查用户是否按下了Enter键

这里我们介绍如何使用MyHandler类来注册两个事件处理程序:

MyHandler handler = new MyHandler();
sendButton.addClickHandler(handler);
nameField.addKeyUpHandler(handler);

11. 调用服务器

现在,我们准备将消息发送到服务器,我们将使用异步sendMessage()方法执行远程过程调用。

该方法的第2个参数是AsyncCallback<String>接口,其中String是对应同步方法的返回类型

messageServiceAsync.sendMessage(textToServer, new AsyncCallback<String>() {
    public void onFailure(Throwable caught) {
        serverResponseLabel.addStyleName("serverResponseLabelError");
        serverResponseLabel.setHTML("server error occurred");
        closeButton.setFocus(true);
    }

    public void onSuccess(String result) {
        serverResponseLabel.setHTML(result);
        vPanel.setVisible(true);
    }
});

我们可以看到,接收器为每种响应类型实现了onSuccess(String result)和onFailure(Throwable)方法

根据响应结果,我们可以设置错误消息“server error occurred”或者在容器中显示结果值。

12. CSS样式

当使用eclipse插件创建项目时,它会自动在/webapp目录下生成Google_web_toolkit.css文件并将其链接到主HTML文件。

<link type="text/css" rel="stylesheet" href="Google_web_toolkit.css">

当然,我们可以以编程方式为特定的UI组件定义自定义样式:

sendButton.addStyleName("sendButton");

这里我们为sendButton组件分配一个类名为sendButton的CSS样式:

.sendButton {
    display: block;
    font-size: 16pt;
}

13. 结果

因此,我们有了这个简单的Web应用程序:

在这里,我们向服务器提交一条“Hi there”消息,并在屏幕上打印“Hello, Hi there!”响应。

14. 总结

在这篇简短的文章中,我们了解了GWT框架的基础知识。之后,我们讨论了其SDK的架构、生命周期、功能和不同组件。

因此,我们学习了如何创建一个简单的Web应用程序。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章