The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Usando WebSockets

Este guia explica como seu aplicativo Quarkus pode utilizar web sockets para criar aplicativos web interativas. Por ser a aplicação canônica de web socket, vamos criar um aplicativo de bate-papo simples.

Pré-requisitos

Para concluir este guia, você precisa:

  • Cerca de 15 minutos

  • Um IDE

  • JDK 11+ instalado com 'JAVA_HOME' configurado adequadamente

  • Apache Maven 3.8.6

  • Opcionalmente, o Quarkus CLI se você quiser usá-lo

  • Opcionalmente, Mandrel ou GraalVM instalado e configurado apropriadamente se você quiser criar um executável nativo (ou Docker se você usar uma compilação de contêiner nativo)

Arquitetura

Neste guia, criamos um aplicativo de bate-papo simples usando soquetes da Web para receber e enviar mensagens a outros usuários conectados.

Architecture

Solução

Recomendamos que você siga as instruções nas próximas seções e crie o aplicativo passo a passo. No entanto, você pode pular diretamente para o exemplo completo.

Clone o repositório Git: git clone https://github.com/quarkusio/quarkus-quickstarts.git, ou baixe um arquivo.

The solution is located in the websockets-quickstart directory.

Criar o projeto Maven

Primeiro, precisamos de um novo projeto. Crie um novo projeto com o seguinte comando:

CLI
quarkus create app org.acme:websockets-quickstart \
    --stream=2.16 \
    --extension='websockets' \
    --no-code
cd websockets-quickstart

Para criar um projeto Gradle, adicione a opção --gradle ou --gradle-kotlin-dsl.

For more information about how to install the Quarkus CLI and use it, please refer to the Quarkus CLI guide.

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:2.16.12.Final:create \
    -DplatformVersion=2.16 \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=websockets-quickstart \
    -Dextensions='websockets' \
    -DnoCode
cd websockets-quickstart

Para criar um projeto Gradle, adicione a opção '-DbuildTool=gradle' ou '-DbuildTool=gradle-kotlin-dsl'.

Esse comando gera o projeto (sem nenhuma classe) e importa a extensão websockets .

Se você já configurou seu projeto Quarkus, pode adicionar a extensão websockets ao seu projeto executando o seguinte comando no diretório base do seu projeto:

CLI
quarkus extension add 'websockets'
Maven
./mvnw quarkus:add-extension -Dextensions='websockets'
Gradle
./gradlew addExtension --extensions='websockets'

Isto irá adicionar o seguinte trecho no seu arquivo de build:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-websockets</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-websockets")
Se você deseja utilizar apenas o cliente WebSocket, você deve incluir quarkus-websockets-client.

Manuseio de web sockets

Nosso aplicativo contém uma única classe que lida com os Web Sockets. Crie a classe org.acme.websockets.ChatSocket no diretório src/main/java . Copie o seguinte conteúdo para o arquivo criado:

package org.acme.websockets;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import javax.enterprise.context.ApplicationScoped;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import javax.websocket.Session;

@ServerEndpoint("/chat/{username}")         (1)
@ApplicationScoped
public class ChatSocket {

    Map<String, Session> sessions = new ConcurrentHashMap<>(); (2)

    @OnOpen
    public void onOpen(Session session, @PathParam("username") String username) {
        sessions.put(username, session);
    }

    @OnClose
    public void onClose(Session session, @PathParam("username") String username) {
        sessions.remove(username);
        broadcast("User " + username + " left");
    }

    @OnError
    public void onError(Session session, @PathParam("username") String username, Throwable throwable) {
        sessions.remove(username);
        broadcast("User " + username + " left on error: " + throwable);
    }

    @OnMessage
    public void onMessage(String message, @PathParam("username") String username) {
        if (message.equalsIgnoreCase("_ready_")) {
            broadcast("User " + username + " joined");
        } else {
            broadcast(">> " + username + ": " + message);
        }
    }

    private void broadcast(String message) {
        sessions.values().forEach(s -> {
            s.getAsyncRemote().sendObject(message, result ->  {
                if (result.getException() != null) {
                    System.out.println("Unable to send message: " + result.getException());
                }
            });
        });
    }

}
1 Configure a URL do Web Socket
2 Armazena os web sockets atualmente abertos

Um frontend da Web sofisticado

All chat applications need a nice UI, well, this one may not be that nice, but does the work. Quarkus automatically serves static resources contained in the META-INF/resources directory. Create the src/main/resources/META-INF/resources directory and copy this index.html file in it.

Executar o aplicativo

Agora, vamos ver nosso aplicativo em ação. Execute-o com:

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

Em seguida, abra as duas janelas do navegador em http://localhost:8080/:

  1. Digite um nome na área de texto superior (use dois nomes diferentes).

  2. Clique em conectar

  3. Enviar e receber mensagens

Application

Como de costume, a aplicação pode ser empacotada utilizando:

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

E executada com java -jar target/quarkus-app/quarkus-run.jar.

Você também pode criar o executável nativo usando:

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.package.type=native

You can also test your web socket applications using the approach detailed here.

Clientes WebSocket

O Quarkus também contém um cliente WebSocket. Você pode chamar ContainerProvider.getWebSocketContainer().connectToServer para criar uma conexão WebSocket. Por padrão, o artefato quarkus-websockets inclui suporte tanto para cliente quanto para servidor. No entanto, se você deseja apenas o cliente, pode incluir quarkus-websockets-client.

When you connect to the server you can either pass in the Class of the annotated client endpoint you want to use, or an instance of javax.websocket.Endpoint. If you are using the annotated endpoint then you can use the exact same annotations as you can on the server, except it must be annotated with @ClientEndpoint instead of @ServerEndpoint.

O exemplo abaixo mostra o client sendo usado para testar o endpoint de bate-papo acima.

package org.acme.websockets;

import java.net.URI;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;

@QuarkusTest
public class ChatTest {

    private static final LinkedBlockingDeque<String> MESSAGES = new LinkedBlockingDeque<>();

    @TestHTTPResource("/chat/stu")
    URI uri;

    @Test
    public void testWebsocketChat() throws Exception {
        try (Session session = ContainerProvider.getWebSocketContainer().connectToServer(Client.class, uri)) {
            Assertions.assertEquals("CONNECT", MESSAGES.poll(10, TimeUnit.SECONDS));
            Assertions.assertEquals("User stu joined", MESSAGES.poll(10, TimeUnit.SECONDS));
            session.getAsyncRemote().sendText("hello world");
            Assertions.assertEquals(">> stu: hello world", MESSAGES.poll(10, TimeUnit.SECONDS));
        }
    }

    @ClientEndpoint
    public static class Client {

        @OnOpen
        public void open(Session session) {
            MESSAGES.add("CONNECT");
            // Send a message to indicate that we are ready,
            // as the message handler may not be registered immediately after this callback.
            session.getAsyncRemote().sendText("_ready_");
        }

        @OnMessage
        void message(String msg) {
            MESSAGES.add(msg);
        }

    }

}

Mais informações sobre o WebSocket

A implementação do Quarkus WebSocket é uma implementação do Jakarta Websockets .