Пример создания приложения Google Web Toolkit (GWT) Hello World Example
Быстрый старт в Google web toolkit. Пример создания простого приложения GWT Hello World Example.
Используемые технологии
- GWT 2.7.0.
- IntelliJ IDEA 14
- Maven 3.2.5
1. Описание задачи
Создать простое веб-приложение с использованием фреймворка Google web toolkit версии 2.7.0. Рассмотреть пример взаимодействия клиентской и серверной части. Применить несколько стандартных компонентов GWT и назначить для них обработчики.
2. Структура проекта
Создана простая базовая структура проекта GWT. Имеется необходимый главный класс GwtApp, а так же необходимые файлы GwtApp.css, GwtApp.html и GwtApp.gwt.xml — все они являются обязательными. Для взаимодействия клиента с серверной частью созданы GwtAppServiceIntf, GwtAppServiceIntfAsync, GwtAppServiceImpl — набор так же обязателен. FieldValidator — необязательный класс (создан для проверки длины строки в текстовом поле).
В документации JetBrains есть такая хорошая картинка, описывающая базу GWT:
- GWT корневой пакет (1).
- Client (2). Файлы и ресурсы для клиентской стороны
- Public (3). Различные статические ресурсы, которые могут быть сгруппированы и общедоступны.
- Server (4). Серверная сторона.
- GWT Module XML descriptor (5) XML описание GWT модуля
Как видите, есть некоторые отличия от созданного выше проекта.
3. Создание Google Web Toolkit приложения
Создаем пустой Maven проект.
3.1 pom.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>ru.javastudy</groupId> <artifactId>gwt_helloworld</artifactId> <version>1.0</version> <properties> <gwtVersion>2.7.0</gwtVersion> </properties> <dependencyManagement> <dependencies> <!-- ensure all GWT deps use the same version (unless overridden) --> <dependency> <groupId>com.google.gwt</groupId> <artifactId>gwt</artifactId> <version>${gwtVersion}</version> <scope>import</scope> <type>pom</type> </dependency> </dependencies> </dependencyManagement> <!--<dependencies>--> <!-- GWT --> <!--<dependency>--> <!--<groupId>org.codehaus.mojo</groupId>--> <!--<artifactId>gwt-maven-plugin</artifactId>--> <!--<version>2.7.0</version>--> <!--</dependency>--> <!--</dependencies>--> </project> |
Как видите, здесь два определения зависимостей для GWT. Первая указана на сайте GWT проекта, вторая лежит в центральном репозитории. Hello World проект запуститься с любой из них. Посмотрите сами в чем отличие.
3.2 Добавление фреймворков
Выбираем галочки напротив Web Application и Google Web Toolkit.
3.3. web.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- Servlets --> <servlet> <servlet-name>gwtServlet</servlet-name> <servlet-class>ru.javastudy.gwtApp.server.GwtAppServiceImpl</servlet-class> </servlet> <servlet-mapping> <servlet-name>gwtServlet</servlet-name> <url-pattern>/gwtApp/gwtAppService</url-pattern> </servlet-mapping> <!-- Default page to serve --> <welcome-file-list> <welcome-file>GwtApp.html</welcome-file> </welcome-file-list> </web-app> |
Указан сервлет, по какому паттерну он будет мапиться, а так же страница входа после загрузки сервера.
<url-pattern>/gwtApp/gwtAppService</url-pattern> — обратите внимание на эту строчку. gwtAppService — указан в аннотации интерфейса GwtAppServiceIntf, который будет описан ниже.
3.4 GwtApp.gwt.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?xml version="1.0" encoding="UTF-8"?> <!-- When updating your version of GWT, you should also update this DTD reference, so that your app can take advantage of the latest GWT module capabilities. --> <!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.0//EN" "http://google-web-toolkit.googlecode.com/svn/releases/2.0/distro-source/core/src/gwt-module.dtd"> <module rename-to="gwtApp"> <!-- Inherit the core Web Toolkit stuff. --> <inherits name='com.google.gwt.user.User'/> <!-- Inherit the default GWT style sheet. You can change --> <!-- the theme of your GWT application by uncommenting --> <!-- any one of the following lines. --> <inherits name='com.google.gwt.user.theme.clean.Clean'/> <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> --> <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> --> <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/> --> <!-- Other module inherits --> <!-- Specify the app entry point class. --> <entry-point class='ru.javastudy.gwtApp.client.GwtApp'/> <!-- Specify the paths for translatable code --> <source path='client'/> <source path='shared'/> <!-- allow Super Dev Mode --> <add-linker name="xsiframe"/> </module> |
Дескриптор главного модуля GWT приложения. Подписи внутри кода поясняют его назначение. Сам модуль GWT описан чуть ниже.
4. Описание GWT Module. EntryPoint interface
Для загрузки приложения необходимо создать класс, реализующий интерфейс EntryPoint. Это аналог public static void main() в обычном Java приложении. Требуется реализовать только один метод, чтобы увидеть рабочее GWT приложение.
В Idea есть способ создать сразу несколько файлов (html, css, модуль). Для этого нажмите правой кнопкой и выберите необходимый пункт. Например, после создания модуля сразу будут созданы html и css с аналогичным названием.
GwtApp.class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
package ru.javastudy.gwtApp.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.event.dom.client.*; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.*; import ru.javastudy.gwtApp.shared.FieldValidator; /** Entry point classes define <code>onModuleLoad()</code>. */ public class GwtApp implements EntryPoint { final Button confirmButton = new Button("Confirm"); final TextBox nameField = new TextBox(); final Label errorLabel = new Label(); final Label helloLabel = new Label(); VerticalPanel dialogVPanel = new VerticalPanel(); final DialogBox dialogBox = new DialogBox(); final HTML serverResponseHtml = new HTML(); final Label sendToServerLabel = new Label(); final Button closeButton = new Button("Close"); private final GwtAppServiceIntfAsync gwtAppService = GWT.create(GwtAppServiceIntf.class); /** This is the entry point method.*/ public void onModuleLoad() { helloLabel.setText("GwtApp Application hello world"); final Label usernameLabel = new Label(); usernameLabel.setText("Username: "); /*Связываем id='' на html странице с компонентами */ RootPanel.get("helloId").add(helloLabel); RootPanel.get("usernameLabelId").add(usernameLabel); RootPanel.get("usernameId").add(nameField); RootPanel.get("confirmButtonId").add(confirmButton); RootPanel.get("errorLabelContainer").add(errorLabel); // Create the popup dialog box dialogBox.setText("Remote procedure call from server"); dialogBox.setAnimationEnabled(true); closeButton.getElement().setId("closeButtonId"); dialogVPanel.addStyleName("dialogVPanel"); dialogVPanel.add(new HTML("<b>Отправленные поля на сервер:</b>")); dialogVPanel.add(sendToServerLabel); dialogVPanel.add(new HTML("<br><b>Ответ сервера:</b>")); dialogVPanel.add(serverResponseHtml); dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT); dialogVPanel.add(closeButton); dialogBox.setWidget(dialogVPanel); //обработчик для клика по кнопке 'Confirm' confirmButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { confirmButton.setEnabled(false); sendInfoToServer(); } }); //обработчик по нажатию enter в текстовом поле nameField.addKeyUpHandler(new KeyUpHandler() { public void onKeyUp(KeyUpEvent event) { if(event.getNativeKeyCode() == KeyCodes.KEY_ENTER) { sendInfoToServer(); } } }); //обработчик по клику на кнопку 'Close' в диалоговом окне closeButton.addClickHandler(new ClickHandler() { public void onClick(ClickEvent event) { dialogBox.hide(); confirmButton.setEnabled(true); confirmButton.setFocus(true); } }); } private void sendInfoToServer() { //validate input text errorLabel.setText(""); String nameToServer = nameField.getText(); if (!FieldValidator.isValidData(nameToServer)) { //отобразить ошибку на html странице errorLabel.setText("Имя должно содержать больше трех символов"); return; } sendToServerLabel.setText(nameToServer); confirmButton.setEnabled(false); serverResponseHtml.setText(""); gwtAppService.gwtAppCallServer(nameToServer, new AsyncCallback<String>() { public void onFailure(Throwable caught) { dialogBox.setText("Remote Procedure Call - Failure"); serverResponseHtml.addStyleName("serverResponseLabelError"); serverResponseHtml.setHTML("ERROR ON SERVER"); dialogBox.center(); closeButton.setFocus(true); } public void onSuccess(String result) { dialogBox.setText("Remote Procedure Call"); serverResponseHtml.removeStyleName("serverResponseLabelError"); serverResponseHtml.setHTML(result); dialogBox.center(); closeButton.setFocus(true); } }); } } |
- Вначале определяем компоненты GWT (кнопки, текстовое поле, диалоговое окно и т.д.).
- С помощью RootPanel.get(«idFromHtmlPage»).add(gwtComponent) — связываем id на html странице с компонентом (виджетом) GWT.
- Создаем диалоговое окно (его вызов описан в sendInfoToServer()). Добавляем компоненты и различные свойства.
- Методы addKeyUpHandler и addClickHandler — обработчики событий нажатия клавиши и щелчка мыши соответственно. Обработчики задаются у текстового поля и кнопки Confirm.
- Метод sendInfoToServer() позволяет отправить данные на серверную часть приложения. Для этого вначале был создан экземпляр gwtAppService с помощью команды GWT.create(GwtAppServiceIntf.class); С его помощью выполняется асинхронная обработка данных, и для неё необходимо реализовать два метода: для случая успешного выполнения и для неудачи.
5. Представление html GWT приложения
Для главного модуля нужно создать html страницу. Именно с ней производится связь компонентов GWT из кода выше.
GwtApp.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<!doctype html> <!-- The DOCTYPE declaration above will set the --> <!-- browser's rendering engine into --> <!-- "Standards Mode". Replacing this declaration --> <!-- with a "Quirks Mode" doctype is not supported. --> <html> <head> <title>GwtApp Application</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <!-- Consider inlining CSS to reduce the number of requested files --> <link rel="stylesheet" href="GwtApp.css"> </head> <!-- --> <!-- The body can have arbitrary html, or --> <!-- you can leave the body empty if you want --> <!-- to create a completely dynamic UI. --> <!-- --> <body> <!-- This script loads your compiled module. --> <!-- If you add any GWT meta tags, they must --> <!-- be added before this line. --> <script type="text/javascript" language="javascript" src="gwtApp/gwtApp.nocache.js"></script> <!-- RECOMMENDED if your web app will not function without JavaScript enabled --> <noscript> <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif"> Your web browser must have JavaScript enabled in order for this application to display correctly. </div> </noscript> <h1 id="helloId" style="text-align: center"></h1> <table align="center"> <tr> <td colspan="2" style="font-weight: bold; text-align: center">First GWT Application</td> </tr> <tr> <td id="usernameLabelId"></td> <td id="usernameId"></td> </tr> <tr> <td id="confirmButtonId"></td> </tr> <tr> <td colspan="2" style="color:red;" id="errorLabelContainer"></td> </tr> </table> </body> </html> |
В начале файла идут рекомендуемые настройки\импорты. Т.к. без включенного javascript пользователь ничего не увидит, то рекомендуется так же добавить тег <noscript> где попросить включить поддержку JavaScript в браузере. Далее написана одна таблица с несколькими id. Выше с ними произведена связка с компонентами google web toolkit.
GwtApp.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
/** Add css rules here for your application. */ body { background-color: white; color: black; font-family: Arial, sans-serif; font-size: small; margin: 8px; } /** Example rules used by the template application (remove for your app) */ h1 { font-size: 2em; font-weight: bold; color: #777777; margin: 40px 0px 70px; text-align: center; } .sendButton { display: block; font-size: 16pt; } /** Most GWT widgets already have a style name defined */ .gwt-DialogBox { width: 400px; } .dialogVPanel { margin: 5px; } .serverResponseLabelError { color: red; } /** Set ids using widget.getElement().setId("idOfElement") */ #closeButton { margin: 15px 6px 6px; } |
Вы можете добавить css-стили на своё усмотрение.
6. Классы и интерфейсы для работы клиентской части с серверной
Для совместной работы клиентской и серверной частей необходимо создать интерфейс, расширяющий интерфейс-маркер RemoteService.
GwtAppServiceIntf:
1 2 3 4 5 6 7 8 9 10 11 12 |
package ru.javastudy.gwtApp.client; import com.google.gwt.user.client.rpc.RemoteService; import com.google.gwt.user.client.rpc.RemoteServiceRelativePath; /** * The client-side stub for the RPC service. */ @RemoteServiceRelativePath("gwtAppService") public interface GwtAppServiceIntf extends RemoteService { String gwtAppCallServer(String data) throws IllegalArgumentException; } |
Обратите внимание на аннотацию и посмотрите еще раз в web.xml.
Для асинхронной работы необходим интерфейс с таким же названием и добавлением Async. GwtAppServiceIntfAsync:
1 2 3 4 5 6 7 8 9 10 |
package ru.javastudy.gwtApp.client; import com.google.gwt.user.client.rpc.AsyncCallback; /** * The async counterpart of <code>GwtAppServiceIntf</code> */ public interface GwtAppServiceIntfAsync { void gwtAppCallServer(String data, AsyncCallback<String> callback) throws IllegalArgumentException; } |
В пакет server необходимо добавить класс, реализующий наш только что созданный интерфейс, а так же расширяющий RemoteServiceServlet. GwtAppServiceImpl:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
package ru.javastudy.gwtApp.server; import com.google.gwt.user.server.rpc.RemoteServiceServlet; import ru.javastudy.gwtApp.client.GwtAppServiceIntf; import ru.javastudy.gwtApp.shared.FieldValidator; /** * The server-side implementation of the RPC service. */ public class GwtAppServiceImpl extends RemoteServiceServlet implements GwtAppServiceIntf { public String gwtAppCallServer(String data) throws IllegalArgumentException { if (!FieldValidator.isValidData(data)) { throw new IllegalArgumentException("Имя должно быть больше трех символов"); } String serverInfo = getServletContext().getServerInfo(); String userAgent = getThreadLocalRequest().getHeader("User-Agent"); data = escapeHtml(data); userAgent = escapeHtml(userAgent); return "Привет, " + data + "!<br> Инфо сервера: " + serverInfo + ".<br> Вы используете:" + "<br>" + userAgent; } private String escapeHtml(String html) { if (html == null) { return null; } return html.replaceAll("&", "&").replaceAll("<", "<").replaceAll( ">", ">"); } } |
7. Вспомогательный класс-валидатор
Был создан необязательный класс-валидатор, который проверяет длину введенной строки в компонент TextBox.
1 2 3 4 5 6 7 8 9 10 11 12 |
package ru.javastudy.gwtApp.shared; public class FieldValidator { public static boolean isValidData(String data) { if (data == null) { return false; } return data.length() >=3; } } |
8. Запуск приложения GWT Hello World
Для начала покажу скриншоты настроек в Idea. Может быть, кому-то эта информация будет необходима (особенно если не получится запустить с первого раза).
Необходимо добавить в настройках Edit Configuration GWT Configuration (дебаг добавился автоматически после установки чекбокса with JavaScript debugger):
После запуска:
После клика на кнопку:
Можеть быть интересно
GWT – UIBinder Hello World. Пример использования UIBinder в GWT