SpringBoot實現WebSocket的示例代碼
更新時間:2024年11月19日 09:59:31 作者:絡7
這篇文章主要為大家詳細介紹了SpringBoot實現WebSocket的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
一、環(huán)境搭建
1.創(chuàng)建SpringBoot項目,引入相關依賴
<dependencies>
<!-- Spring Boot核心啟動器,引入常用依賴基礎 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- Spring Boot對Thymeleaf模板引擎支持,用于視圖渲染 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- nekohtml庫,用于HTML解析,指定版本1.9.22 -->
<dependency>
<groupId>net.sourceforge.nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<version>1.9.22</version>
</dependency>
<!-- JUnit 4測試框架依賴,僅測試階段用,版本4.13.2 -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- JUnit Jupiter(JUnit 5部分),用于測試,僅測試環(huán)境 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<!-- Spring Boot Web開發(fā)啟動器,構建Web應用相關 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Boot測試相關依賴,確保應用正確性等 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<!-- Spring Boot對WebSocket啟動器,實現雙向通信功能 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
</dependencies>
2.在resources下邊創(chuàng)建static和templates文件夾
3.配置application.yml
spring:
thymeleaf:
cache: false # 關閉Thymeleaf頁面緩存,開發(fā)時便于即時看到模板修改效果
encoding: UTF-8 # 模板編碼設為UTF-8,確保字符正確解析,避免亂碼
prefix: classpath:/templates/ # 頁面映射路徑:模板文件查找路徑前綴,在類路徑下的templates目錄找
suffix:.html # 視圖對應的模板文件后綴名
mode: HTML5 # 設置模板模式為HTML5,遵循HTML5規(guī)范解析處理
mvc:
pathmatch:
matching-strategy: ant_path_matcher # Spring MVC路徑匹配采用ant_path_matcher策略,更靈活處理URL路徑
static-path-pattern: /static/** # 定義靜態(tài)資源訪問路徑模式,通過/static/開頭的URL可訪問static目錄下靜態(tài)資源
二、配置類開啟WebSocket支持
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @ Description: 開啟WebSocket支持
* 用于在Spring框架的應用中配置和啟用WebSocket功能。
* 通過相關注解和方法的定義,使得應用能夠正確地處理WebSocket連接和通信。
*/
@Configuration
public class WebSocketConfig {
@Bean //用于將方法返回的ServerEndpointExporter對象作為一個Bean注冊到Spring的容器中
public ServerEndpointExporter serverEndpointExporter() {
//創(chuàng)建并返回一個ServerEndpointExporter對象。
// ServerEndpointExporter主要作用是掃描帶有@ServerEndpoint注解的WebSocket端點類,并將它們注冊到Servlet容器中,
// 從而使得應用能夠正確地處理WebSocket連接請求,實現WebSocket的通信功能。
return new ServerEndpointExporter();
}
}
三、服務層
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* @ServerEndpoint 注解是一個類層次的注解,它的功能主要是將目前的類定義成一個 websocket 服務器端。
* 注解的值將被用于監(jiān)聽用戶連接的終端訪問 URL 地址,客戶端可以通過這個 URL 來連接到 WebSocket 服務器端
*/
@Component
@Service
/**@ServerEndpoint注解用于將當前類定義為一個WebSocket服務器端端點。注解中的值"/api/websocket/{sid}"指定了客戶端連接到這個WebSocket服務器端的URL地址,
其中{sid}是一個路徑參數,可以在后續(xù)的方法中獲取并使用,不同的客戶端可以通過帶有不同sid值的這個URL來建立與服務器的WebSocket連接。
*/
@ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {
private Session session; //用戶信息
//存放每個客戶端對應的MyWebSocket對象,保存所有已連接的客戶端對應的WebSocketServer實例
private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
//當前在線連接數,用于記錄當前有多少個客戶端與WebSocket服務器建立了連接
private static int onlineCount = 0;
//用于接收從客戶端連接URL路徑參數中獲取的sid值,這個sid可以用于標識不同的客戶端連接或者與客戶端相關的業(yè)務邏輯處理
private String sid = "";
/**
* 連接建立成功調用的方法
* 這個方法會處理與新連接建立相關的初始化操作,
* 比如記錄客戶端的會話信息、將當前對象添加到已連接客戶端集合中、更新在線連接數等。
*/
@OnOpen
public void onOpen(Session session, @PathParam("sid") String sid) {
this.session = session;
webSocketSet.add(this); //加入set中,將當前新建立連接的WebSocketServer對象添加到存放所有客戶端的集合中
this.sid = sid;
addOnlineCount(); //在線數加1,調用方法增加當前的在線連接數統(tǒng)計值
try {
sendMessage("conn_success"); // 向當前新連接的客戶端發(fā)送一條消息"conn_success",告知客戶端連接成功。
// 在控制臺打印出有新窗口開始監(jiān)聽的sid以及當前的在線人數信息。
System.out.println("有新窗口開始監(jiān)聽:" + sid + ",當前在線人數為:" + getOnlineCount());
} catch (IOException e) {
// 如果發(fā)送消息過程中出現IO異常,在控制臺打印出相應提示信息
System.out.println("websocket IO Exception");
}
}
/**
* 連接關閉調用的方法
*/
// @OnClose注解標記的方法會在WebSocket連接關閉時被自動調用。這個方法主要處理與連接關閉相關的清理操作,
// 比如從已連接客戶端集合中刪除對應的對象、更新在線連接數等。
@OnClose
public void onClose() {
webSocketSet.remove(this); //從set中刪除,將當前關閉連接的WebSocketServer對象從存放所有客戶端的集合中移除
subOnlineCount(); //在線數減1,調用方法減少當前的在線連接數統(tǒng)計值
// 在控制臺打印出當前關閉連接所對應的sid值
System.out.println("釋放的sid為:"+sid);
// 在控制臺打印出有一連接關閉的提示信息以及更新后的當前在線人數
System.out.println("有一連接關閉!當前在線人數為" + getOnlineCount());
}
/**
* 接受到用戶信息后調用的方法
* @param message
* @param session
*/
// @OnMessage注解標記的方法會在WebSocket服務器接收到客戶端發(fā)送的消息時被自動調用。這個方法主要負責處理接收到的消息,
// 比如在控制臺打印出消息來源及內容,并且可以根據業(yè)務需求對消息進行進一步的處理,這里是將接收到的消息群發(fā)出去。
@OnMessage
public void onMessage(String message,Session session){
// 在控制臺打印出收到消息的來源窗口(通過sid標識)以及消息的具體內容
System.out.println("收到來自窗口" + sid + "的信息:" + message);
//群發(fā)消息
for (WebSocketServer item : webSocketSet) {
try {
//遍歷所有已連接的客戶端對應的WebSocketServer對象,調用每個對象的sendMessage方法將接收到的消息發(fā)送給每個客戶端,實現群發(fā)功能
item.sendMessage(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* @ Param session
* @ Param error
*/
// @OnError注解標記的方法會在WebSocket連接過程中出現錯誤時被自動調用。這個方法主要負責處理錯誤情況,
// 比如在控制臺打印出錯誤提示信息以及打印出詳細的錯誤堆棧信息,以便于排查問題
@OnError
public void onError(Session session, Throwable error) {
System.out.println("發(fā)生錯誤");
error.printStackTrace();
}
/**
* 實現服務器主動推送
*/
public void sendMessage(String message) throws IOException {
// 通過當前客戶端的會話對象(this.session)獲取基本的遠程通信端點(getBasicRemote),然后使用sendText方法將指定的消息發(fā)送給客戶端
this.session.getBasicRemote().sendText(message);
}
/**
* 群發(fā)自定義消息
*/
public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
// 在控制臺打印出要推送消息的目標窗口(通過sid標識)以及推送的具體內容
System.out.println("推送消息到窗口" + sid + ",推送內容:" + message);
for (WebSocketServer item : webSocketSet) {
try {
//為null則全部推送
if (sid == null) {
item.sendMessage(message);
} else if (item.sid.equals(sid)) {
// 遍歷所有已連接的客戶端對應的WebSocketServer對象,如果sid為null則表示要向所有客戶端推送消息,
// 如果當前對象的sid與要推送的目標sid相等,則調用該對象的sendMessage方法將消息發(fā)送給對應的客戶端。
item.sendMessage(message);
}
} catch (IOException e) {
// 如果在發(fā)送消息給某個客戶端過程中出現IO異常,跳過當前循環(huán),繼續(xù)嘗試給下一個客戶端發(fā)送消息。
continue;
}
}
}
// 以下這幾個方法用于對在線連接數(onlineCount)以及存放客戶端的集合(webSocketSet)進行操作,
// 并且都使用了synchronized關鍵字來保證在多線程環(huán)境下對這些共享資源的操作是線程安全的。
/*該方法用于獲取當前的在線連接數。
* 由于在線連接數(onlineCount)是一個被多個方法可能同時訪問和修改的共享變量,
* 為了確保在多線程環(huán)境下獲取到的在線連接數是準確的,使用了synchronized關鍵字進行同步。
* 這樣在某個線程調用此方法獲取在線連接數時,其他線程不能同時對onlineCount進行修改操作,保證了數據的一致性。
*/
public static synchronized int getOnlineCount() {
return onlineCount;
}
/**
* 該方法用于增加在線連接數。
* 當有新的客戶端與WebSocket服務器成功建立連接時(如在onOpen方法中)會調用此方法。
* 同樣因為onlineCount是共享變量,多個線程可能同時嘗試增加它的值(比如多個客戶端同時連接),
* 使用synchronized關鍵字確保在同一時刻只有一個線程能夠執(zhí)行此方法對onlineCount進行自增操作,
* 避免了數據不一致的情況,比如多個線程同時增加導致計數錯誤的問題。
*/
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
/**
* 該方法用于減少在線連接數。
* 當有客戶端與WebSocket服務器的連接關閉時(如在onClose方法中)會調用此方法。
* 與增加在線連接數的方法類似,為了保證在多線程環(huán)境下對onlineCount進行準確的自減操作,
* 使用synchronized關鍵字進行同步,防止多個線程同時對其進行操作而導致數據錯誤。
*/
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
/**
* 該方法用于獲取存放所有已連接客戶端對應的WebSocketServer對象的集合(webSocketSet)。
* 雖然這里獲取集合的操作相對簡單,但由于webSocketSet也是一個可能被多個線程訪問的共享資源,
* 使用synchronized關鍵字進行同步,確保在獲取集合時,其他線程不會對其進行修改等操作,
* 從而保證獲取到的集合狀態(tài)是準確的,可以安全地在獲取到集合后進行后續(xù)的遍歷等操作(如在sendInfo方法中遍歷集合發(fā)送消息)
* @return
*/
public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
return webSocketSet;
}
}
四、前端頁面
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Java 后端 WebSocket 的 Tomcat 實現</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
<body>
Welcome<br/><input id="text" type="text" />
<button onclick="send()">發(fā)送消息</button>
<hr/>
<button onclick="closeWebSocket()">關閉WebSocket連接</button>
<hr/>
<div id="message"></div>
</body>
<script type="text/javascript">
// 定義一個全局變量websocket,用于存儲創(chuàng)建的WebSocket對象,初始值為null
var websocket = null;
//判斷當前瀏覽器是否支持WebSocket
if('WebSocket' in window) {
// 如果瀏覽器支持WebSocket,創(chuàng)建一個WebSocket連接對象,連接到指定的服務器地址,
// 這里連接到本地的8080端口,路徑為/api/websocket/100,其中100可能是一個示例的連接標識或參數
websocket = new WebSocket("ws://localhost:8080/api/websocket/100");
} else {
// 如果瀏覽器不支持WebSocket,彈出一個警告框,提示用戶當前瀏覽器不支持WebSocket
alert('當前瀏覽器 Not support websocket')
}
// 連接發(fā)生錯誤回調方法
// 當WebSocket連接過程中出現錯誤時,會自動調用此函數
websocket.onerror = function() {
// 在網頁上顯示"WebSocket連接發(fā)生錯誤"的提示信息
setMessageInnerHTML("WebSocket連接發(fā)生錯誤");
};
//連接成功建立回調方法
// 當WebSocket連接成功建立時,會自動調用此函數
websocket.onopen = function() {
// 在網頁上顯示"WebSocket連接成功"的提示信息
setMessageInnerHTML("WebSocket連接成功");
}
var U01data, Uidata, Usdata
//接收消息回調方法
// 當WebSocket服務器發(fā)送消息過來時,會自動調用此函數
websocket.onmessage = function(event) {
//在控制臺打印接收到的消息事件對象,用于調試查看消息的詳細信息
console.log(event);
// 將接收到的消息內容顯示在網頁上
setMessageInnerHTML(event.data);
}
//連接關閉回調方法
// 當WebSocket連接關閉時,會自動調用此函數
websocket.onclose = function() {
setMessageInnerHTML("WebSocket連接關閉");
}
//監(jiān)聽窗口關閉事件
// 當用戶嘗試關閉瀏覽器窗口時,會自動調用此函數
window.onbeforeunload = function() {
// 調用closeWebSocket函數,關閉當前的WebSocket連接
closeWebSocket();
}
//將消息顯示在網頁上
function setMessageInnerHTML(innerHTML) {
//在控制臺打印要顯示在網頁上的內容
console.log(innerHTML)
// 通過id獲取網頁上的div元素(id為"message"),并將傳入的內容添加到該元素的innerHTML屬性中
document.getElementById('message').innerHTML += innerHTML + '<br/>';
}
//關閉WebSocket連接
function closeWebSocket() {
// 調用WebSocket對象的close方法,關閉當前建立的WebSocket連接
websocket.close();
}
//發(fā)送消息
function send() {
// 通過id獲取網頁上文本輸入框(id為"text")中的值,即用戶輸入的消息內容
var message = document.getElementById('text').value;
// 使用WebSocket對象的send方法,將用戶輸入的消息以特定格式(這里是一個包含"msg"字段的JSON字符串)發(fā)送給服務器
websocket.send('{"msg":"' + message + '"}');
// 調用setMessageInnerHTML函數,將用戶輸入的消息顯示在網頁上,并添加一個換行符( )
setMessageInnerHTML(message + " ");
}
</script>
</html>五、運行效果
兩個瀏覽器模擬兩個用戶對話:

控制臺

到此這篇關于SpringBoot實現WebSocket的示例代碼的文章就介紹到這了,更多相關SpringBoot實現WebSocket內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:
- SpringBoot分布式WebSocket的實現指南
- SpringBoot實現WebSocket通信過程解讀
- 深入淺出SpringBoot WebSocket構建實時應用全面指南
- 利用SpringBoot與WebSocket實現實時雙向通信功能
- Springboot整合WebSocket 實現聊天室功能
- vue+springboot+webtrc+websocket實現雙人音視頻通話會議(最新推薦)
- Springboot使用Websocket的時候調取IOC管理的Bean報空指針異常問題
- Java?springBoot初步使用websocket的代碼示例
- SpringBoot3整合WebSocket詳細指南
- Spring Boot集成WebSocket項目實戰(zhàn)的示例代碼
相關文章
基于Springboot2.3訪問本地路徑下靜態(tài)資源的方法(解決報錯:Not allowed to load local
這篇文章主要介紹了基于Springboot2.3訪問本地路徑下靜態(tài)資源的方法(解決報錯:Not allowed to load local resource),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-08-08
spring-boot-maven-plugin引入不成功的解決方案
解決Spring Boot Maven插件問題:刪除倉庫文件夾或添加指定版本號,不刪除插件會導致打包路徑錯誤,引用失敗2025-07-07

