Рубрики
Без рубрики

Краткий пример аннотации @SendToUser Spring Websockets

Краткое и практическое руководство по аннотации @SendToUser Spring 5.

Автор оригинала: baeldung.

1. Обзор

В этом кратком руководстве мы проиллюстрируем, как отправить сообщение конкретному сеансу или конкретному пользователю с помощью Spring WebSockets .

Для ознакомления с вышеуказанным модулем, пожалуйста, обратитесь к этой статье .

2. Конфигурация WebSocket

Прежде всего, нам нужно настроить наш брокер сообщений и конечную точку приложения WebSocket :

@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");
    }	
}

С помощью @EnableWebSocketMessageBroker мы включили поддерживаемый брокером обмен сообщениями через WebSocket с использованием STOMP , который расшифровывается как Протокол потоковой передачи текстовых сообщений. Важно отметить, что эта аннотация должна использоваться в сочетании с @Configuration .

Не обязательно расширять AbstractWebSocketMessageBrokerConfigurer , но для быстрого примера проще настроить импортированную конфигурацию.

В первом методе мы настроили простой брокер сообщений на основе памяти для передачи сообщений обратно клиенту в пункты назначения с префиксами “/тема” и “/очередь” .

И, во-вторых, мы зарегистрировали конечные точки stomp в “/приветствие” .

В случае, если мы хотим включить SockJS, мы должны внести изменения в часть реестра:

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

3. Получить идентификатор сеанса с помощью перехватчика

Одним из способов получить идентификатор сеанса является добавление перехватчика Spring, который будет срабатывать во время рукопожатия и получать информацию из данных запроса.

Этот перехватчик можно добавить непосредственно в WebSocketConfig:

@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. Конечная точка WebSocket

Начиная с ВЫПУСКА Spring 5.0.5., нет необходимости делать какие-либо настройки из-за улучшения аннотации @SendToUser , которая позволяет нам отправлять сообщение пользователю через ” /user/{SessionID}/… “, а не ” /user/{user}/… “.

Это означает, что аннотация работает, полагаясь на идентификатор сеанса входного сообщения, эффективно отправляя ответ в адрес назначения, закрытый для сеанса:

@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();
    }
}

Важно отметить, что @SendToUser указывает, что возвращаемое значение метода обработки сообщений должно быть отправлено в виде Сообщения в указанный пункт назначения(ы) с добавлением “ /user/{username} .

5. Клиент 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");
}

Создается новый WebSocket , указывающий на ” /приветствие ” для отображения в конфигурации WebSocket .

Когда мы подписываем клиента на ” /пользователь/очередь/ошибки ” и ” /пользователь/очередь/ответ “, мы используем отмеченную информацию из последнего раздела.

Как мы видим, @SendToUser указывает на ” очередь/ошибки “, но сообщение будет отправлено на ” /пользователь/очередь/ошибки “.

6. Заключение

В этой статье мы рассмотрели способ отправки сообщения непосредственно пользователю или идентификатору сеанса с помощью Spring WebSocket

Как всегда, полный исходный код примеров доступен на GitHub .