Contents

GWT 简介

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 – 设置错误、警告、信息、跟踪、调试、垃圾邮件、所有日志记录级别之一
  • -workdir – 编译器的工作目录
  • -gen - 写入生成文件的目录
  • -out – 输出文件目录
  • -optimize – 将编译器优化级别设置为 0 到 9
  • -style – 脚本输出样式OBF、PRETTYDETAILED
  • -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 APIgwt-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类扩展而来。在视觉上,我们有可以在屏幕上看到、单击或移动的元素小部件:

  • 组件小部件—— TextBoxTextAreaButtonRadioButtonCheckBox等…… 并且有组成和组织屏幕的布局或面板小部件:
  • 面板小部件——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接口以将其标记为模块的主条目。它连接到执行 java 代码的相应 HTML 文档。

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

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

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

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

在这里,我们还定义了ButtonTextBox小部件。要将它们附加到 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>标记将映射到ButtonTextBox组件。

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='com.blogdemo.client.Google_web_toolkit'/>
</module>

我们通过包含com.google.gwt.user.User界面来使核心 GWT 内容可访问。此外,我们可以为我们的应用程序选择一个默认样式表。在这种情况下,它是 *.clean.Clean。

其他可用的样式选项是 *.dark.Dark、*.standard.Standard 、*.chrome.Chrome。com.blogdemo.client.Google_web_toolkit在 此处也用<*entry-point */>标记进行了标记。

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()*方法执行远程过程调用。

方法的第二个参数是 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)方法。

根据响应结果,我们要么设置错误消息“发生服务器错误”,要么在容器中显示结果值。

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 应用程序:

/uploads/gwt/1.png

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