Introdução: Por que WebSocket é o padrão para aplicações real-time em Java
Aplicações web modernas exigem troca instantânea de dados entre cliente e servidor. O protocolo HTTP tradicional, baseado no modelo "requisição-resposta", não é adequado para tarefas onde a latência mínima é importante: chats online, cotações de bolsa, jogos multiplayer ou painéis de monitoramento em tempo real.
O protocolo WebSocket resolve esse problema estabelecendo uma conexão bidirecional permanente entre cliente e servidor. Após o handshake HTTP inicial, a conexão é "atualizada" para WebSocket, e os dados são transmitidos na forma de frames sem cabeçalhos adicionais. Java, graças à sua poderosa biblioteca padrão e frameworks, oferece excelentes ferramentas para trabalhar com WebSocket.
Neste artigo, veremos como criar uma aplicação real-time completa em Java usando Jakarta WebSocket API (anteriormente Java EE WebSocket). Você aprenderá sobre configuração do servidor, processamento de mensagens, gerenciamento de sessões e soluções arquiteturais típicas.
Fundamentos do trabalho com WebSocket em Java: Jakarta WebSocket API
A partir do Java EE 7 (Jakarta EE), foi adicionado à plataforma padrão o JSR 356 — Java API para WebSocket. Isso significa que para criar um servidor WebSocket não é necessário adicionar bibliotecas externas — basta um contêiner de servlet que suporte Jakarta EE (por exemplo, Apache Tomcat 9+, Jetty 10+, WildFly).
Criação de um endpoint WebSocket
O elemento principal é uma classe endpoint anotada com @ServerEndpoint. Dentro dela, definimos métodos que serão chamados na conexão, recebimento de mensagem, erro ou fechamento da conexão.
import jakarta.websocket.*;import jakarta.websocket.server.ServerEndpoint;import java.io.IOException;import java.util.Set;import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/chat")public class ChatEndpoint {
private static final Set<Session> sessions = new CopyOnWriteArraySet<>();
@OnOpen public void onOpen(Session session) { sessions.add(session); broadcast("Usuário conectou. Total: " + sessions.size()); }
@OnMessage public void onMessage(String message, Session session) { broadcast("[" + session.getId() + "]: " + message); }
@OnClose public void onClose(Session session) { sessions.remove(session); broadcast("Usuário desconectou. Restam: " + sessions.size()); }
@OnError public void onError(Session session, Throwable throwable) { System.err.println("Erro na sessão " + session.getId() + ": " + throwable.getMessage()); }
private void broadcast(String message) { for (Session s : sessions) { if (s.isOpen()) { try { s.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } } } }}Neste exemplo:
@ServerEndpoint("/chat")— indica que o endpoint está disponível no caminho relativo/chat.CopyOnWriteArraySet— coleção thread-safe para armazenar sessões ativas.@OnOpen— chamado ao estabelecer a conexão.@OnMessage— chamado ao receber uma mensagem de texto.@OnClose— chamado ao fechar a conexão.@OnError— tratamento de erros.
JavaScript do cliente
Para testar o servidor, basta um arquivo HTML simples com JavaScript:
<!DOCTYPE html><html><head> <title>WebSocket Chat</title></head><body> <div id="messages"></div> <input type="text" i