知識庫 / Spring RSS 訂閱

Spring WebSockets @SendToUser 註解快速示例

Spring
HongKong
4
02:04 PM · Dec 06 ,2025

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協議進行的消息代理,STOMP代表流式文本定向消息協議。需要注意的是,此註解必須與@Configuration註解一起使用。

雖然並非強制要求擴展AbstractWebSocketMessageBrokerConfigurer,但為了快速示例,自定義導入的配置會更方便。

在第一個方法中,我們設置了一個基於內存的消息代理,用於將消息帶回客户端,目的地以“/topic”“/queue”為前綴。

並且,在第二個方法中,我們註冊了stomp端點,位於“/greeting”

如果需要啓用SockJS,則需要修改註冊部分:

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

3. 通過攔截器獲取會話 ID

獲取會話 ID 的一種方法是添加一個 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.RELEASE 版本開始,由於 @SendToUser 標註的改進,無需進行任何自定義,因為該標註允許我們通過 “/user/{sessionId}/…” 而不是 “/user/{user}/…” 將消息發送到用户目標。

這意味着該標註依賴於輸入消息的會話 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();
    }
}

重要的是要指出,<em/>@SendToUser</em/> 表示消息處理方法的返回值應作為 <em/>Message</em/> 對象發送到指定的destination(s)</strong/>,並且在目標位置前會添加 <em/>/user/{username}</em/> 路徑。

5. WebSocket 客户端

WebSocket 客户端是與 WebSocket 服務器建立持久連接並進行通信的應用程序。它允許客户端和服務器之間進行實時雙向通信,無需客户端主動發起請求。

主要功能:

  • 連接建立: 客户端通過指定 WebSocket 服務器的地址和端口,建立持久的 TCP 連接。
  • 消息發送與接收: 客户端可以向服務器發送和接收 WebSocket 消息。
  • 狀態管理: 客户端需要管理連接的狀態,例如連接打開、連接關閉等。
  • 錯誤處理: 客户端需要處理連接中斷、消息錯誤等異常情況。

示例 (JavaScript):

// 建立 WebSocket 連接
const websocket = new WebSocket("ws://localhost:8080");

// 監聽連接事件
websocket.onopen = () => {
  console.log("WebSocket 連接已建立");
};

// 監聽消息事件
websocket.onmessage = (event) => {
  console.log("接收到的消息:", event.data);
};

// 監聽關閉事件
websocket.onclose = (event) => {
  console.log("WebSocket 連接已關閉:", event);
};
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,指向 “/greeting” ,用於 WebSocketConfiguration 的映射。

當我們將客户端訂閲到 “/user/queue/errors” 和 “/user/queue/reply” 時,我們使用上一節中標記的信息。

如你所見,@SendToUser 指向 “queue/errors”,但消息將被髮送到 “/user/queue/errors”。

6. 結論

在本文中,我們探討了如何直接向用户或會話 ID 發送消息,使用 Spring WebSocket 實現。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.