Inicie o Server-Sent Events (SSE) para enviar e receber dados de um servidor e de clientes com um
serviço de bate-papo.
Antes de Começar
O SSE faz parte do HTML5. Para iniciar o SSE, use um cliente Java™ , como Java API for RESTful Web Services (JAX-RS) 2.1 ou JavaScript.
Sobre esta Tarefa
O SSE foi introduzido pela primeira vez no HTML5. Um cliente, como um navegador, cria uma conexão
HTTP com um servidor e envia uma solicitação inicial. No entanto, em vez de fechar a conexão, o cliente e o
servidor mantêm a conexão aberta e o servidor envia dados para o cliente, conforme necessário. Em seguida, o
cliente processa os dados como eventos. O servidor ou o cliente pode fechar a conexão, porém, se dois clientes
permanecerem conectados, eles poderão ver eventos que o servidor envia.
Procedimento
- Inicie o SSE com o JAX-RS 2.1.
O código do servidor a seguir mostra um recurso que dispara o SSE e envia dados de volta para um cliente
específico. A conexão com o servidor permanece aberta para que o servidor possa enviar informações a qualquer
momento. Este serviço RESTful de exemplo fornece informações de rádio para música. Crie o arquivo
RadioInfoService.java no aplicativo da web.
@GET
@Path("/songDataStream")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void songDataStream(@Context SseEventSink eventSink, @Context Sse sse) {
Runnable r = new Runnable() {
@Override
public void run() {
Song song = RadioService.getCurrentSong();
while (song != null) {
OutboundSseEvent event = sse.newEventBuilder()
.mediaType(MediaType.APPLICATION_JSON_TYPE)
.data(Song.class, song)
.build();
eventSink.send(event);
try {
Thread.currentThread().sleep(song.timeRemaining());
} catch (InterruptedException ex) {
// ...
}
}
}
}
new Thread(r).start();
}
- Criar um cliente JAX-RS em um arquivo .java .
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost/RadioSvc/rest/songDataStream");
try (SseEventSource source = SseEventSource.target(target).build()) {
source.register(new Consumer<InboundSseEvent>(){
@Override
public void accept(InboundSseEvent event) {
// called when we receive a new event
Song song = event.readData(Song.class);
System.out.println("Now playing " + song.title() + " by " + song.artist());
}}, new Consumer<Throwable>(){
@Override
public void accept(Throwable t) {
// called when something went wrong
t.printStackTrace();
}}, new Runnable() {
@Override
public void run() {
// called when our connection is closed
System.out.println("All done for now!");
}});
source.open();
Thread.sleep(3600000); // Consume song events for one hour
} catch (InterruptedException e) {
e.printStackTrace();
}
- Opcional: Se não for possível converter os interceptores JSON de volta em objetos Java, inclua um
MessageBodyReader
e um provedor MessageBodyWriter
.
- Crie uma página da web que chame seu método SSE. O arquivo HTML de exemplo a seguir cria uma
página da web simples que exibe a musica que ele reproduz:
<!DOCTYPE html>
<html>
<head>
<title>SSE Radio - Now Playing</title>
</head>
<body>
<h2>Now Playing:</h2>
<div id="song">Song: </div>
<div id="artist">Artist: </div>
<script>
var source = new EventSource('rest/songDataStream');
source.onmessage = function(e) {
var song = JSON.parse(e.data);
document.getElementById("song").innerHTML = 'Song: ' + song.title;
document.getElementById("artist").innerHTML = 'Artist: ' + song.artist;
};
</script>
</body>
</html>
- Empacote a página HTML com seu aplicativo da web.
- Navegue para o seu aplicativo da web. O aplicativo recebe eventos de música do servidor e atualiza
automaticamente a página da web sem exigir que você atualize.
Se múltiplos clientes chamarem
o método de recurso songDataStream
ou outro método, cada chamada de método criará um
encadeamento separado que envia dados para esse usuário específico. A mensagem enviada cria um evento SSE de
saída e a mensagem é enviada para todos os clientes.
- Para assegurar-se de que todos os clientes vejam os mesmos dados e enviem uma mensagem para todos
os clientes ao mesmo tempo, use o método de transmissão. Ambos os exemplos anteriores do cliente JAX-RS e do JavaScript funcionam com este exemplo de difusão Mude apenas
a URL.
- Como um transmissor, envie mensagens para todos os clientes registrados.
Neste
exemplo, sempre que você chama o método de recurso playSong
, todos os clientes inscritos
recebem o evento com os dados da música selecionada.
- Como um cliente, registre-se para eventos e permaneça conectado.
Nesse exemplo,
múltiplos clientes podem se inscrever na estação de rádio chamando o método de recurso
SSE listen
.
@Context
private Sse sse;
private static SseBroadcaster broadcaster;
private synchronized static SseBroadcaster getBroadcaster(Sse sse) {
if (broadcaster == null) {
broadcaster = sse.newBroadcaster();
}
return broadcaster;
}
@GET
@Path("listen")
@Produces(MediaType.SERVER_SENT_EVENTS)
public void listen(@Context SseEventSink sink, @Context Sse sse) {
SseBroadcaster b = getBroadcaster(this.sse);
b.register(sink);
}
@PUT
@Path("playSong")
public Response playSong(@PathParam("songId") String songId) {
Song song = RadioService.getSong(songId);
SseBroadcaster b = getBroadcaster(this.sse);
OutboundSseEvent event = sse.newEventBuilder()
.mediaType(MediaType.APPLICATION_JSON_TYPE)
.data(Song.class, song)
.build();
b.broadcast(event);
}
Resultados
O aplicativo da web recebe os eventos do servidor e atualiza automaticamente a
página da web.