知識庫 / Spring RSS 訂閱

Spring WebSockets:向特定用户發送消息

Spring
HongKong
3
01:41 PM · Dec 06 ,2025

1. 簡介

本教程將介紹如何使用 Spring WebSockets 向單個用户發送 STOMP 消息。這很重要,因為我們有時不想將每個消息廣播給所有用户。此外,我們還將演示以安全的方式發送這些消息。

對於 WebSockets 的介紹,請查看本優秀的教程,幫助您快速上手。為了更深入地瞭解安全方面,請查看本文,以安全地實現您的 WebSockets 應用程序。

2. 隊列、主題和端點

使用 Spring WebSockets 和 STOMP 有三種主要方式來指定消息發送位置以及訂閲方式:

  1. 主題 (Topics) – 開放給任何客户端或用户的常見對話或聊天主題
  2. 隊列 (Queues) – 僅供特定用户及其當前會話使用
  3. 端點 (Endpoints) – 通用端點

下面我們快速看一下每個端點的上下文路徑示例:

  • “/topic/movies”
  • “/user/queue/specific-user”
  • “/secured/chat”

需要注意的是,.

3. 配置

現在,讓我們學習如何配置我們的應用程序,以便將消息發送到特定用户:

public class SocketBrokerConfig extends 
  WebSocketMessageBrokerConfigurer {

    @Override
    public void configureMessageBroker(MessageBrokerRegistry config) {
        config.enableSimpleBroker("/secured/history","/secured/user/queue/specific-user");
        config.setApplicationDestinationPrefixes("/spring-security-mvc-socket");
        config.setUserDestinationPrefix("/secured/user");
    }

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

請務必包含用户目的地,因為這決定了哪些端點被保留給單個用户。

我們還將所有隊列和用户目的地前綴為“/secured”,以確保它們需要身份驗證。對於未受保護的端點,我們可以刪除“/secured”前綴(這是由於我們其他安全設置造成的)。

pom.xml的角度來看,不需要添加任何額外的依賴項。

4. URL 映射

我們希望客户使用符合以下模式的 URL 映射來訂閲隊列:

"/user/queue/updates"

此映射將由 UserDestinationMessageHandler 自動轉換為用户會話特定的地址。

例如,如果用户名為 “user123”,則對應的地址將是:

"/queue/updates-user123"

服務端,我們將使用以下 URL 映射模式發送針對用户特定響應:

"/user/{username}/queue/updates"

這也會被轉換成我們已訂閲的正確 URL 映射,用於客户端。

因此,我們看到這裏 關鍵要素是雙重性質:

  1. 添加我們指定的 User Destination 前綴(配置在 AbstractWebSocketMessageBrokerConfigurer 中)。
  2. 在映射中,使用 “/queue”

在下一部分,我們將詳細説明如何執行此操作。

5. 調用

我們可以非靜態地從 中調用

@Autowired
private SimpMessagingTemplate simpMessagingTemplate;

@MessageMapping("/secured/room") 
public void sendSpecific(
  @Payload Message msg, 
  Principal user, 
  @Header("simpSessionId") String sessionId) throws Exception { 
    OutputMessage out = new OutputMessage(
      msg.getFrom(), 
      msg.getText(),
      new SimpleDateFormat("HH:mm").format(new Date())); 
    simpMessagingTemplate.convertAndSendToUser(
      msg.getTo(), "/secured/user/queue/specific-user", out); 
}

你可能已經注意到:

@Header("simpSessionId") String sessionId

頭 @Header 註解允許訪問 inbound 消息中暴露的頭信息。例如,我們可以無需複雜的攔截器即可獲取當前的 sessionId。 同樣,我們可以通過 Principal 訪問當前用户。

重要的是,本文采用的方法在 @sendToUser 註解上提供了更大的 URL 映射定製化程度。 欲瞭解更多關於該註解的信息,請查看這篇優秀的文章。

客户端,我們將使用 JavaScript 中的 connect()var socket = new SockJS('/secured/room'); var stompClient = Stomp.over(socket); var sessionId = ""; stompClient.connect({}, function (frame) { var url = stompClient.ws._transport.url; url = url.replace( "ws://localhost:8080/spring-security-mvc-socket/secured/room/", ""); url = url.replace("/websocket", ""); url = url.replace(/^[0-9]+\//, ""); console.log("Your current session is: " + url); sessionId = url; }

我們還訪問提供的 sessionId,並將它附加到“secured/room”URL映射中。 這使我們能夠動態地和手動地提供用户特定的訂閲隊列:

stompClient.subscribe('secured/user/queue/specific-user' 
  + '-user' + that.sessionId, function (msgOut) {
     //handle messages
}

一切設置完成後,我們應該看到:

 

以及在服務器控制枱中:

6. 結論

請查看官方 Spring 博客 以及 官方文檔,以獲取更多有關此主題的信息。

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

發佈 評論

Some HTML is okay.