| // |
| // 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. |
| // |
| |
| = Usando a API do WebSocket em uma Aplicação Web |
| :jbake-type: tutorial |
| :jbake-tags: tutorials |
| :jbake-status: published |
| :icons: font |
| :syntax: true |
| :source-highlighter: pygments |
| :toc: left |
| :toc-title: |
| :description: Usando a API do WebSocket em uma Aplicação Web - Apache NetBeans |
| :keywords: Apache NetBeans, Tutorials, Usando a API do WebSocket em uma Aplicação Web |
| |
| Este tutorial demonstra como criar uma aplicação Web simples que permite colaboração entre browsers do cliente que estão conectados a uma aplicação do servidor único. Quando um usuário desenha um elemento gráfico em uma tela no browser do cliente, o elemento aparece na tela de todos os clientes conectados. Como isso funciona? Quando o browser carrega a página Web um script do cliente envia uma solicitação de handshake de WebSocket para o servidor de aplicações. A aplicação pode aceitar mensagens binárias e de JSON dos clientes conectados na sessão e transmitir as mensagens para todos os clientes conectados. |
| |
| Neste tutorial você criará uma aplicação web que usa Java API para WebSocket (link:http://www.jcp.org/en/jsr/detail?id=356[+JSR 356+]) para ativar a comunicação bidirecional entre clientes do browser e o servidor de aplicações. Java API para WebSocket fornece suporte para criar componentes de WebSocket Java e interceptar eventos de WebSocket e criar e consumir texto e mensagens binárias de WebSocket. O tutorial também demonstra como você usa a API de Java para Processamento de JSON (link:http://jcp.org/en/jsr/detail?id=353[+JSR 353+]) para produzir e consumir JSON. Java API para WebSocket e a API Java para Processamento de JSON fazem parte da plataforma Java EE 7 (link:http://jcp.org/en/jsr/detail?id=342[+JSR 342+]). |
| |
| A aplicação contém um ponto final de WebSocket e interfaces do decodificador e do codificador, uma página Web e alguns arquivos de JavaScript que são executados no browser do cliente quando a página for carregada ou quando chamada de um form na página Web. Você implantará a aplicação para GlassFish Server Open Source Edition 4, a implementação de referência da tecnologia Java EE 7. |
| |
| NOTE: Este tutorial é baseado no blog 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) (Quadro de Comunicação sobre como usar WebSocket no GlassFish 4 - Texto/JSON e Transferência de Dados/Binário/ArrayBuffer (TOTD #189)) +] e em outros blogs que podem ser encontrados no link:http://blog.arungupta.me/[+blog de Arun Gupta+]. Certifique-se de visitar o blog e ver muitas outras entradas excelentes sobre como trabalhar com a API de WebSocket e com o GlassFish 4. |
| |
| Você também pode assistir ao link:maven-websocketapi-screencast.html[+Vídeo Usando a API do WebSocket em uma Aplicação Web+]. |
| |
| *Exercícios do Tutorial* |
| |
| * <<Exercise_1,Criando o Projeto de Aplicação Web>> |
| * <<createendpoint,Criando o Ponto Final do WebSocket>> |
| * <<createendpoint1,Criar o Ponto Final>> |
| * <<createendpoint2,Iniciar a Sessão de WebSocket>> |
| * <<createendpoint3,Testar o Ponto Final>> |
| * <<createwhiteboard,Criando o Quadro de Comunicação>> |
| * <<createwhiteboard1,Adicionar a Tela>> |
| * <<createwhiteboard2,Criar o POJO>> |
| * <<createwhiteboard3,Criar uma Classe de Coordenadas>> |
| * <<createwhiteboard6,Gerar a String JSON>> |
| * <<createwhiteboard4,Implementar as Interfaces do Codificador e do Decodificador>> |
| * <<createwhiteboard5,Executar a Aplicação>> |
| * <<sendbinary,Enviando Dados Binários para o Ponto Final>> |
| |
| *Para seguir este tutorial, são necessários os recursos e o software a seguir.* |
| |
| |=== |
| |Software ou Recurso |Versão Necessária |
| |
| |link:https://netbeans.org/downloads/index.html[+NetBeans IDE+] |Versão Java EE 7.3.1, 7.4, 8.0 |
| |
| |link:http://www.oracle.com/technetwork/java/javase/downloads/index.html[+JDK (Java Development Kit)+] |versão 7 ou 8 |
| |
| |link:https://glassfish.java.net/[+GlassFish Server Open Source Edition+] |4 |
| |=== |
| |
| NOTE: O GlassFish 4 está incluído no pacote de downloads do Java EE do NetBeans IDE. |
| |
| *Pré-requisitos* |
| |
| Este tutorial pressupõe que você tenha algum conhecimento básico das tecnologias a seguir, ou alguma experiência de programação com elas: |
| |
| * Programação em Java |
| * Programação de JavaScript/HTML |
| * NetBeans IDE |
| |
| Antes de começar este tutorial, talvez você queira se familiarizar com a documentação a seguir. |
| |
| * link:http://wiki.netbeans.org/MavenBestPractices[+Melhores Práticas para o Apache Maven no NetBeans IDE+] |
| * link:http://books.sonatype.com/mvnref-book/reference/introduction.html[+Capítulo 1. Introdução ao Apache Maven+] (do link:http://books.sonatype.com/mvnref-book/reference/index.html[+Maven: A Referência Completa +]) |
| |
| Você pode fazer download link:https://netbeans.org/projects/samples/downloads/download/Samples/JavaEE/WhiteboardApp.zip[+de um arquivo compactado zip do projeto finalizado+]. |
| |
| |
| == Criando o Projeto de Aplicação Web |
| |
| O objetivo deste exercício é criar um projeto de aplicação Web usando o assistente Novo Projeto noIDE. Quando você criar o projeto irá selecionar Java EE 7 como a versão do Java EE e GlassFish 4 como o servidor de aplicações. O GlassFish 4 é a implementação de referência da plataforma Java EE 7. Você deve ter um servidor de aplicações que suporta Java EE 7 registrado com o IDE para criar a aplicação neste tutorial. |
| |
| 1. Selecione Arquivo > Novo Projeto (Ctrl-Shift-N no Windows, ⌘-Shift-N no Mac) no menu principal. |
| 2. Selecione Aplicação Web na categoria Maven. Clique em Próximo. |
| 3. Digite *WhiteboardApp* como nome do projeto e defina a Localização do Projeto. |
| 4. Digite *org.sample* para o Id do Grupo. Clique em Próximo. |
| 5. Selecione *GlassFish Server 4.0* para o Servidor. |
| 6. Defina a Versão do Java EE como *Java EE 7 Web*. Clique em Finalizar. |
| |
| image::images/websocket-newproject.png[title="Versões de servidor e Java EE no assistente de Novo Projeto"] |
| |
| Quando você clica em Finalizar, o IDE cria o projeto e o abre na janela Projetos. |
| |
| |
| == Criando o Ponto Final do WebSocket |
| |
| Nesta seção você criará uma classe e um ponto final de WebSocket e um arquivo JavaScript. A classe do ponto final de WebSocket contém alguns métodos básicos que são executados quando a sessão for aberta. Em seguida, você irá criar um arquivo JavaScript que iniciará o handshake com o servidor quando a página for carregada. Você irá então executar a aplicação para testar se a conexão foi bem-sucedida. |
| |
| Para obter mais informações sobre como usar APIs e anotações de WebSocket, consulte o resumo do pacote link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/package-summary.html[+ javax.websocket +]. |
| |
| |
| === Criando o Ponto Final |
| |
| Neste exercício você usará usar um assistente no IDE para ajudá-lo a criar a classe do ponto final de WebSocket. |
| |
| 1. Clique com o botão direito do mouse no nó Pacotes do Código-fonte na janela Projetos e selecione Novo > Outro. |
| 2. Selecione Ponto Final de WebSocket na categoria Web. Clique em Próximo. |
| 3. Digite *MyWhiteboard* como o Nome da Classe. |
| 4. Selecione ``org.sample.whiteboardapp`` na lista drop-down Pacote. |
| 5. Digite */whiteboardendpoint* como o URI de WebSocket. Clique em Finalizar. |
| |
| image::images/websocket-newendpoint.png[title="Ponto Final de WebSocket no assistente Novo Arquivo"] |
| |
| Quando você clica em Finalizar, o IDE gera a classe Ponto Final do WebSocket e abre a classe no editor de código-fonte. No editor, você pode ver que o IDE gerou algumas anotações que são parte da API do WebSocket. A classe é anotada com ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/server/ServerEndpoint.html[+@ServerEndpoint+]`` para identificar a classe como um ponto final e o URI do WebSocket é especificado como um parâmetro da anotação. O IDE também gerou um método ``onMessage`` default que é anotado com ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnMessage.html[+@onmessage+]`` . Um método anotado com ``@onmessage`` é chamado cada vez que o cliente recebe uma mensagem de WebSocket. |
| |
| |
| [source,java] |
| ---- |
| |
| @ServerEndpoint("/whiteboardendpoint") |
| public class MyWhiteboard { |
| |
| @OnMessage |
| public String onMessage(String message) { |
| return null; |
| } |
| |
| } |
| ---- |
| |
| |
| . Adicione os campos a seguir (em *negrito*) à classe. |
| |
| [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; |
| } |
| } |
| ---- |
| |
| |
| . Adicione os seguintes métodos ``onOpen`` e ``onClose`` . |
| |
| [source,java] |
| ---- |
| |
| @OnOpen |
| public void onOpen (Session peer) { |
| peers.add(peer); |
| } |
| |
| @OnClose |
| public void onClose (Session peer) { |
| peers.remove(peer); |
| } |
| ---- |
| |
| Você pode ver que os métodos ``onOpen`` e ``onClose`` são anotados com as anotações da API de WebSocket ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnOpen.html[+@OnOpen+]`` e ``link:https://javaee-spec.java.net/nonav/javadocs/javax/websocket/OnClose.html[+@OnClose+]`` . Um método anotado com ``@OnOpen`` é chamado quando a sessão de web socket é aberta. Neste exemplo, o método ``onOpen`` anotado adiciona o cliente do browser ao grupo de colegas da sessão atual e o método ``onClose`` remove o browser do grupo. |
| |
| Use as dicas e a funcionalidade autocompletar código no editor de código-fonte para ajudá-lo a gerar os métodos. Clique no glifo de dicas na margem esquerda próxima à declaração de classe (ou coloque o cursor na declaração de classe e clique em Alt-Enter) e selecione o método no menu pop-up. A funcionalidade autocompletar código pode ajudá-lo a codificar o método. |
| |
| image::images/websocket-endpoint-hint.png[title="Dica do Código no Editor de Código-fonte"] |
| |
| |
| |
| . Clique com o botão direito do mouse no editor e selecione Corrigir Importações (Alt-Shift-I; ⌘-Shift-I no Mac). Salve as alterações. |
| |
| Você verá que as instruções de importação das classes no ``javax.websocket`` foram adicionadas ao arquivo. |
| |
| O ponto final agora foi criado. Agora você precisará criar um arquivo JavaScript para iniciar a sessão WebSocket. |
| |
| |
| |
| |
| === Iniciar a Sessão de WebSocket |
| |
| Neste exercício você criará um arquivo JavaScript que iniciará uma sessão de WebSocket. O cliente do browser junta-se a uma sessão por meio de um 'handshake' HTTP com o servidor em TCP. No arquivo JavaScript você especificará o nome do ``wsURI`` do ponto final e declarará o WebSocket. O esquema do URI ``wsURI`` faz parte do protocolo de WebSocket e especifica o caminho para o ponto final da aplicação. |
| |
| 1. Clique com o botão direito do mouse no nó do projeto na janela Projetos e escolha Novo > Outro. |
| 2. Selecione o Arquivo JavaScript na categoria Web do assistente Novo Arquivo. Clique em Próximo. |
| 3. Digite *websocket* para o Nome do Arquivo JavaScript. Clique em Finalizar. |
| 4. Adicione o seguinte ao arquivo 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); |
| } |
| ---- |
| |
| Este script iniciará o handshake da sessão com o servidor quando ``websocket.js`` for carregado pelo browser. |
| |
| |
| |
| . Abra ``index.html`` e adicione o seguinte código (em *negrito*) na parte inferior do arquivo para carregar ``websocket.js`` quando a página terminar de carregar. |
| |
| [source,html] |
| ---- |
| |
| <body> |
| *<h1>Collaborative Whiteboard App</h1> |
| |
| <script type="text/javascript" src="websocket.js"></script>* |
| </body> |
| ---- |
| |
| Agora você pode testar se o ponto final do WebSocket está trabalhando e se a sessão foi iniciada e o cliente adicionado à sessão. |
| |
| |
| |
| |
| === Testando o Ponto Final |
| |
| Neste exercício você adicionará alguns métodos simples ao arquivo JavaScript para imprimir o ``wsURI`` na janela do browser quando o browser for conectado ao ponto final. |
| |
| |
| |
| . Adicione a seguinte tag ``<div>`` (em *negrito*) para ``index.html`` |
| |
| [source,html] |
| ---- |
| |
| <h1>Collaborative Whiteboard App</h1> |
| |
| *<div id="output"></div>* |
| <script type="text/javascript" src="websocket.js"></script> |
| ---- |
| |
| |
| . Adicione a seguinte declaração e métodos ao ``websocket.js`` . Salve as alterações. |
| |
| [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 |
| ---- |
| |
| Quando a página carregar as funções de JavaScript imprimirá a mensagem que o browser está conectado ao ponto final. Você pode deletar as funções depois que confirmar se o ponto final está executando corretamente. |
| |
| |
| |
| . Clique com o botão direito do mouse na janela Projetos e selecione Executar. |
| |
| Quando você executar a aplicação, o IDE iniciará o GlassFish server e construirá e implantará a aplicação. A página de índice será aberta no seu browser e você verá a seguinte mensagem na janela do browser. |
| |
| image::images/websocket-browser1.png[title="Conectado à mensagem do ponto final na janela do browser"] |
| |
| Na janela do browser você pode ver o seguinte ponto final no qual as mensagens serão aceitas: ``http://localhost:8080/WhiteboardApp/whiteboardendpoint`` |
| |
| |
| == Criando o Quadro de Comunicação |
| |
| Nesta seção você criará as classes e os arquivos JavaScript para enviar e receber mensagens de texto de JSON. Você também adicionará um elemento link:http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html[+Tela HTML5+] para exibição de conteúdo e ``<form>`` HTML com botões de rádio que permitem que você especifique o formato e cor do pincel. |
| |
| |
| === Adicionar a Tela à Página Web |
| |
| Neste exercício você adicionar um elemento ``canvas`` e um elemento ``form`` à página do índice default. As caixas de seleção no form determinam as propriedades do pincel da tela. |
| |
| 1. Abra ``index.html`` no editor de código-fonte. |
| 2. Delete a tag ``<div>`` que você adicionou para testar o ponto final e adicione os seguintes elementos ``<table>`` e ``<form>`` (em *bold*) após abrir a tag do corpo. |
| |
| [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> |
| ---- |
| |
| |
| . Adicione o seguinte código (em *negrito*) ao elemento canvas. |
| |
| [source,html] |
| ---- |
| |
| <table> |
| <tr> |
| <td> |
| *<canvas id="myCanvas" width="150" height="150" style="border:1px solid #000000;"></canvas>* |
| </td> |
| ---- |
| |
| |
| . Adicione a seguinte ``<table>`` para adicionar os botões de rádio para selecionar a cor e o formato. Salve as alterações. |
| |
| [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> |
| ---- |
| |
| O formato, cor e coordenadas de qualquer figura desenhada na tela serão convertidos em uma string em uma estrutura JSON e enviadas como uma mensagem ao ponto final de WebSocket. |
| |
| |
| |
| |
| === Criando o POJO |
| |
| Neste exercício você criará um POJO simples. |
| |
| 1. Clique com o botão direito do mouse no nó do projeto e selecione Novo > Classe Java. |
| 2. Digite *Figura* como o Nome da Classe e escolha ``org.sample.whiteboardapp`` na lista drop-down Pacote. Clique em Finalizar. |
| 3. No editor de origem, adicione o seguinte (em *negrito*): |
| |
| [source,java] |
| ---- |
| |
| public class Figure { |
| *private JsonObject json;* |
| } |
| ---- |
| |
| Quando você adicionar o código será solicitado que adicione uma instrução de importação para ``javax.json.jsonobject`` . Se não for solicitado, digite Alt-Enter. |
| |
| Para obter mais informações sobre ``javax.json.JsonObject`` , consulte Java API para Processamento de JSON (link:http://jcp.org/en/jsr/detail?id=353[+JSR 353+]), que faz parte da Especificação Java EE 7. |
| |
| |
| |
| . Criar um getter e setter para ``json`` . |
| |
| Você pode selecionar getter e setter no menu pop-up Inserir Código (Alt-Ins no Windows; Ctrl-I no Mac) para abrir a caixa de diálogo Gerar Getters e Setter. Se preferir, você pode escolher Origem > Inserir Código no menu principal. |
| |
| image::images/websocket-generategetter.png[title="Caixa de diálogo Gerar Getter e Setter"] |
| |
| |
| |
| . Adicione um construtor para ``json`` . |
| |
| [source,java] |
| ---- |
| |
| public Figure(JsonObject json) { |
| this.json = json; |
| } |
| ---- |
| |
| Você pode escolher Construtor no menu pop-up Inserir Código (Ctrl-I). |
| |
| image::images/websocket-generateconstructor.png[title="Menu pop-up Gerar Construtor"] |
| |
| |
| |
| . Adicione o método ``toString`` a seguir: |
| |
| [source,java] |
| ---- |
| |
| @Override |
| public String toString() { |
| StringWriter writer = new StringWriter(); |
| Json.createWriter(writer).write(json); |
| return writer.toString(); |
| } |
| ---- |
| |
| |
| . Clique com o botão direito do mouse no editor e selecione Corrigir Importações (Alt-Shift-I; ⌘-Shift-I no Mac). Salve as alterações. |
| |
| |
| |
| === Criar uma Classe de Coordenadas |
| |
| Agora você cria uma classe para as coordenadas das figuras que são pintadas na tela. |
| |
| 1. Clique com o botão direito do mouse no nó do projeto e selecione Novo > Classe Java. |
| 2. No assistente Nova Classe Java, digite *Coordinadas* como o Nome da Classe e selecione ``org.sample.whiteboardapp`` na lista drop-down Pacote. Clique em Finalizar. |
| 3. No editor de Código-fonte, adicione o seguinte código. Salve as alterações. |
| |
| [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; |
| } |
| |
| ---- |
| |
| A classe só contém campos para as coordenadas ``x`` e ``y`` e alguns getters e setters. |
| |
| |
| |
| |
| === Gerar a String JSON |
| |
| Neste exercício você criará um arquivo JavaScript que coloca os detalhes da figura que é desenhada no elemento ``canvas`` para uma estrutura JSON que é enviada para o ponto final do websocket. |
| |
| 1. Clique com o botão direito no nó e escolha Novo > Arquivo JavaScript para abrir o assistente Novo Arquivo JavaScript. |
| 2. Digite *quadro de comunicações* para Nome do Arquivo. Clique em Finalizar. |
| |
| Quando você clica em Finalizar, o IDE cria o arquivo JavaScript vazio e o abre no editor. Você pode ver o novo arquivo no nó Páginas Web, na janela Projetos. |
| |
| |
| |
| . Adicione o seguinte código para iniciar a tela e adicionar um listener de evento. |
| |
| [source,javascript] |
| ---- |
| |
| var canvas = document.getElementById("myCanvas"); |
| var context = canvas.getContext("2d"); |
| canvas.addEventListener("click", defineImage, false); |
| ---- |
| |
| Você pode ver que o método ``defineImage`` é chamado quando o usuário clica no elemento ``canvas`` . |
| |
| |
| |
| . Adicione os seguintes métodos ``getCurrentPos`` , ``defineImage`` e ``drawImageText`` para construir a estrutura JSON e enviá-la ao ponto final ( ``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; |
| } |
| } |
| ---- |
| |
| A estrutura JSON que é enviada será semelhante à seguinte: |
| |
| |
| [source,javascript] |
| ---- |
| |
| { |
| "shape": "square", |
| "color": "#FF0000", |
| "coords": { |
| "x": 31.59999942779541, |
| "y": 49.91999053955078 |
| } |
| } |
| ---- |
| |
| Agora você precisa adicionar um método ``sendText(json)`` para enviar uma string JSON usando ``websocket.send()`` . |
| |
| |
| |
| . Abra ``websocket.js`` no editor e adicione os seguintes métodos para enviar JSON ao ponto final e para desenhar a imagem quando uma mensagem for recebida do ponto final. |
| |
| [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: Você pode deletar o código adicionado ao ``websocket.js`` para testar o ponto final. |
| |
| |
| |
| . Adicione a seguinte linha (em *negrito*) na parte inferior de ``index.html`` para carregar o ``whiteboard.js`` . |
| |
| [source,html] |
| ---- |
| |
| </table> |
| <script type="text/javascript" src="websocket.js"></script> |
| *<script type="text/javascript" src="whiteboard.js"></script>* |
| <body> |
| |
| ---- |
| |
| |
| |
| === Implementar as Interfaces do Codificador e do Decodificador |
| |
| Neste exercício você cria classes para implementar interfaces do decodificador e do codificador para decodificar mensagens do web socket (JSON) para a classe POJO ``Figura`` e para codificar a ``Figura`` como uma string JSON para enviar ao ponto final. |
| |
| Para obter mais detalhes, consulte a seção sobre tipos de mensagem e codificadores e decodificadores no artito técnico link:http://www.oracle.com/technetwork/articles/java/jsr356-1937161.html[+JSR 356, Java API para WebSocket+]. |
| |
| 1. Clique com o botão direito do mouse no nó do projeto e selecione Novo > Classe Java. |
| 2. Digite *FigureEncoder* como o Nome da Classe e escolha ``org.sample.whiteboardapp`` na lista drop-down Pacote. Clique em Finalizar. |
| 3. No editor de código-fonte, implemente a interface Codificador do WebSocket adicionando o seguinte código (em *negrito*): |
| |
| [source,java] |
| ---- |
| |
| |
| public class FigureEncoder *implements Encoder.Text<Figure>* { |
| |
| } |
| ---- |
| |
| |
| . Adicione uma instrução de importação para ``javax.websocket.Encoder`` e implemente os métodos abstratos. |
| |
| Coloque o cursor na declaração de classe e digite Alt-Enter e selecione *Implementar todos os métodos abstratos* no menu pop-up. |
| |
| |
| |
| . Modifique os métodos abstratos gerados fazendo as seguintes alterações (em *negrito*). Salve as alterações. |
| |
| [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");* |
| } |
| ---- |
| |
| |
| . Clique com o botão direito do mouse no nó do projeto e selecione Novo > Classe Java. |
| |
| |
| . Digite *FigureEncoder* como o Nome da Classe e escolha ``org.sample.whiteboardapp`` na lista drop-down Pacote. Clique em Finalizar. |
| |
| |
| . No editor de código-fonte, implemente a interface Decodificador do WebSocket adicionando o seguinte código (em *negrito*): |
| |
| [source,java] |
| ---- |
| |
| |
| public class FigureDecoder *implements Decoder.Text<Figure>* { |
| |
| } |
| ---- |
| |
| |
| . Adicione uma instrução de importação para ``javax.websocket.Decoder`` e implemente os métodos abstratos. |
| |
| |
| . Faça as seguintes alterações (em *negrito*) para os métodos abstratos gerados. |
| |
| [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");* |
| } |
| ---- |
| |
| |
| . Corrija as importações e salve as alterações. |
| |
| Agora você precisa modificar ``MyWhiteboard.java`` para especificar o codificador e o decodificador. |
| |
| |
| |
| |
| === Executando a Aplicação |
| |
| Agora você está quase pronto para executar a aplicação. Neste exercício você modifica a classe do ponto final do WebSocket para especificar o codificador e o decodificador para a string JSON e adicionar um método para enviar a string JSON aos clientes conectados quando uma mensagem for recebida. |
| |
| 1. Abra ``MyWhiteboard.java`` no editor. |
| 2. Modifique a anotação ``@ServerEndpoint`` para especificar o codificador e o decodificador do ponto final. Observe que você precisa especificar explicitamente o parâmetro ``valor`` para o nome do ponto final. |
| |
| [source,java] |
| ---- |
| |
| @ServerEndpoint(*value=*"/whiteboardendpoint"*, encoders = {FigureEncoder.class}, decoders = {FigureDecoder.class}*) |
| |
| ---- |
| |
| |
| . Delete o método ``onMessage`` que foi gerado por default. |
| |
| |
| . Adicione o seguinte método ``broadcastFigure`` e anote o método com ``@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); |
| } |
| } |
| } |
| ---- |
| |
| |
| . Clique com o botão direito do mouse no editor e selecione Corrigir Importações (Alt-Shift-I; ⌘-Shift-I no Mac). Salve as alterações. |
| |
| |
| . Clique com o botão direito do mouse na janela Projetos e selecione Executar. |
| |
| Quando você clicar em Executar, o IDE abre uma janela do browser para link:http://localhost:8080/WhiteboardApp/[+http://localhost:8080/WhiteboardApp/+]. |
| |
| NOTE: Talvez você precise cancelar a implantação da aplicação anterior do servidor de aplicações ou forçar a recarga da página no browser. |
| |
| Se você exibir as mensagens do browser poderá ver que uma string é enviada por meio de JSON para o ponto final, cada vez que você clicar na tela. |
| |
| image::images/websocket-onebrowser.png[title="Canvas com figuras no browser e JSON exibido na console web"] |
| |
| Se você abrir outro browser para ``http://localhost:8080/WhiteboardApp/`` você verá que cada vez que você clicar na tela em um browser, o novo círculo ou quadrado é reproduzido na tela de outro browser. |
| |
| image::images/websocket-twobrowsers.png[title="Dois browsers enviando JSON por meio do ponto final"] |
| |
| |
| == Enviando Dados Binários para o Ponto Final |
| |
| A aplicação agora pode processar e enviar uma string por meio de JSON para o ponto final e a string é, em seguida, enviada para os clientes conectados. Nesta seção você modificará os arquivos JavaScript para enviar e receber dados binários. |
| |
| Para enviar os dados binários para o ponto final, é necessário definir a propriedade ``binaryType`` do WebSocket para ``arraybuffer`` . Isso garante que quaisquer transferências binárias que usam o WebSocket são feitas usando ``ArrayBuffer`` . A conversão de dados binários é executada pelo método ``defineImageBinary`` em ``whiteboard.js`` . |
| |
| 1. Abra ``websocket.js`` e adicione o seguinte código para definir a propriedade ``binaryType`` de WebSocket para ``arraybuffer`` . |
| |
| [source,javascript] |
| ---- |
| |
| websocket.binaryType = "arraybuffer"; |
| ---- |
| |
| |
| . Adicione o seguinte método para enviar dados binários para o ponto final. |
| |
| [source,javascript] |
| ---- |
| |
| function sendBinary(bytes) { |
| console.log("sending binary: " + Object.prototype.toString.call(bytes)); |
| websocket.send(bytes); |
| } |
| ---- |
| |
| |
| . Modifique o método ``onMessage`` para adicionar o seguinte código (em *negrito*) para selecionar o método para atualizar a tela, de acordo com o tipo de dados na mensagem de entrada. |
| |
| [source,javascript] |
| ---- |
| |
| function onMessage(evt) { |
| console.log("received: " + evt.data); |
| *if (typeof evt.data == "string") {* |
| drawImageText(evt.data); |
| *} else { |
| drawImageBinary(evt.data); |
| }* |
| } |
| ---- |
| |
| O método ``drawImageBinary`` é chamado se uma mensagem com dados binários for recebida. |
| |
| |
| |
| . Abra ``whiteboard.js`` e adicione os seguintes métodos. O método ``drawImageBinary`` é chamado para atualizar a tela após fazer parse dos dados binários de entrada. O método ``defineImageBinary`` é usado para preparar um snapshot da tela como dados binários. |
| |
| [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); |
| } |
| ---- |
| |
| Agora você precisa adicionar uma forma de chamar ``defineImageBinary`` quando quiser gerar dados como o tipo ``ArrayBuffer`` e enviá-los ao ponto final. |
| |
| |
| |
| . Abra ``index.html`` e modifique o elemento ``<table>`` para adicionar a seguinte linha à tabela do form. |
| |
| [source,html] |
| ---- |
| |
| <tr> |
| <th> </th> |
| <td><input type="submit" value="Send Snapshot" onclick="defineImageBinary(); return false;"></td> |
| <td> </td> |
| <td> </td> |
| <td> </td> |
| </tr> |
| |
| ---- |
| |
| A nova linha contém um botão Enviar Snapshot para enviar um snapshot binário da tela para os colegas conectados. O método ``defineImageBinary`` em ``whiteboard.js`` será chamado quando o botão for clicado. |
| |
| |
| |
| . Abra ``MyWhiteboard.java`` e adicione o seguinte método que enviará os dados binários aos colegas quando o ponto final receber uma mensagem com dados binários. |
| |
| [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: Será necessário adicionar uma instrução de importação em ``java.nio.ByteBuffer`` . |
| |
| Você pode modificar a aplicação para permitir que o usuário interrompa o envio de dados ao ponto final. Por default, todos os colegas são conectados assim que abrem a página e os dados são enviados do browser para todos os colegas conectados. Você pode adicionar uma condicional simples, de forma que os dados não sejam enviados ao ponto final, a menos que a opção seja selecionada. Isso não afeta o recebimento de dados. Os dados ainda são recebidos do ponto final. |
| |
| 1. Modifique o método ``defineImage`` em ``whiteboard.js`` para adicionar o seguinte código (em *negrito*). |
| |
| [source,javascript] |
| ---- |
| |
| drawImageText(json); |
| * if (document.getElementById("instant").checked) {* |
| sendText(json); |
| * }* |
| } |
| ---- |
| |
| O código condicional que você verifica se o elemento com o id for ``verificado`` |
| |
| |
| |
| . Abra ``index.html`` e modifique o elemento ``<table>`` para adicionar uma caixa de seleção ao form. |
| |
| [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> |
| |
| ---- |
| |
| Os dados não são enviados quando a caixa de seleção On-line estiver desmarcada, mas o cliente ainda receberá dados do ponto final. |
| |
| Se você adicionar o botão Enviar Snapshot e a caixa de seleção On-line e executar a aplicação novamente, você verá os novos elementos na página do índice. Se você abrir outro browser e desmarcar o botão On-line você poderá ver que a mensagem JSON não é enviada ao ponto final quando você clicar na tela. |
| |
| image::images/websocket-onebrowser-binary.png[title="Console da web no browser exibindo a mensagem que os dados binários foram enviados"] |
| |
| Se você clicar em Enviar Snapshot, os dados binários serão enviados para o ponto final e transmitidos para os clientes conectados. |
| |
| |
| link:/about/contact_form.html?to=3&subject=Feedback:%20Using%20the%20WebSocket%20API%20in%20a%20Web%20Application[+Enviar Feedback neste Tutorial+] |
| |
| |
| |
| == Consulte Também |
| |
| Para obter mais informações sobre o uso do NetBeans IDE para desenvolver aplicações Java EE, consulte os seguintes recursos: |
| |
| * Demonstração: link:maven-websocketapi-screencast.html[+ Usando a API do WebSocket em uma Aplicação Web+] |
| * link:javaee-intro.html[+Introdução à Tecnologia Java EE+] |
| * link:javaee-gettingstarted.html[+Conceitos Básicos sobre Aplicações do Java EE+] |
| * link:../../trails/java-ee.html[+Trilha de Aprendizado do Java EE e Java Web+] |
| |
| Para obter mais informações sobre o uso de Java EE, consulte o link:http://download.oracle.com/javaee/6/tutorial/doc/[+Tutorial do Java EE+]. |
| |
| Para enviar comentários e sugestões, obter suporte e se manter informado sobre os mais recentes desenvolvimentos das funcionalidades de desenvolvimento do Java EE do NetBeans IDE, link:../../../community/lists/top.html[+inscreva-se na lista de correspondência de nbj2ee+]. |
| |