利用SpringBoot與WebSocket實(shí)現(xiàn)實(shí)時雙向通信功能
演示環(huán)境說明:
- 開發(fā)工具:IDEA 2021.3
- JDK版本: JDK 1.8
- Spring Boot版本:2.3.1 RELEASE
- Maven版本:3.8.2
- 操作系統(tǒng):Windows 11
前言
隨著互聯(lián)網(wǎng)技術(shù)的飛速發(fā)展,實(shí)時通信技術(shù)已經(jīng)逐漸成為現(xiàn)代Web應(yīng)用的核心需求。無論是在即時消息系統(tǒng)、在線游戲、金融交易平臺,還是物聯(lián)網(wǎng)(IoT)應(yīng)用中,WebSocket都提供了一種高效、持久的雙向通信方式。特別是在需要低延遲的場景下,WebSocket的優(yōu)勢尤為突出。本文將深入解析如何利用Spring Boot實(shí)現(xiàn)WebSocket通信,進(jìn)而結(jié)合STOMP協(xié)議,構(gòu)建一個功能強(qiáng)大的實(shí)時聊天室應(yīng)用。
WebSocket協(xié)議簡介
WebSocket協(xié)議自HTML5引入以來,成為了現(xiàn)代Web應(yīng)用的重要組成部分。它打破了傳統(tǒng)HTTP協(xié)議只能在請求和響應(yīng)的周期內(nèi)進(jìn)行單向通信的限制,實(shí)現(xiàn)了雙向通信,并保持持久連接。
WebSocket協(xié)議的優(yōu)勢
- 低延遲:WebSocket連接是持久性的連接,避免了頻繁的握手過程。消息從客戶端到服務(wù)器,再到客戶端的延遲極低,非常適合即時通訊和實(shí)時推送場景。
- 節(jié)省帶寬:相比HTTP的請求-響應(yīng)模式,WebSocket連接不需要每次傳輸都重新建立連接,節(jié)省了很多帶寬和計算資源。
- 全雙工通信:客戶端和服務(wù)器都可以隨時發(fā)送數(shù)據(jù),不需要等待對方回應(yīng)。這使得實(shí)時互動應(yīng)用變得更加靈活和高效。
WebSocket的應(yīng)用場景
- 實(shí)時聊天:例如即時通訊、客服系統(tǒng),WebSocket允許即時傳遞消息。
- 實(shí)時數(shù)據(jù)推送:例如股市行情、體育比賽實(shí)時得分等,WebSocket使得數(shù)據(jù)可以實(shí)時推送到客戶端。
- 在線游戲:WebSocket能夠?qū)崿F(xiàn)游戲玩家之間的即時互動和實(shí)時數(shù)據(jù)同步。
- 物聯(lián)網(wǎng)(IoT):WebSocket能夠幫助傳感器和設(shè)備實(shí)時通信,提供更及時的數(shù)據(jù)反饋。
Spring Boot中實(shí)現(xiàn)WebSocket
Spring Boot 是一個開箱即用的框架,集成了多種常用功能,幫助開發(fā)者快速實(shí)現(xiàn)應(yīng)用的功能。Spring Boot 對 WebSocket 的支持非常全面,允許我們輕松地配置 WebSocket 服務(wù)。
1. 配置 WebSocket 端點(diǎn)
在 Spring Boot 中配置 WebSocket 服務(wù)非常簡單,我們需要做以下幾步:
- 創(chuàng)建一個 WebSocket 配置類,并使用
@EnableWebSocket注解啟用 WebSocket 功能。 - 在配置類中注冊 WebSocket 端點(diǎn),配置客戶端連接路徑。
package com.example.websocket.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// 注冊WebSocketHandler,"/chat"是客戶端連接WebSocket時訪問的路徑
registry.addHandler(new WebSocketHandlerImpl(), "/chat")
.setAllowedOrigins("*"); // 允許跨域請求
}
}
2. 創(chuàng)建 WebSocket 處理類
WebSocket 處理類負(fù)責(zé)接收客戶端發(fā)送的消息并做出響應(yīng)。我們通過繼承 TextWebSocketHandler 類來實(shí)現(xiàn)消息的處理:
package com.example.websocket.handler;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.handler.TextWebSocketHandler;
public class WebSocketHandlerImpl extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
try {
// 處理客戶端發(fā)送的消息,并向客戶端發(fā)送回應(yīng)消息
System.out.println("Received message: " + message.getPayload());
session.sendMessage(new TextMessage("Echo: " + message.getPayload()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("WebSocket connection established");
}
@Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
System.out.println("WebSocket connection closed");
}
}
3. 客戶端的 WebSocket 連接
在前端頁面,我們使用原生 JavaScript 創(chuàng)建 WebSocket 連接??蛻舳送ㄟ^ new WebSocket() 方法與服務(wù)器建立連接:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket Chat</title>
</head>
<body>
<h1>WebSocket Chat</h1>
<div>
<input type="text" id="messageInput" placeholder="Enter a message">
<button onclick="sendMessage()">Send</button>
</div>
<div id="messages"></div>
<script>
const socket = new WebSocket("ws://localhost:8080/chat");
// 接收服務(wù)器發(fā)送的消息
socket.onmessage = function(event) {
const message = event.data;
const messagesDiv = document.getElementById("messages");
const newMessage = document.createElement("p");
newMessage.textContent = message;
messagesDiv.appendChild(newMessage);
};
// 向服務(wù)器發(fā)送消息
function sendMessage() {
const messageInput = document.getElementById("messageInput");
const message = messageInput.value;
socket.send(message);
messageInput.value = ''; // 清空輸入框
}
</script>
</body>
</html>
在這個例子中,我們創(chuàng)建了一個簡單的聊天室應(yīng)用,前端通過 WebSocket 與后端建立了連接,客戶端輸入消息并通過 WebSocket 發(fā)送給服務(wù)器,服務(wù)器將其原樣返回。
WebSocket 與 STOMP 協(xié)議集成
雖然 WebSocket 本身支持雙向通信,但它的消息處理方式較為基礎(chǔ),適合一些簡單的場景。然而,STOMP 協(xié)議為 WebSocket 提供了更加高級的消息處理機(jī)制,能夠?qū)崿F(xiàn)消息的廣播、訂閱、隊(duì)列處理等。
1. 引入 STOMP 依賴
首先,我們需要在 pom.xml 中引入 spring-boot-starter-websocket 和 spring-messaging 依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.messaging</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
2. WebSocket 配置與 STOMP 協(xié)議啟用
通過 @EnableWebSocketMessageBroker 注解啟用 STOMP 協(xié)議,配置消息代理和 STOMP 端點(diǎn)。
package com.example.websocket.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
// 注冊STOMP端點(diǎn),客戶端將通過這個端點(diǎn)連接WebSocket
registry.addEndpoint("/gs-guide-websocket").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
// 配置消息代理
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
}
解釋:
registerStompEndpoints方法注冊 STOMP 端點(diǎn),客戶端將通過該端點(diǎn)連接到 WebSocket 服務(wù)。configureMessageBroker方法啟用消息代理,/app是應(yīng)用消息的前綴,/topic是消息廣播的主題。
3. WebSocket 控制器
使用 STOMP 協(xié)議時,我們可以通過 @MessageMapping 注解來接收客戶端的消息,使用 @SendTo 注解廣播消息:
package com.example.websocket.controller;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
@Controller
public class ChatController {
@MessageMapping("/chat.sendMessage")
@SendTo("/topic/public")
public String sendMessage(String message) throws Exception {
return message;
}
}
解釋:
@MessageMapping("/chat.sendMessage")表示當(dāng)客戶端發(fā)送消息到/app/chat.sendMessage時,方法將被觸發(fā)。@SendTo("/topic/public")表示將結(jié)果發(fā)送到/topic/public主題,并廣播給所有訂閱該主題的客戶端。
4. 前端頁面集成 STOMP 協(xié)議
客戶端通過 SockJS 和 Stomp.js 庫與服務(wù)器建立 WebSocket 連接,并進(jìn)行消息交換:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>STOMP WebSocket Chat</title>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client/dist/sockjs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/stompjs"></script>
</head>
<body>
<h1>STOMP WebSocket Chat</h1>
<div>
<input type="text" id="messageInput" placeholder="Enter a message">
<button onclick="sendMessage()">Send</button>
</div>
<div id="messages"></div>
<script>
const socket = new SockJS("/gs-guide-websocket");
const stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
console.log('Connected: ' + frame);
stompClient.subscribe('/topic/public', function (messageOutput) {
const message = messageOutput.body;
const messagesDiv = document.getElementById("messages");
const newMessage = document.createElement("p");
newMessage.textContent = message;
messagesDiv.appendChild(newMessage);
});
});
function sendMessage() {
const messageInput = document.getElementById("messageInput");
const message = messageInput.value;
stompClient.send("/app/chat.sendMessage", {}, message);
messageInput.value = '';
}
</script>
</body>
</html>
解釋:
SockJS提供 WebSocket 降級支持,確??蛻舳嗽?WebSocket 不可用時也能連接。stompClient.send("/app/chat.sendMessage", {}, message)發(fā)送消息到服務(wù)器,服務(wù)器將消息廣播到所有訂閱的客戶端。
小結(jié)
- WebSocket 是一種持久連接協(xié)議,提供了低延遲的雙向通信,適用于實(shí)時數(shù)據(jù)傳輸場景。
- STOMP 協(xié)議 使 WebSocket 消息的處理更加高效,支持發(fā)布/訂閱模型,適合于構(gòu)建復(fù)雜的實(shí)時應(yīng)用。
- 使用 Spring Boot,我們能夠輕松配置 WebSocket 和 STOMP,快速實(shí)現(xiàn)實(shí)時通信功能。
總結(jié)
通過本文的學(xué)習(xí),我們了解了如何在 Spring Boot 中實(shí)現(xiàn) WebSocket 雙向通信,并結(jié)合 STOMP 協(xié)議構(gòu)建一個簡單的實(shí)時聊天應(yīng)用。WebSocket 提供了高效的實(shí)時通信機(jī)制,而 STOMP 協(xié)議則為 WebSocket 提供了更加靈活的消息推送方式,能夠滿足復(fù)雜應(yīng)用場景的需求。
實(shí)時通信是現(xiàn)代Web應(yīng)用的重要組成部分,WebSocket 和 STOMP 協(xié)議為我們提供了低延遲、可靠的解決方案。通過結(jié)合 Spring Boot 的 WebSocket 支持,開發(fā)者可以非常方便地構(gòu)建實(shí)時通信應(yīng)用。掌握這些技術(shù),可以為你在開發(fā)即時消息系統(tǒng)、在線游戲、物聯(lián)網(wǎng)等應(yīng)用中提供強(qiáng)有力的支持。
希望本文的深入解析能幫助你更好地理解 WebSocket 和 STOMP 協(xié)議的原理,并能夠在實(shí)際項(xiàng)目中應(yīng)用這些技術(shù)!
以上就是利用SpringBoot與WebSocket實(shí)現(xiàn)實(shí)時雙向通信功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot WebSocket雙向通信的資料請關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot分布式WebSocket的實(shí)現(xiàn)指南
- SpringBoot實(shí)現(xiàn)WebSocket通信過程解讀
- 深入淺出SpringBoot WebSocket構(gòu)建實(shí)時應(yīng)用全面指南
- Springboot整合WebSocket 實(shí)現(xiàn)聊天室功能
- vue+springboot+webtrc+websocket實(shí)現(xiàn)雙人音視頻通話會議(最新推薦)
- Springboot使用Websocket的時候調(diào)取IOC管理的Bean報空指針異常問題
- Java?springBoot初步使用websocket的代碼示例
- SpringBoot3整合WebSocket詳細(xì)指南
- SpringBoot實(shí)現(xiàn)WebSocket的示例代碼
- Spring Boot集成WebSocket項(xiàng)目實(shí)戰(zhàn)的示例代碼
相關(guān)文章
SpringCloud+SpringBoot項(xiàng)目搭建結(jié)構(gòu)層次的實(shí)例
這篇文章詳細(xì)介紹了SpringCloud項(xiàng)目的架構(gòu)層次及其搭建經(jīng)驗(yàn),包括Controller層、Service層、Repository層、Entity層、DTO層、Exception層等,通過文字和圖片的形式,幫助讀者理解如何組織和實(shí)現(xiàn)一個SpringBoot項(xiàng)目的不同層次2025-01-01
spring-boot-klock-starter V1.1 主體功能重大更新內(nèi)容介紹
這篇文章主要介紹了spring-boot-klock-starter V1.1 主體功能重大更新內(nèi)容描述,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2018-01-01
Spring框架中Bean的三種配置和實(shí)例化方法總結(jié)
在Spring框架中,Bean的配置和實(shí)例化是很重要的基礎(chǔ)內(nèi)容,掌握各種配置方式,才能靈活管理Bean對象,本文將全面介紹Bean的別名配置、作用范圍配置,以及構(gòu)造器實(shí)例化、工廠實(shí)例化等方式2023-10-10
Java靜態(tài)和非靜態(tài)成員變量初始化過程解析
這篇文章主要介紹了Java靜態(tài)和非靜態(tài)成員變量初始化過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-01-01
解讀System.getProperty("ENM_HOME")中的值從哪獲取的
這篇文章主要介紹了解讀System.getProperty("ENM_HOME")中的值從哪獲取的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12
Java和C語言分別實(shí)現(xiàn)水仙花數(shù)及拓展代碼
這篇文章主要介紹了分別用Java和C語言實(shí)現(xiàn)水仙花數(shù),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11

