| // |
| // Licensed to the Apache Software Foundation (ASF) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The ASF licenses this file |
| // to you under the Apache License, Version 2.0 (the |
| // "License"); you may not use this file except in compliance |
| // with the License. You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, |
| // software distributed under the License is distributed on an |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| // KIND, either express or implied. See the License for the |
| // specific language governing permissions and limitations |
| // under the License. |
| // |
| |
| = Использование WebSocket API в веб-приложении |
| :jbake-type: tutorial |
| :jbake-tags: tutorials |
| :jbake-status: published |
| :icons: font |
| :syntax: true |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :description: Использование WebSocket API в веб-приложении - Apache NetBeans |
| :keywords: Apache NetBeans, Tutorials, Использование WebSocket API в веб-приложении |
| |
| В этом учебном курсе приведен пример создания простого веб-приложения, обеспечивающего взаимодействие браузерных клиентов, подключенных к одному серверному приложению. Когда пользователь рисует графический элемент на полотне в браузере клиента, этот элемент появляется на полотне всех подключенных клиентов. Как это работает? Когда браузер загружает веб-страницу, сценарий на стороне клиента отправляет запрос квитирования WebSocket на сервер приложений. Приложение может принимать двоичные сообщения и сообщения JSON от клиентов, подключенных к сеансу, и транслировать эти сообщения на все подключенные клиенты. |
| |
| Из этого учебного курса вы узнаете о том, как создать веб-приложение, использующее интерфейс Java API for WebSocket (link:http://www.jcp.org/en/jsr/detail?id=356[+JSR 356+]) для двустороннего обмена данными между браузерными клиентами и сервером приложений. Интерфейс Java API for WebSocket обеспечивает возможность создания компонентов Java WebSocket, инициализации и перехвата событий WebSocket, а также создания и использования текстовых и двоичных сообщений WebSocket. В этом учебном курсе также приведен пример использования интерфейса Java API for JSON Processing (link:http://jcp.org/en/jsr/detail?id=353[+JSR 353+]) для создания и использования компонентов JSON. Интерфейсы Java API for WebSocket и Java API for JSON Processing являются компонентами платформы Java EE 7 (link:http://jcp.org/en/jsr/detail?id=342[+JSR 342+]). |
| |
| Приложение содержит интерфейсы WebSocket для терминала, декодера и кодера, веб-страницу и ряд файлов JavaScript, запускаемых в браузере клиента при загрузке страницы или вызываемых формой на веб-странице. Развертывание приложения осуществляется на экземпляре GlassFish Server Open Source Edition 4, эталонной версии реализации технологии Java EE 7. |
| |
| NOTE: Этот курс основывается на статье блога link:https://blogs.oracle.com/arungupta/entry/collaborative_whiteboard_using_websocket_in[+ Collaborative Whiteboard using WebSocket in GlassFish 4 - Text/JSON and Binary/ArrayBuffer Data Transfer (TOTD #189) +] и других статьях блога link:http://blog.arungupta.me/[+Arun Gupta+]. Рекомендуем посетить этот блог и ознакомиться с другими интересными статьями о работе с WebSocket API и GlassFish 4. |
| |
| Также рекомендуем посмотреть видеоролик link:maven-websocketapi-screencast.html[+Использование WebSocket API в веб-приложении+]. |
| |
| *Упражнения по темам руководства* |
| |
| * <<Exercise_1,Создание проекта веб-приложения>> |
| * <<createendpoint,Создание терминала WebSocket>> |
| * <<createendpoint1,Создание терминала>> |
| * <<createendpoint2,Инициализация сеанса WebSocket>> |
| * <<createendpoint3,Тестирование терминала>> |
| * <<createwhiteboard,Создание интерактивной доски>> |
| * <<createwhiteboard1,Добавление полотна>> |
| * <<createwhiteboard2,Создание POJO>> |
| * <<createwhiteboard3,Создание класса координат>> |
| * <<createwhiteboard6,Генерация строки JSON>> |
| * <<createwhiteboard4,Реализация интерфейсов кодера и декодера>> |
| * <<createwhiteboard5,Запуск приложения>> |
| * <<sendbinary,Отправка двоичных данных на терминал>> |
| |
| *Для работы с этим учебным курсом требуется следующее программное обеспечение и ресурсы.* |
| |
| |=== |
| |Программное обеспечение или ресурс |Требуемая версия |
| |
| |link:https://netbeans.org/downloads/index.html[+IDE NetBeans+] |Версия Java EE 7.3.1, 7.4, 8.0 |
| |
| |link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+Комплект для разработчика на языке Java (JDK)+] |версия 7 или 8 |
| |
| |link:https://glassfish.java.net/[+GlassFish Server Open Source Edition 3.1.2.2+] |4 |
| |=== |
| |
| NOTE: GlassFish 4 входит в состав загружаемого комплекта Java EE для NetBeans IDE. |
| |
| *Предпосылки* |
| |
| Предполагается, что читатель обладает базовыми знаниями по следующим технологиям или опытом программирования с их использованием: |
| |
| * Программирование на Java |
| * Программирование на JavaScript/HTML |
| * IDE NetBeans |
| |
| Перед изучением этого учебного курса можно ознакомиться со следующей документацией: |
| |
| * link:http://wiki.netbeans.org/MavenBestPractices[+Испытанные приемы для Apache Maven в IDE NetBeans+] |
| * link:http://books.sonatype.com/mvnref-book/reference/introduction.html[+Глава 1. Введение в Apache Maven+] (из книги link:http://books.sonatype.com/mvnref-book/reference/index.html[+Maven: The Complete Reference +]) |
| |
| Можно загрузить link:https://netbeans.org/projects/samples/downloads/download/Samples/JavaEE/WhiteboardApp.zip[+готовый проект в виде архива ZIP+]. |
| |
| |
| == Создание проекта веб-приложения |
| |
| Цель этого упражнения - создать проект веб-приложения с помощью мастера создания проектов в IDE. При создании проекта в качестве версии Java EE необходимо указать Java EE 7, а в качестве сервера приложений - GlassFish 4. GlassFish 4 является эталонной реализацией платформы Java EE 7. Для создания приложения по инструкциям, приведенным в этом учебном курсе, вам потребуется сервер приложений с поддержкой Java EE 7, зарегистрированный в IDE. |
| |
| 1. Выберите Файл > Создать проект в главном меню (в Windows можно использовать сочетание клавиш Ctrl-Shift-N; в Mac - сочетание клавиш ⌘-Shift-N). |
| 2. Выберите в категории Maven пункт "Веб-приложение". Нажмите 'Далее'. |
| 3. В поле 'Имя проекта' введите *WhiteboardApp* и укажите местоположение проекта. |
| 4. В поле 'ИД группы' введите *org.sample*. Нажмите 'Далее'. |
| 5. В списке 'Сервер' выберите *GlassFish Server 4.0*. |
| 6. В списке 'Версия Java EE' выберите *Java EE 7 Web*. Нажмите 'Готово'. |
| |
| image::images/websocket-newproject.png[title="Версии сервера и Java EE в мастере создания проектов"] |
| |
| При нажатии кнопки "Завершить" проект будет создан в среде IDE, который откроется в окне "Проекты". |
| |
| |
| == Создание терминала WebSocket |
| |
| Этот раздел содержит инструкции по созданию класса терминала WebSocket и файла JavaScript. Класс терминала WebSocket содержит несколько базовых методов, которые выполняются при открытии сеанса. Затем необходимо создать файл JavaScript, который запускает процесс квитирования с сервером при загрузке страницы. После этого останется только запустить приложение и проверить подключение. |
| |
| Дополнительные сведения об использовании API-интерфейсов и аннотаций WebSocket см. в описании пакета link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/package-summary.html[+ javax.websocket+]. |
| |
| |
| === Создание терминала |
| |
| В этом упражнении показано, как создать класс терминала WebSocket с помощью мастера IDE. |
| |
| 1. В окне 'Проекты' щелкните правой кнопкой мыши узел 'Исходные пакеты' и выберите 'Создать > Другие'. |
| 2. В категории 'Веб' выберите 'Терминал WebSocket'. Нажмите 'Далее'. |
| 3. В поле 'Имя класса' введите *MyWhiteboard*. |
| 4. В списке 'Пакет' выберите ``org.sample.whiteboardapp`` . |
| 5. В поле 'WebSocket URI' введите */whiteboardendpoint*. Нажмите 'Готово'. |
| |
| image::images/websocket-newendpoint.png[title="Терминал WebSocket в мастере создания файлов"] |
| |
| При нажатии кнопки 'Готово' среда IDE создает класс терминала WebSocket и открывает файл в редакторе исходного кода. При просмотре файла в редакторе вы увидите, что среда IDE сгенерировала несколько аннотаций, которые входят в состав API-интерфейса WebSocket. Класс имеет аннотацию ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/server/ServerEndpoint.html[+@ServerEndpoint+]`` , указывающую на его принадлежность к классам терминала, а в качестве параметра аннотации указан WebSocket URI. Среда IDE также создает стандартный метод ``onMessage`` с аннотацией ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnMessage.html[+@OnMessage+]`` . Метод с аннотацией ``@OnMessage`` вызывается каждый раз, когда клиент получает сообщение WebSocket. |
| |
| |
| [source,java] |
| ---- |
| |
| @ServerEndpoint("/whiteboardendpoint") |
| public class MyWhiteboard { |
| |
| @OnMessage |
| public String onMessage(String message) { |
| return null; |
| } |
| |
| } |
| ---- |
| |
| |
| . Добавьте в класс следующее поле (выделено *полужирным шрифтом*). |
| |
| [source,java] |
| ---- |
| |
| @ServerEndpoint("/whiteboardendpoint") |
| public class MyWhiteboard { |
| *private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());* |
| |
| @OnMessage |
| public String onMessage(String message) { |
| return null; |
| } |
| } |
| ---- |
| |
| |
| . Добавьте методы ``onOpen`` и ``onClose`` . |
| |
| [source,java] |
| ---- |
| |
| @OnOpen |
| public void onOpen (Session peer) { |
| peers.add(peer); |
| } |
| |
| @OnClose |
| public void onClose (Session peer) { |
| peers.remove(peer); |
| } |
| ---- |
| |
| Методы ``onOpen`` и ``onClose`` имеют аннотации API-интерфейса WebSocket: ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnOpen.html[+@OnOpen+]`` и ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnClose.html[+@OnClose+]`` . Метод с аннотацией ``@OnOpen`` вызывается при открытии сеанса WebSocket. В этом примере аннотированный метод ``onOpen`` добавляет браузерного клиента в группу одноранговых узлов текущего сеанса, а метод ``onClose`` удаляет клиента из этой группы. |
| |
| Создайте методы, используя подсказки и автозавершение кода в редакторе исходного кода. Щелкните значок подсказки в левом поле рядом с объявлением класса (или поместите указатель мыши на объявление класса и нажмите Alt-Enter), затем выберите этот метод в раскрывающемся меню. Для создания кода метода можно использовать автозавершение кода. |
| |
| image::images/websocket-endpoint-hint.png[title="Подсказка к коду в редакторе исходного кода"] |
| |
| |
| |
| . Щелкните правой кнопкой мыши в редакторе и выберите 'Исправить операторы импорта' (Alt-Shift-I; ⌘-Shift-I для Mac). Сохраните изменения. |
| |
| В результате в файл будут добавлены операторы импорта для классов в ``javax.websocket`` . |
| |
| Терминал создан. Теперь необходимо создать файл JavaScript для инициализации сеанса WebSocket. |
| |
| |
| |
| |
| === Инициализация сеанса WebSocket |
| |
| Этот раздел содержит инструкции по созданию файла JavaScript для инициализации сеанса WebSocket. Браузерный клиент подключается к сеансу, используя HTTP-запрос для квитирования с сервером по протоколу TCP. В файле JavaScript необходимо указать ``wsURI`` терминала и объявить WebSocket. Схема ``wsURI`` является составным элементом протокола WebSocket и указывает путь к терминалу для приложения. |
| |
| 1. Щелкните правой кнопкой мыши узел проекта в окне "Проекты" и выберите "New > Other"(Создать > Другое). |
| 2. Откройте мастер создания файлов и выберите 'Файл JavaScript' в категории 'Веб'. Нажмите 'Далее'. |
| 3. В поле 'Имя файла JavaScript' введите *websocket*. Нажмите 'Готово'. |
| 4. Добавьте в файл JavaScript следующие элементы. |
| |
| [source,javascript] |
| ---- |
| |
| var wsUri = "ws://" + document.location.host + document.location.pathname + "whiteboardendpoint"; |
| var websocket = new WebSocket(wsUri); |
| |
| websocket.onerror = function(evt) { onError(evt) }; |
| |
| function onError(evt) { |
| writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data); |
| } |
| ---- |
| |
| Этот сценарий инициализирует квитирование сеанса с сервером, когда браузер загружает файл ``websocket.js`` . |
| |
| |
| |
| . Откройте файл ``index.html`` и добавьте следующий код (выделен *полужирным шрифтом*) в самый нижний сегмент файла, чтобы по завершении загрузки страницы загружался файл ``websocket.js`` . |
| |
| [source,html] |
| ---- |
| |
| <body> |
| *<h1>Collaborative Whiteboard App</h1> |
| |
| <script type="text/javascript" src="websocket.js"></script>* |
| </body> |
| ---- |
| |
| Теперь можно проверить функционирование терминала WebSocket, возможность открытия сеанса и подключения клиента к сеансу. |
| |
| |
| |
| |
| === Тестирование терминала |
| |
| В этом упражнении показано, как добавить ряд простых методов в файл JavaScript, чтобы при подключении браузера к терминалу в окне браузера выводились данные ``wsURI`` . |
| |
| 1. Добавьте тег ``<div>`` (выделен *полужирным шрифтом*) в файл ``index.html`` |
| |
| [source,html] |
| ---- |
| |
| <h1>Collaborative Whiteboard App</h1> |
| |
| *<div id="output"></div>* |
| <script type="text/javascript" src="websocket.js"></script> |
| ---- |
| |
| |
| . Добавьте следующее объявление и методы в файл ``websocket.js`` . Сохраните изменения. |
| |
| [source,javascript] |
| ---- |
| |
| // For testing purposes |
| var output = document.getElementById("output"); |
| websocket.onopen = function(evt) { onOpen(evt) }; |
| |
| function writeToScreen(message) { |
| output.innerHTML += message + "<br>"; |
| } |
| |
| function onOpen() { |
| writeToScreen("Connected to " + wsUri); |
| } |
| // End test functions |
| ---- |
| |
| При загрузке страницы функции JavaScript будут выводить сообщение о том, что браузер подключен к терминалу. Эти функции можно удалить после успешной проверки функционирования терминала. |
| |
| |
| |
| . Правой кнопкой мыши щелкните окно 'Проект' и выберите 'Выполнить'. |
| |
| При запуске приложения среда IDE запускает сервер GlassFish и выполняет построение и развертывание приложения. В браузере открывается страница индекса со следующим сообщением. |
| |
| image::images/websocket-browser1.png[title="Сообщение 'Подключение к терминалу установлено' в окне браузера"] |
| |
| В окне браузера отображается терминал, принимающий сообщения: ``http://localhost:8080/WhiteboardApp/whiteboardendpoint`` |
| |
| |
| == Создание интерактивной доски |
| |
| Этот раздел содержит инструкции по созданию классов и файлов JavaScript для отправки и получения текстовых сообщений JSON. Также в этом разделе показано, как создать элемент link:http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html[+HTML5 Canvas+] для рисования и отображения содержимого и HTML-форму ``<form>`` с переключателями, с помощью которых можно выбрать форму и цвет кисти. |
| |
| |
| === Добавление полотна на веб-страницу |
| |
| В этом упражнении показано, как добавить элемент ``canvas`` и элемент ``form`` на страницу индекса по умолчанию. Флажки на форме определяют свойства кисти на полотне. |
| |
| 1. Откройте файл ``index.html`` в редакторе исходного кода. |
| 2. Удалите тег ``<div>`` , добавленный перед тестированием терминала, и добавьте элементы ``<table>`` и ``<form>`` (выделены *полужирным шрифтом*) после открывающего тега body. |
| |
| [source,html] |
| ---- |
| |
| <h1>Collaborative Whiteboard App</h1> |
| |
| *<table> |
| <tr> |
| <td> |
| </td> |
| <td> |
| <form name="inputForm"> |
| |
| |
| </form> |
| </td> |
| </tr> |
| </table>* |
| <script type="text/javascript" src="websocket.js"></script> |
| </body> |
| ---- |
| |
| |
| . Добавьте следующий код (выделен *полужирным шрифтом*) для элемента canvas. |
| |
| [source,html] |
| ---- |
| |
| <table> |
| <tr> |
| <td> |
| *<canvas id="myCanvas" width="150" height="150" style="border:1px solid #000000;"></canvas>* |
| </td> |
| ---- |
| |
| |
| . Добавьте элемент ``<table>`` для создания переключателей, позволяющих выбирать цвет и форму. Сохраните изменения. |
| |
| [source,html] |
| ---- |
| |
| <table> |
| <tr> |
| <td> |
| <canvas id="myCanvas" width="150" height="150" style="border:1px solid #000000;"></canvas> |
| </td> |
| <td> |
| <form name="inputForm"> |
| *<table> |
| |
| <tr> |
| <th>Color</th> |
| <td><input type="radio" name="color" value="#FF0000" checked="true">Red</td> |
| <td><input type="radio" name="color" value="#0000FF">Blue</td> |
| <td><input type="radio" name="color" value="#FF9900">Orange</td> |
| <td><input type="radio" name="color" value="#33CC33">Green</td> |
| </tr> |
| |
| <tr> |
| <th>Shape</th> |
| <td><input type="radio" name="shape" value="square" checked="true">Square</td> |
| <td><input type="radio" name="shape" value="circle">Circle</td> |
| <td> </td> |
| <td> </td> |
| </tr> |
| |
| </table>* |
| </form> |
| ---- |
| |
| Форма, цвет и координаты любой фигуры, нарисованной на полотне, преобразуются в строковые данные в структуре JSON и отправляются в виде сообщения на терминал WebSocket. |
| |
| |
| |
| |
| === Создание POJO |
| |
| В этом упражнении показано, как создать простой компонент POJO. |
| |
| 1. Щелкните узел проекта правой кнопкой мыши и выберите Создать > Класс Java. |
| 2. В поле 'Имя класса' введите *Figure* и выберите ``org.sample.whiteboardapp`` в списке 'Пакет'. Нажмите 'Готово'. |
| 3. В редакторе исходного кода добавьте следующие элементы (выделены *полужирным шрифтом*): |
| |
| [source,java] |
| ---- |
| |
| public class Figure { |
| *private JsonObject json;* |
| } |
| ---- |
| |
| При добавлении кода отобразится запрос на добавление оператора импорта для ``javax.json.JsonObject`` . Если запрос не отображается, нажмите Alt-Enter. |
| |
| Дополнительные сведения о ``javax.json.JsonObject`` см. в описании интерфейса Java API for JSON Processing (link:http://jcp.org/en/jsr/detail?id=353[+JSR 353+]), который входит в спецификацию Java EE 7. |
| |
| |
| |
| . Создайте операторы получения и установки для ``json`` . |
| |
| Методы получения и установки можно выбрать в раскрывающемся меню 'Вставить код' (Alt-Ins в Windows; Ctrl-I в Mac). В результате откроется диалоговое окно 'Создание методов получения и установки'. Также можно выбрать Исходный код > Вставить код в главном меню. |
| |
| image::images/websocket-generategetter.png[title="Диалоговое окно 'Создание методов получения и установки'"] |
| |
| |
| |
| . Добавьте конструктор для ``json`` . |
| |
| [source,java] |
| ---- |
| |
| public Figure(JsonObject json) { |
| this.json = json; |
| } |
| ---- |
| |
| Конструктор можно выбрать в раскрывающемся меню 'Вставить код' (Ctrl-I). |
| |
| image::images/websocket-generateconstructor.png[title="Раскрывающееся меню 'Создать конструктор'"] |
| |
| |
| . Добавьте метод ``toString`` : |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public String toString() { |
| StringWriter writer = new StringWriter(); |
| Json.createWriter(writer).write(json); |
| return writer.toString(); |
| } |
| ---- |
| |
| |
| . Щелкните правой кнопкой мыши в редакторе и выберите 'Исправить операторы импорта' (Alt-Shift-I; ⌘-Shift-I для Mac). Сохраните изменения. |
| |
| |
| |
| === Создание класса координат |
| |
| Теперь необходимо создать класс координат фигур, которые пользователи будут рисовать на полотне. |
| |
| 1. Щелкните узел проекта правой кнопкой мыши и выберите Создать > Класс Java. |
| 2. Откроется мастер создания классов Java. В поле 'Имя класса' введите *Coordinates* и выберите ``org.sample.whiteboardapp`` в списке 'Пакет'. Нажмите 'Готово'. |
| 3. В редакторе исходного кода добавьте следующий код. Сохраните изменения. |
| |
| [source,java] |
| ---- |
| |
| private float x; |
| private float y; |
| |
| public Coordinates() { |
| } |
| |
| public Coordinates(float x, float y) { |
| this.x = x; |
| this.y = y; |
| } |
| |
| public float getX() { |
| return x; |
| } |
| |
| public void setX(float x) { |
| this.x = x; |
| } |
| |
| public float getY() { |
| return y; |
| } |
| |
| public void setY(float y) { |
| this.y = y; |
| } |
| |
| ---- |
| |
| Этот класс содержит только поля для координат ``x`` и ``y`` , а также несколько методов получения и установки. |
| |
| |
| |
| |
| === Создание строки JSON |
| |
| В этом упражнении показано, как создать файл JavaScript, преобразующий все сведения о фигуре, которую пользователь рисует на полотне (элемент ``canvas`` ), в структуру JSON для отправки на терминал WebSocket. |
| |
| 1. Щелкните узел проекта правой кнопкой мыши и выберите Создать > Файл JavaScript. В результате откроется мастер создания файлов JavaScript. |
| 2. В поле 'Имя файла' введите *whiteboard*. Нажмите 'Готово'. |
| |
| При нажатии кнопки 'Готово' среда IDE создает пустой файл JavaScript и открывает его в редакторе. Новый файл отображается в структуре узла 'Веб-страницы' в окне 'Проекты'. |
| |
| |
| |
| . Добавьте следующий код для инициализации элемента canvas и создания прослушивателя событий. |
| |
| [source,javascript] |
| ---- |
| |
| var canvas = document.getElementById("myCanvas"); |
| var context = canvas.getContext("2d"); |
| canvas.addEventListener("click", defineImage, false); |
| ---- |
| |
| Когда пользователь нажимает на полотно (элемент ``canvas`` ), вызывается метод ``defineImage`` . |
| |
| |
| |
| . Добавьте методы ``getCurrentPos`` , ``defineImage`` и ``drawImageText`` для создания структуры JSON и ее отправки на терминал ( ``sendText(json)`` ). |
| |
| [source,javascript] |
| ---- |
| |
| function getCurrentPos(evt) { |
| var rect = canvas.getBoundingClientRect(); |
| return { |
| x: evt.clientX - rect.left, |
| y: evt.clientY - rect.top |
| }; |
| } |
| |
| function defineImage(evt) { |
| var currentPos = getCurrentPos(evt); |
| |
| for (i = 0; i < document.inputForm.color.length; i++) { |
| if (document.inputForm.color[i].checked) { |
| var color = document.inputForm.color[i]; |
| break; |
| } |
| } |
| |
| for (i = 0; i < document.inputForm.shape.length; i++) { |
| if (document.inputForm.shape[i].checked) { |
| var shape = document.inputForm.shape[i]; |
| break; |
| } |
| } |
| |
| var json = JSON.stringify({ |
| "shape": shape.value, |
| "color": color.value, |
| "coords": { |
| "x": currentPos.x, |
| "y": currentPos.y |
| } |
| }); |
| drawImageText(json); |
| sendText(json); |
| } |
| |
| function drawImageText(image) { |
| console.log("drawImageText"); |
| var json = JSON.parse(image); |
| context.fillStyle = json.color; |
| switch (json.shape) { |
| case "circle": |
| context.beginPath(); |
| context.arc(json.coords.x, json.coords.y, 5, 0, 2 * Math.PI, false); |
| context.fill(); |
| break; |
| case "square": |
| default: |
| context.fillRect(json.coords.x, json.coords.y, 10, 10); |
| break; |
| } |
| } |
| ---- |
| |
| Готовая к отправке структура JSON будет выглядеть примерно так: |
| |
| |
| [source,javascript] |
| ---- |
| |
| { |
| "shape": "square", |
| "color": "#FF0000", |
| "coords": { |
| "x": 31.59999942779541, |
| "y": 49.91999053955078 |
| } |
| } |
| ---- |
| |
| Теперь необходимо добавить метод ``sendText(json)`` для отправки строковых данных JSON с помощью ``websocket.send()`` . |
| |
| |
| |
| . Откройте файл ``websocket.js`` в редакторе и добавьте следующие методы для отправки JSON на терминал и рисования изображения при получении сообщения от терминала. |
| |
| [source,javascript] |
| ---- |
| |
| websocket.onmessage = function(evt) { onMessage(evt) }; |
| |
| function sendText(json) { |
| console.log("sending text: " + json); |
| websocket.send(json); |
| } |
| |
| function onMessage(evt) { |
| console.log("received: " + evt.data); |
| drawImageText(evt.data); |
| } |
| ---- |
| |
| NOTE: Код, добавленный в файл ``websocket.js`` для тестирования терминала, можно удалить. |
| |
| |
| |
| . Добавьте следующую строку (выделена *полужирным шрифтом*) в нижний сегмент файла ``index.html`` для загрузки файла ``whiteboard.js`` . |
| |
| [source,html] |
| ---- |
| |
| </table> |
| <script type="text/javascript" src="websocket.js"></script> |
| *<script type="text/javascript" src="whiteboard.js"></script>* |
| <body> |
| |
| ---- |
| |
| |
| |
| === Реализация интерфейсов кодера и декодера |
| |
| В этом упражнении показано, как создать классы для реализации интерфейсов декодера и кодера, которые требуются для преобразования сообщений WebSocket (JSON) в класс POJO ``Figure`` и преобразования класса ``Figure`` в формат строковых данных JSON, отправляемых на терминал. |
| |
| Дополнительные сведения можно найти в разделе технической статьи о типах сообщений, кодерах и декодерах link:http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html[+JSR 356, Java API for WebSocket+]. |
| |
| 1. Щелкните узел проекта правой кнопкой мыши и выберите Создать > Класс Java. |
| 2. В поле 'Имя класса' введите *FigureEncoder* и выберите ``org.sample.whiteboardapp`` в списке 'Пакет'. Нажмите 'Готово'. |
| 3. В редакторе исходного кода реализуйте интерфейс кодера WebSocket. Для этого добавьте следующий код (выделен *полужирным шрифтом*): |
| |
| [source,java] |
| ---- |
| |
| |
| public class FigureEncoder *implements Encoder.Text<Figure>* { |
| |
| } |
| ---- |
| |
| |
| . Добавьте оператор импорта для ``javax.websocket.Encoder`` и реализуйте абстрактные методы. |
| |
| Поместите указатель мыши на объявление класса, нажмите Alt-Enter и выберите *Реализовать все абстрактные методы* в раскрывающемся меню. |
| |
| |
| |
| . Внесите следующие изменения в созданные абстрактные методы (выделены *полужирным шрифтом*). Сохраните изменения. |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public String encode(Figure *figure*) throws EncodeException { |
| *return figure.getJson().toString();* |
| } |
| |
| @Override |
| public void init(EndpointConfig ec) { |
| *System.out.println("init");* |
| } |
| |
| @Override |
| public void destroy() { |
| *System.out.println("destroy");* |
| } |
| ---- |
| |
| |
| . Щелкните узел проекта правой кнопкой мыши и выберите Создать > Класс Java. |
| |
| |
| . В поле 'Имя класса' введите *FigureDecoder* и выберите ``org.sample.whiteboardapp`` в списке 'Пакет'. Нажмите 'Готово'. |
| |
| |
| . В редакторе исходного кода реализуйте интерфейс декодера WebSocket. Для этого добавьте следующий код (выделен *полужирным шрифтом*): |
| |
| [source,java] |
| ---- |
| |
| |
| public class FigureDecoder *implements Decoder.Text<Figure>* { |
| |
| } |
| ---- |
| |
| |
| . Добавьте оператор импорта для ``javax.websocket.Decoder`` и реализуйте абстрактные методы. |
| |
| |
| . Внесите следующие изменения (выделены *полужирным шрифтом*) в созданные абстрактные методы. |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public Figure decode(String *string*) throws DecodeException { |
| *JsonObject jsonObject = Json.createReader(new StringReader(string)).readObject(); |
| return new Figure(jsonObject);* |
| } |
| |
| @Override |
| public boolean willDecode(String *string*) { |
| *try { |
| Json.createReader(new StringReader(string)).readObject(); |
| return true; |
| } catch (JsonException ex) { |
| ex.printStackTrace(); |
| return false; |
| }* |
| |
| } |
| |
| @Override |
| public void init(EndpointConfig ec) { |
| *System.out.println("init");* |
| } |
| |
| @Override |
| public void destroy() { |
| *System.out.println("destroy");* |
| } |
| ---- |
| |
| |
| . Исправьте операторы импорта и сохраните изменения. |
| |
| Теперь необходимо внести изменения в файл ``MyWhiteboard.java`` и указать кодер и декодер. |
| |
| |
| |
| |
| === Запуск приложения |
| |
| Скоро вы сможете запустить приложение. В этом упражнении показано, как изменить класс терминала WebSocket и указать кодер и декодер для строковых данных JSON, а также добавить метод для отправки строковых данных JSON на подключенные клиенты при получении сообщения. |
| |
| 1. Откройте файл ``MyWhiteboard.java`` в редакторе. |
| 2. Измените аннотацию ``@ServerEndpoint`` и укажите кодер и декодер для терминала. Обратите внимание, что необходимо явно указать параметр ``value`` для имени терминала. |
| |
| [source,java] |
| ---- |
| |
| @ServerEndpoint(*value=*"/whiteboardendpoint"*, encoders = {FigureEncoder.class}, decoders = {FigureDecoder.class}*) |
| |
| ---- |
| |
| |
| . Удалите метод ``onMessage`` , созданный по умолчанию. |
| |
| |
| . Добавьте метод ``broadcastFigure`` и создайте для него аннотацию ``@OnMessage`` . |
| |
| [source,java] |
| ---- |
| |
| @OnMessage |
| public void broadcastFigure(Figure figure, Session session) throws IOException, EncodeException { |
| System.out.println("broadcastFigure: " + figure); |
| for (Session peer : peers) { |
| if (!peer.equals(session)) { |
| peer.getBasicRemote().sendObject(figure); |
| } |
| } |
| } |
| ---- |
| |
| |
| . Щелкните правой кнопкой мыши в редакторе и выберите 'Исправить операторы импорта' (Alt-Shift-I; ⌘-Shift-I для Mac). Сохраните изменения. |
| |
| |
| . В окне 'Проекты' щелкните проект правой кнопкой мыши и выберите 'Выполнить'. |
| |
| При нажатии кнопки 'Выполнить' среда IDE открывает окно браузера с адресом link:http://localhost:8080/WhiteboardApp/[+http://localhost:8080/WhiteboardApp/+]. |
| |
| NOTE: Может потребоваться удалить предыдущее приложение с сервера приложений или выполнить принудительную перезагрузку страницы в браузере. |
| |
| Просмотрите сообщения браузера. Вы увидите, что при каждом нажатии на полотно на терминал отправляются строковые данные JSON. |
| |
| image::images/websocket-onebrowser.png[title="Полотно с нарисованными фигурами в окне браузера и JSON в веб-консоли"] |
| |
| Если открыть страницу с адресом ``http://localhost:8080/WhiteboardApp/`` в другом браузере, можно видеть, что при каждом нажатии на полотно в окне одного браузера в окне другого браузера появляется новый круг или квадрат. |
| |
| image::images/websocket-twobrowsers.png[title="Два браузера, отправляющие данные JSON через терминал"] |
| |
| |
| == Отправка двоичных данных на терминал |
| |
| Теперь приложение может обрабатывать и отправлять строковые данные через JSON на терминал, а затем эти строковые данные будут пересылаться на подключенные клиенты. Этот раздел содержит инструкции по изменению файлов JavaScript для отправки и получения двоичных данных. |
| |
| Чтобы отправлять двоичные данные на терминал, необходимо задать для свойства ``binaryType`` компонента WebSocket значение ``arraybuffer`` . Таким образом гарантируется, что любые двоичные данные, передаваемые посредством WebSocket, передаются посредством ``ArrayBuffer`` . Преобразование двоичных данных осуществляется методом ``defineImageBinary`` в файле ``whiteboard.js`` . |
| |
| 1. Откройте файл ``websocket.js`` и добавьте в него следующий код, чтобы задать для свойства ``binaryType`` компонента WebSocket значение ``arraybuffer`` . |
| |
| [source,javascript] |
| ---- |
| |
| websocket.binaryType = "arraybuffer"; |
| ---- |
| |
| |
| . Добавьте следующий метод для отправки двоичных данных на терминал. |
| |
| [source,javascript] |
| ---- |
| |
| function sendBinary(bytes) { |
| console.log("sending binary: " + Object.prototype.toString.call(bytes)); |
| websocket.send(bytes); |
| } |
| ---- |
| |
| |
| . Измените метод ``onMessage`` и добавьте в него следующий код (выделен *полужирным шрифтом*), чтобы выбрать метод обновления полотна в соответствии с типом данных, переданных во входящем сообщении. |
| |
| [source,javascript] |
| ---- |
| |
| function onMessage(evt) { |
| console.log("received: " + evt.data); |
| *if (typeof evt.data == "string") {* |
| drawImageText(evt.data); |
| *} else { |
| drawImageBinary(evt.data); |
| }* |
| } |
| ---- |
| |
| Метод ``drawImageBinary`` вызывается при получении сообщения с двоичными данными. |
| |
| |
| |
| . Откройте файл ``whiteboard.js`` и добавьте следующие методы. Метод ``drawImageBinary`` вызывается для обновления полотна после анализа входных двоичных данных. Метод ``defineImageBinary`` используется для подготовки снимка полотна в двоичном формате. |
| |
| [source,javascript] |
| ---- |
| |
| function drawImageBinary(blob) { |
| var bytes = new Uint8Array(blob); |
| // console.log('drawImageBinary (bytes.length): ' + bytes.length); |
| |
| var imageData = context.createImageData(canvas.width, canvas.height); |
| |
| for (var i=8; i<imageData.data.length; i++) { |
| imageData.data[i] = bytes[i]; |
| } |
| context.putImageData(imageData, 0, 0); |
| |
| var img = document.createElement('img'); |
| img.height = canvas.height; |
| img.width = canvas.width; |
| img.src = canvas.toDataURL(); |
| } |
| |
| function defineImageBinary() { |
| var image = context.getImageData(0, 0, canvas.width, canvas.height); |
| var buffer = new ArrayBuffer(image.data.length); |
| var bytes = new Uint8Array(buffer); |
| for (var i=0; i<bytes.length; i++) { |
| bytes[i] = image.data[i]; |
| } |
| sendBinary(buffer); |
| } |
| ---- |
| |
| Теперь необходимо реализовать вызов метода ``defineImageBinary`` , когда требуется сгенерировать двоичные данные с типом ``ArrayBuffer`` и отправить их на терминал. |
| |
| |
| |
| . Откройте файл ``index.html`` и измените элемент ``<table>`` так, чтобы в таблице формы появилась следующая строка. |
| |
| [source,html] |
| ---- |
| |
| <tr> |
| <th> </th> |
| <td><input type="submit" value="Send Snapshot" onclick="defineImageBinary(); return false;"></td> |
| <td> </td> |
| <td> </td> |
| <td> </td> |
| </tr> |
| |
| ---- |
| |
| Новая строка содержит кнопку 'Отправить снимок', которая позволяет отправить двоичный снимок полотна на подключенные одноранговые узлы. При нажатии этой кнопки вызывается метод ``defineImageBinary`` в файле ``whiteboard.js`` . |
| |
| |
| |
| . Откройте файл ``MyWhiteboard.java`` и добавьте следующий метод. Этот метод используется для отправки двоичных данных на одноранговые узлы, когда на терминал поступает сообщение с двоичными данными. |
| |
| [source,java] |
| ---- |
| |
| @OnMessage |
| public void broadcastSnapshot(ByteBuffer data, Session session) throws IOException { |
| System.out.println("broadcastBinary: " + data); |
| for (Session peer : peers) { |
| if (!peer.equals(session)) { |
| peer.getBasicRemote().sendBinary(data); |
| } |
| } |
| } |
| ---- |
| |
| NOTE: Потребуется добавить оператор импорта для ``java.nio.ByteBuffer`` . |
| |
| Вы можете изменить приложение так, чтобы пользователь мог остановить отправку данных на терминал. По умолчанию все одноранговые узлы подключаются в момент открытия страницы и отправки данных из браузера на все подключенные клиенты. Вы можете добавить простой условный оператор, чтобы данные отправлялись на терминал только в том случае, если выбран этот параметр. Этот параметр не влияет на получение данных. Клиенты по-прежнему будут получать данные от терминала. |
| |
| 1. Измените метод ``defineImage`` в файле ``whiteboard.js`` , добавив в него следующий код (выделен *полужирным шрифтом*). |
| |
| [source,javascript] |
| ---- |
| |
| drawImageText(json); |
| * if (document.getElementById("instant").checked) {* |
| sendText(json); |
| * }* |
| } |
| ---- |
| |
| Этот код условия проверяет, ``установлен ли флажок`` для элемента с этим идентификатором |
| |
| |
| |
| . Откройте файл ``index.html`` и измените элемент ``<table>`` , добавив в форму флажок. |
| |
| [source,html] |
| ---- |
| |
| <tr> |
| <th> </th> |
| <td><input type="submit" value="Send Snapshot" onclick="defineImageBinary(); return false;"></td> |
| <td>*<input type="checkbox" id="instant" value="Online" checked="true">Online*</td> |
| <td> </td> |
| <td> </td> |
| </tr> |
| |
| ---- |
| |
| Если флажок 'Подключено' не установлен, отправка данных не осуществляется, но клиенты по-прежнему могут получать данные от терминала. |
| |
| Если добавить кнопку 'Отправить снимок' и флажок 'Подключено' и снова запустить приложение, на странице индекса отобразятся новые элементы. Если открыть другой браузер и снять флажок 'Подключено', можно видеть, что при нажатии на полотно сообщение JSON не отправляется на терминал. |
| |
| image::images/websocket-onebrowser-binary.png[title="Веб-консоль в окне браузера с сообщением об отправке двоичных данных"] |
| |
| Если нажать кнопку 'Отправить снимок', двоичные данные будут отправлены на терминал, который будет транслировать эти данные на все подключенные клиенты. |
| |
| |
| link:/about/contact_form.html?to=3&subject=Feedback:%20Using%20the%20WebSocket%20API%20in%20a%20Web%20Application[+Отправить отзыв по этому учебному курсу+] |
| |
| |
| |
| == См. также |
| |
| Подробнее об использовании IDE NetBeans для разработки приложений Java EE см. в следующих ресурсах: |
| |
| * Демонстрация: link:maven-websocketapi-screencast.html[+Использование WebSocket API в веб-приложении+] |
| * link:javaee-intro.html[+Введение в технологию Java EE +] |
| * link:javaee-gettingstarted.html[+Начало работы с приложениями Java EE+] |
| * link:../../trails/java-ee.html[+Учебная карта по Java EE и Java Web+] |
| |
| Дополнительные сведения об использовании Java EE можно найти в link:http://download.oracle.com/javaee/6/tutorial/doc/[+Учебном курсе по Java EE+]. |
| |
| To send comments and suggestions, get support, and keep informed on the latest developments on the IDE NetBeans Java EE development features, link:../../../community/lists/top.html[+join the nbj2ee mailing list+]. |
| |