«1. Введение

GWT или Google Web Toolkit — это платформа для создания высокопроизводительных веб-приложений на Java.

В этом уроке мы сосредоточимся на некоторых из его ключевых возможностей и функций.

2. GWT SDK

SDK содержит библиотеки Java API, компилятор и сервер разработки.

2.1. Java API

GWT API имеет классы для создания пользовательских интерфейсов, вызовов сервера, интернационализации, выполнения модульных тестов. Чтобы узнать больше, ознакомьтесь с документацией по Java здесь.

2.2. Компилятор

Проще говоря, компилятор GWT — это транслятор исходного кода из Java-кода в Javascript. Результатом компиляции является Javascript-приложение.

Логика его работы включает вырезание из кода неиспользуемых классов, методов, полей и сокращение названий Javascript.

Благодаря этому преимуществу нам больше не нужно включать библиотеки Ajax в наш проект Javascript. Конечно, также можно установить подсказки при компиляции кода.

Вот некоторые полезные параметры 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 содержит 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. Приложение

Давайте создадим простое веб-приложение. Он отправит сообщение на сервер и отобразит ответ.

В общем случае GWT-приложение состоит из серверной и клиентской частей. Клиентская сторона делает HTTP-запрос для подключения к серверу. Чтобы сделать это возможным, GWT использует удаленный вызов процедур или просто механизм RPC.

5. GWT и RPC

Возвращаясь к нашему приложению, давайте посмотрим, как осуществляется связь RPC. Для этого мы создаем сервис для получения сообщения от сервера.

Давайте сначала создадим интерфейс:

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

Аннотация @RemoteServiceRelativePath сопоставляет службу с относительным URL модуля /message. 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. Он автоматически десериализует входящие запросы от клиента и сериализует исходящие ответы от сервера.

Теперь давайте посмотрим, как мы используем его со стороны клиента. MessageService — это только окончательная версия нашего сервиса.

Для работы на стороне клиента нам нужно создать асинхронную версию нашего сервиса:

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

Здесь мы видим дополнительный аргумент в методе getMessage(). Нам нужен async для уведомления пользовательского интерфейса о завершении асинхронного вызова. Таким образом мы предотвращаем блокировку рабочего потока пользовательского интерфейса.

6. Компоненты и их жизненный цикл

SDK предлагает некоторые элементы пользовательского интерфейса и макеты для проектирования графических интерфейсов.

В общем, все компоненты пользовательского интерфейса происходят от класса 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);
    }
}

Каждый класс пользовательского интерфейса реализует интерфейс com.google.gwt.core.client.EntryPoint, чтобы пометить ее. в качестве основной записи для модуля. Он подключается к соответствующему документу HTML, где выполняется код Java.

Мы можем определить компоненты пользовательского интерфейса GWT и затем назначить теги HTML с тем же заданным идентификатором. Класс точки входа переопределяет метод точки входа onModuleLoad(), который вызывается автоматически при загрузке модуля.

Здесь мы создаем компоненты пользовательского интерфейса, регистрируем обработчики событий, модифицируем DOM браузера.

Теперь давайте посмотрим, как мы создадим экземпляр нашего удаленного сервера. Для этого мы используем статический метод GWT.create(MessageService.class).

Он определяет запрошенный тип во время компиляции. Видя этот метод, компилятор GWT генерирует множество версий кода во время компиляции, только одна из которых должна быть загружена конкретным клиентом во время начальной загрузки во время выполнения. Эта функция широко используется в вызовах RPC.

Здесь мы также определяем виджеты Button и TextBox. Чтобы добавить их в DOM-дерево, мы используем класс RootPanel. Это корневая панель, которая возвращает одноэлементное значение для привязки элементов виджета:

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

Сначала она получает корневой контейнер, помеченный идентификатором sendButtonContainer. После того, как мы прикрепим sendButton к контейнеру.

8. HTML

Внутри папки /webapp у нас есть файл Google_web_toolkit.html.

Мы можем пометить элементы тега определенными идентификаторами, чтобы платформа могла связать их с объектами 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>

Теги \u003ctd\u003e с идентификаторами nameFieldContainer и sendButtonContainer будут сопоставлены с компонентами 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='com.baeldung.client.Google_web_toolkit'/>
</module>

Мы делаем основные вещи GWT доступными, включив файл com.google. gwt.user.Пользовательский интерфейс. Кроме того, мы можем выбрать таблицу стилей по умолчанию для нашего приложения. В данном случае это *.clean.Clean.

Другие доступные параметры стиля: *.dark.Dark, *.standard.Standard, *.chrome.Chrome. com.baeldung.client.Google_web_toolkit также отмечен здесь тегом \u003centry-point /\u003e.

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\u003cString\u003e, где 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 он автоматически создает файл Google_web_toolkit.css в каталоге /webapp и связывает его с основным HTML-файлом.

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

Конечно, мы можем определить пользовательские стили для конкретных компонентов пользовательского интерфейса программно:

sendButton.addStyleName("sendButton");

Здесь мы назначаем стиль CSS с именем класса sendButton нашему компоненту sendButton:

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

13 Результат

В результате у нас есть это простое веб-приложение:

Здесь мы отправляем сообщение «Привет!» на сервер и печатаем ответ «Привет, привет!» на экране.

14. Заключение

В этой быстрой статье мы узнали об основах GWT Framework. После этого мы обсудили архитектуру, жизненный цикл, возможности и различные компоненты его SDK.

В итоге мы научились создавать простое веб-приложение.

И, как всегда, полный исходный код руководства доступен на GitHub.