Um exemplo rápido da anotação @SendToUser do Spring Websockets '

Um exemplo rápido da anotação @SendToUser do Spring Websockets '

1. Visão geral

Neste tutorial rápido, vamos ilustrarhow to send a message to a specific session or particular user using Spring WebSockets.

Para obter uma introdução ao módulo acima, consulteto this article.

2. Configuração WebSocket

Primeiro de tudo, precisamosconfigure our message broker and WebSocket application endpoint:

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig
  extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/topic/", "/queue/");
    config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
    registry.addEndpoint("/greeting");
    }
}

Com@EnableWebSocketMessageBroker, nósenabled a broker-backed messaging over WebSocket using*STOMP*, que representaStreaming Text Oriented Messaging Protocol. It’s important to remark that this annotation needs to be used in conjunction with the @Configuration

Não é obrigatório estender oAbstractWebSocketMessageBrokerConfigurer, mas, para um exemplo rápido, é mais fácil personalizar a configuração importada.

No primeiro método, configuramos um agente de mensagens simples baseado em memória para transportar as mensagens de volta para o cliente em destinos prefixados com“/topic”e“/queue”.

E, no segundo, registramos endpoints de stomp em“/greeting”.

Caso desejemos ativar o SockJS, precisamos alterar a parte do registro:

registry.addEndpoint("/greeting").withSockJS();

3. Obter ID da sessão pelo interceptador

Uma maneirato obtain the session id é adicionar um Spring Interceptor que será acionado durante o handshake e obterá as informações dos dados do pedido.

Este interceptor pode ser adicionado diretamente emWebSocketConfig:

@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {

registry
  .addEndpoint("/greeting")
  .setHandshakeHandler(new DefaultHandshakeHandler() {

      public boolean beforeHandshake(
        ServerHttpRequest request,
        ServerHttpResponse response,
        WebSocketHandler wsHandler,
        Map attributes) throws Exception {

            if (request instanceof ServletServerHttpRequest) {
                ServletServerHttpRequest servletRequest
                 = (ServletServerHttpRequest) request;
                HttpSession session = servletRequest
                  .getServletRequest().getSession();
                attributes.put("sessionId", session.getId());
            }
                return true;
        }}).withSockJS();
    }

4. Ponto final WebSocket

A partir do Spring 5.0.5.RELEASE, não é necessário fazer nenhuma customização por causa da melhoria de@SendToUser annotation, that allows us to send a message to a user destination via “/user/{sessionId}/…” ao invés de “/user/{user}/…“.

Isso significa que a anotação funciona com base no ID da sessão da mensagem de entrada, enviando efetivamente uma resposta ao destino privado para a sessão:

@Controller
public class WebSocketController {

    @Autowired
    private SimpMessageSendingOperations messagingTemplate;

    private Gson gson = new Gson();

    @MessageMapping("/message")
    @SendToUser("/queue/reply")
    public String processMessageFromClient(
      @Payload String message,
      Principal principal) throws Exception {
    return gson
          .fromJson(message, Map.class)
          .get("name").toString();
    }

    @MessageExceptionHandler
    @SendToUser("/queue/errors")
    public String handleException(Throwable exception) {
        return exception.getMessage();
    }
}

É importante observar que@SendToUser indica que o valor de retorno de um método de tratamento de mensagem deve ser enviado comoMessage para odestination(s) prepended with “/user/{username} especificado.

5. Cliente WebSocket

function connect() {
    var socket = new WebSocket('ws://localhost:8080/greeting');
    ws = Stomp.over(socket);

    ws.connect({}, function(frame) {
        ws.subscribe("/user/queue/errors", function(message) {
            alert("Error " + message.body);
        });

        ws.subscribe("/user/queue/reply", function(message) {
            alert("Message " + message.body);
        });
    }, function(error) {
        alert("STOMP error " + error);
    });
}

function disconnect() {
    if (ws != null) {
        ws.close();
    }
    setConnected(false);
    console.log("Disconnected");
}

Um novoWebSocket é criado apontando para “/greeting” para o mapeamento emWebSocketConfiguration.

Quando inscrevemos o cliente em “/user/queue/errors” e “/user/queue/reply” é onde usamos as informações comentadas da última seção.

Como podemos ver,@SendToUser aponta para “queue/errors” mas a mensagem será enviada para “/user/queue/errors“.

6. Conclusão

Neste artigo, exploramos uma maneira de enviar uma mensagem diretamente para um usuário ou id de sessão com Spring WebSocket

Como sempre, o código-fonte completo dos exemplos está disponívelover on GitHub.