知識庫 / Spring RSS 訂閱

Spring WebSockets 入門

Spring
HongKong
3
02:50 PM · Dec 06 ,2025

1. 概述

在本教程中,我們將創建一個簡單的 Web 應用程序,該應用程序使用 Spring Framework 4.0 中引入的 新 WebSocket 功能來實現消息傳遞。

WebSocket 是一種 雙向、全雙工、持久連接,它在 Web 瀏覽器和服務器之間建立。一旦 WebSocket 連接建立,該連接將保持開放,直到客户端或服務器決定關閉該連接。

典型的用例是當應用程序涉及多個用户相互通信,例如在聊天中。 我們將在此示例中構建一個簡單的聊天客户端。

2. Maven 依賴

由於該項目基於 Maven,因此首先需要在 pom.xml 中添加所需的依賴項:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-websocket</artifactId>
    <version>6.0.13</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-messaging</artifactId>
    <version>6.0.13</version>
</dependency>

此外,由於我們將使用 JSON 構建消息體,還需要添加 Jackson 依賴項。

這使得 Spring 能夠將我們的 Java 對象轉換為 JSON 以及反之。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.17.2</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId> 
    <version>2.17.2</version>
</dependency>

查找上述庫的最新版本,請訪問 Maven Central

3. 啓用 WebSocket 在 Spring

首先,我們啓用 WebSocket 功能。要做到這一點,我們需要將配置添加到我們的應用程序中,並使用 @EnableWebSocketMessageBroker 註解標記此類。

正如其名稱所示,它啓用 WebSocket 消息處理,並由消息代理支持。

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

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

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

在這裏我們可以看到,configureMessageBroker 方法用於配置消息代理

首先,我們啓用內存消息代理,以便將消息返回到以“/topic”為前綴的客户端目的地。

我們通過指定“/app”前綴來完成簡單的配置,從而過濾目標到帶有應用程序註解的方法(通過 @MessageMapping)的路由。

registerStompEndpoints 方法註冊了“/chat”端點,從而啓用 Spring 對 STOMP 協議的支持

請注意,我們在這裏添加了一個無需 SockJS 也能工作的端點,以提高彈性。

當此端點以“/app”為前綴時,它映射到 ChatController.send() 方法來處理。

它還啓用 SockJS 備用選項,以便在 WebSockets 不可用時,可以使用替代消息選項。這在 WebSocket 在所有瀏覽器中尚未得到支持,並且可能受到限制的網絡代理影響時非常有用。

這些備用方案允許應用程序在運行時根據需要,優雅地降級到非 WebSocket 替代方案。

4. 創建消息模型

現在我們已經設置了項目並配置了 WebSocket 功能,我們需要創建一個消息進行發送。

該端點將接受包含發送者名稱和文本的 STOMP 消息,其消息主體是一個 JSON 對象。

消息可能如下所示:

{
    "from": "John",
    "text": "Hello!"
}

為了模擬傳輸文本的消息,我們可以創建一個簡單的Java對象,其中包含from和text屬性:

public class Message {

    private String from;
    private String text;

    // getters and setters
}

默認情況下,Spring 將使用 Jackson 庫將我們的模型對象轉換為 JSON 格式,以及從 JSON 格式轉換為模型對象。

5. 創建消息處理控制器

正如我們所見,Spring 處理 STOMP 消息的方式是將控制器方法與配置的端點關聯起來。我們可以通過使用 @MessageMapping 標註來實現這一點。

端點和控制器之間的關聯使我們能夠在需要時處理消息:

@MessageMapping("/chat")
@SendTo("/topic/messages")
public OutputMessage send(Message message) throws Exception {
    String time = new SimpleDateFormat("HH:mm").format(new Date());
    return new OutputMessage(message.getFrom(), message.getText(), time);
}

在我們的示例中,我們將創建一個名為 OutputMessage 的模型對象,用於表示發送到配置的目標地的輸出消息。

我們用來自傳入消息的發送者和消息文本,並加上時間戳填充該對象。

在處理消息後,我們將它發送到定義的適當目標地,該目標地由 @SendTo 註解定義。所有訂閲了 “/topic/messages” 目標地的訂閲者都會收到該消息。

6. 創建瀏覽器客户端

在服務器端完成配置後,我們將使用 sockjs-client 庫,構建一個簡單的 HTML 頁面,以便與我們的消息系統進行交互。

首先,我們需要導入 sockjsstomp JavaScript 客户端庫。

接下來,我們可以創建一個 connect() 函數來與我們的端點建立通信,創建一個 sendMessage() 函數來發送我們的 STOMP 消息,以及一個 disconnect() 函數來關閉通信。

<html>
    <head>
        <title>Chat WebSocket</title>
        <script src="resources/js/sockjs-0.3.4.js"></script>
        <script src="resources/js/stomp.js"></script>
        <script type="text/javascript">
            var stompClient = null;
            
            function setConnected(connected) {
                document.getElementById('connect').disabled = connected;
                document.getElementById('disconnect').disabled = !connected;
                document.getElementById('conversationDiv').style.visibility 
                  = connected ? 'visible' : 'hidden';
                document.getElementById('response').innerHTML = '';
            }
            
            function connect() {
                var socket = new SockJS('/chat');
                stompClient = Stomp.over(socket);  
                stompClient.connect({}, function(frame) {
                    setConnected(true);
                    console.log('Connected: ' + frame);
                    stompClient.subscribe('/topic/messages', function(messageOutput) {
                        showMessageOutput(JSON.parse(messageOutput.body));
                    });
                });
            }
            
            function disconnect() {
                if(stompClient != null) {
                    stompClient.disconnect();
                }
                setConnected(false);
                console.log("Disconnected");
            }
            
            function sendMessage() {
                var from = document.getElementById('from').value;
                var text = document.getElementById('text').value;
                stompClient.send("/app/chat", {}, 
                  JSON.stringify({'from':from, 'text':text}));
            }
            
            function showMessageOutput(messageOutput) {
                var response = document.getElementById('response');
                var p = document.createElement('p');
                p.style.wordWrap = 'break-word';
                p.appendChild(document.createTextNode(messageOutput.from + ": " 
                  + messageOutput.text + " (" + messageOutput.time + ")"));
                response.appendChild(p);
            }
        </script>
    </head>
    <body onload="disconnect()">
        <div>
            <div>
                <input type="text" id="from" placeholder="Choose a nickname"/>
            </div>
            <br />
            <div>
                <button id="connect" onclick="connect();">Connect</button>
                <button id="disconnect" disabled="disabled" onclick="disconnect();">
                    Disconnect
                </button>
            </div>
            <br />
            <div id="conversationDiv">
                <input type="text" id="text" placeholder="Write a message..."/>
                <button id="sendMessage" onclick="sendMessage();">Send</button>
                <p id="response"></p>
            </div>
        </div>

    </body>
</html>

7. 測試示例

為了測試我們的示例,我們可以打開幾個瀏覽器窗口並訪問聊天頁面:

http://localhost:8080

完成這些步驟後,可以通過輸入暱稱並點擊“連接”按鈕加入聊天室。如果發送併發送一條消息,可以在所有已加入聊天室的瀏覽器會話中看到它。

請查看以下截圖:

8. 結論

本文介紹了 Spring 的 WebSocket 支持。我們已經瞭解了其服務器端配置,並使用 sockjsstomp JavaScript 庫構建了一個簡單的客户端對應程序。

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

發佈 評論

Some HTML is okay.