51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

Spring Websockets 的 @SendToUser 注解

1、概览 {#1概览}

本文将带你了解如何在 Spring WebSockets 中使用 @SendToUser 注解向特定 Session 或特定用户发送消息。

有关上述 Spring WebSockets 的介绍,请参阅 上一篇文章

2、WebSocket 配置 {#2websocket-配置}

首先,需要配置 Message Broker 和 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(Streaming Text Oriented Messaging Protocol)的基于 Broker 的消息传递。需要强调的是,这个注解需要与 @Configuration 一起使用。

继承 AbstractWebSocketMessageBrokerConfigurer 并不是必须的,但这可以更容易地自定义导入的配置。

在第一个方法中,建立了一个简单的基于内存的 Message Broker,通过以 /topic/queue 为前缀的目标将消息传回客户端。

第二个方法,注册了 /greeting stomp 端点。

可以考虑启用 SockJS。

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

3、通过 Interceptor 获取 Session ID {#3通过-interceptor-获取-session-id}

获取 Session ID 的一种方法是添加一个 Spring Interceptor,它在握手过程中触发,并从请求数据中获取信息。

此 Interceptor 可直接添加到 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 端点 {#4websocket-端点}

从 Spring 5.0.5.RELEASE 开始,无需进行任何自定义,因为 @SendToUser 注解的改进允许我们通过 /user/{sessionId}/... 而不是 /user/{user}/... 向目标用户发送消息。

这意味着该注解依赖于输入消息的 Session ID,从而有效地将回复发送到会话私有的目标位置:

@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 客户端 {#5websocket-客户端}

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

WebSocketConfiguration 中创建了一个新的 WebSocket,将其映射到 /greeting

当客户端订阅到 /user/queue/errors/user/queue/reply 时,就会使用上一节中提到的信息。

可以看到,@SendToUser 指向的是 queue/errors,但消息将被发送到 /user/queue/errors

6、总结 {#6总结}

本文介绍了如何在 Spring WebSocket 中使用 @SendToUser 注解直接向用户或 Session ID 发送消息。


Ref:https://www.baeldung.com/spring-websockets-sendtouser

赞(4)
未经允许不得转载:工具盒子 » Spring Websockets 的 @SendToUser 注解