欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot實現(xiàn)WebSocket的示例代碼

 更新時間:2024年11月19日 09:59:31   作者:絡(luò)7  
這篇文章主要為大家詳細(xì)介紹了SpringBoot實現(xiàn)WebSocket的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

一、環(huán)境搭建

1.創(chuàng)建SpringBoot項目,引入相關(guān)依賴

<dependencies>
        <!-- Spring Boot核心啟動器,引入常用依賴基礎(chǔ) -->
        <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ā)啟動器,構(gòu)建Web應(yīng)用相關(guān) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- Spring Boot測試相關(guān)依賴,確保應(yīng)用正確性等 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-test</artifactId>
        </dependency>

        <!-- Spring Boot對WebSocket啟動器,實現(xiàn)雙向通信功能 -->
        <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 # 關(guān)閉Thymeleaf頁面緩存,開發(fā)時便于即時看到模板修改效果
    encoding: UTF-8 # 模板編碼設(shè)為UTF-8,確保字符正確解析,避免亂碼
    prefix: classpath:/templates/  # 頁面映射路徑:模板文件查找路徑前綴,在類路徑下的templates目錄找
    suffix:.html # 視圖對應(yīng)的模板文件后綴名
    mode: HTML5 # 設(shè)置模板模式為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框架的應(yīng)用中配置和啟用WebSocket功能。
 * 通過相關(guān)注解和方法的定義,使得應(yīng)用能夠正確地處理WebSocket連接和通信。
 */
@Configuration
public class WebSocketConfig {
    @Bean //用于將方法返回的ServerEndpointExporter對象作為一個Bean注冊到Spring的容器中
    public ServerEndpointExporter serverEndpointExporter() {
        //創(chuàng)建并返回一個ServerEndpointExporter對象。
        // ServerEndpointExporter主要作用是掃描帶有@ServerEndpoint注解的WebSocket端點類,并將它們注冊到Servlet容器中,
        // 從而使得應(yīng)用能夠正確地處理WebSocket連接請求,實現(xiàn)WebSocket的通信功能。
        return new ServerEndpointExporter();
    }
}

三、服務(wù)層

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 服務(wù)器端。
 * 注解的值將被用于監(jiān)聽用戶連接的終端訪問 URL 地址,客戶端可以通過這個 URL 來連接到 WebSocket 服務(wù)器端
 */
@Component
@Service
/**@ServerEndpoint注解用于將當(dāng)前類定義為一個WebSocket服務(wù)器端端點。注解中的值"/api/websocket/{sid}"指定了客戶端連接到這個WebSocket服務(wù)器端的URL地址,
其中{sid}是一個路徑參數(shù),可以在后續(xù)的方法中獲取并使用,不同的客戶端可以通過帶有不同sid值的這個URL來建立與服務(wù)器的WebSocket連接。
*/
 @ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {

    private Session session;  //用戶信息
    //存放每個客戶端對應(yīng)的MyWebSocket對象,保存所有已連接的客戶端對應(yīng)的WebSocketServer實例
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
    //當(dāng)前在線連接數(shù),用于記錄當(dāng)前有多少個客戶端與WebSocket服務(wù)器建立了連接
    private static int onlineCount = 0;
    //用于接收從客戶端連接URL路徑參數(shù)中獲取的sid值,這個sid可以用于標(biāo)識不同的客戶端連接或者與客戶端相關(guān)的業(yè)務(wù)邏輯處理
    private String sid = "";


    /**
     * 連接建立成功調(diào)用的方法
     * 這個方法會處理與新連接建立相關(guān)的初始化操作,
     * 比如記錄客戶端的會話信息、將當(dāng)前對象添加到已連接客戶端集合中、更新在線連接數(shù)等。
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        webSocketSet.add(this);     //加入set中,將當(dāng)前新建立連接的WebSocketServer對象添加到存放所有客戶端的集合中
        this.sid = sid;
        addOnlineCount();           //在線數(shù)加1,調(diào)用方法增加當(dāng)前的在線連接數(shù)統(tǒng)計值
        try {
            sendMessage("conn_success"); // 向當(dāng)前新連接的客戶端發(fā)送一條消息"conn_success",告知客戶端連接成功。
            // 在控制臺打印出有新窗口開始監(jiān)聽的sid以及當(dāng)前的在線人數(shù)信息。
            System.out.println("有新窗口開始監(jiān)聽:" + sid + ",當(dāng)前在線人數(shù)為:" + getOnlineCount());
        } catch (IOException e) {
            // 如果發(fā)送消息過程中出現(xiàn)IO異常,在控制臺打印出相應(yīng)提示信息
            System.out.println("websocket IO Exception");
        }
    }

    /**
     * 連接關(guān)閉調(diào)用的方法
     */
    // @OnClose注解標(biāo)記的方法會在WebSocket連接關(guān)閉時被自動調(diào)用。這個方法主要處理與連接關(guān)閉相關(guān)的清理操作,
    // 比如從已連接客戶端集合中刪除對應(yīng)的對象、更新在線連接數(shù)等。
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //從set中刪除,將當(dāng)前關(guān)閉連接的WebSocketServer對象從存放所有客戶端的集合中移除
        subOnlineCount();           //在線數(shù)減1,調(diào)用方法減少當(dāng)前的在線連接數(shù)統(tǒng)計值

        // 在控制臺打印出當(dāng)前關(guān)閉連接所對應(yīng)的sid值
        System.out.println("釋放的sid為:"+sid);
        // 在控制臺打印出有一連接關(guān)閉的提示信息以及更新后的當(dāng)前在線人數(shù)
        System.out.println("有一連接關(guān)閉!當(dāng)前在線人數(shù)為" + getOnlineCount());
    }
    /**
     * 接受到用戶信息后調(diào)用的方法
     * @param message
     * @param session
     */
    // @OnMessage注解標(biāo)記的方法會在WebSocket服務(wù)器接收到客戶端發(fā)送的消息時被自動調(diào)用。這個方法主要負(fù)責(zé)處理接收到的消息,
    // 比如在控制臺打印出消息來源及內(nèi)容,并且可以根據(jù)業(yè)務(wù)需求對消息進(jìn)行進(jìn)一步的處理,這里是將接收到的消息群發(fā)出去。
    @OnMessage
    public void onMessage(String message,Session session){
        // 在控制臺打印出收到消息的來源窗口(通過sid標(biāo)識)以及消息的具體內(nèi)容
        System.out.println("收到來自窗口" + sid + "的信息:" + message);
        //群發(fā)消息
        for (WebSocketServer item : webSocketSet) {
            try {
                //遍歷所有已連接的客戶端對應(yīng)的WebSocketServer對象,調(diào)用每個對象的sendMessage方法將接收到的消息發(fā)送給每個客戶端,實現(xiàn)群發(fā)功能
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @ Param session
     * @ Param error
     */
    // @OnError注解標(biāo)記的方法會在WebSocket連接過程中出現(xiàn)錯誤時被自動調(diào)用。這個方法主要負(fù)責(zé)處理錯誤情況,
    // 比如在控制臺打印出錯誤提示信息以及打印出詳細(xì)的錯誤堆棧信息,以便于排查問題
    @OnError
    public void onError(Session session, Throwable error) {
        System.out.println("發(fā)生錯誤");
        error.printStackTrace();
    }

    /**
     * 實現(xiàn)服務(wù)器主動推送
     */
    public void sendMessage(String message) throws IOException {
        // 通過當(dāng)前客戶端的會話對象(this.session)獲取基本的遠(yuǎn)程通信端點(getBasicRemote),然后使用sendText方法將指定的消息發(fā)送給客戶端
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 群發(fā)自定義消息
     */
    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
        // 在控制臺打印出要推送消息的目標(biāo)窗口(通過sid標(biāo)識)以及推送的具體內(nèi)容
        System.out.println("推送消息到窗口" + sid + ",推送內(nèi)容:" + message);

        for (WebSocketServer item : webSocketSet) {
            try {
                //為null則全部推送
                if (sid == null) {
                    item.sendMessage(message);
                } else if (item.sid.equals(sid)) {
                    // 遍歷所有已連接的客戶端對應(yīng)的WebSocketServer對象,如果sid為null則表示要向所有客戶端推送消息,
                    // 如果當(dāng)前對象的sid與要推送的目標(biāo)sid相等,則調(diào)用該對象的sendMessage方法將消息發(fā)送給對應(yīng)的客戶端。
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                // 如果在發(fā)送消息給某個客戶端過程中出現(xiàn)IO異常,跳過當(dāng)前循環(huán),繼續(xù)嘗試給下一個客戶端發(fā)送消息。
                continue;
            }
        }
    }

    // 以下這幾個方法用于對在線連接數(shù)(onlineCount)以及存放客戶端的集合(webSocketSet)進(jìn)行操作,
    // 并且都使用了synchronized關(guān)鍵字來保證在多線程環(huán)境下對這些共享資源的操作是線程安全的。

    /*該方法用于獲取當(dāng)前的在線連接數(shù)。
     * 由于在線連接數(shù)(onlineCount)是一個被多個方法可能同時訪問和修改的共享變量,
     * 為了確保在多線程環(huán)境下獲取到的在線連接數(shù)是準(zhǔn)確的,使用了synchronized關(guān)鍵字進(jìn)行同步。
     * 這樣在某個線程調(diào)用此方法獲取在線連接數(shù)時,其他線程不能同時對onlineCount進(jìn)行修改操作,保證了數(shù)據(jù)的一致性。
    */
    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    /**
     * 該方法用于增加在線連接數(shù)。
     * 當(dāng)有新的客戶端與WebSocket服務(wù)器成功建立連接時(如在onOpen方法中)會調(diào)用此方法。
     * 同樣因為onlineCount是共享變量,多個線程可能同時嘗試增加它的值(比如多個客戶端同時連接),
     * 使用synchronized關(guān)鍵字確保在同一時刻只有一個線程能夠執(zhí)行此方法對onlineCount進(jìn)行自增操作,
     * 避免了數(shù)據(jù)不一致的情況,比如多個線程同時增加導(dǎo)致計數(shù)錯誤的問題。
     */
    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    /**
     * 該方法用于減少在線連接數(shù)。
     * 當(dāng)有客戶端與WebSocket服務(wù)器的連接關(guān)閉時(如在onClose方法中)會調(diào)用此方法。
     * 與增加在線連接數(shù)的方法類似,為了保證在多線程環(huán)境下對onlineCount進(jìn)行準(zhǔn)確的自減操作,
     * 使用synchronized關(guān)鍵字進(jìn)行同步,防止多個線程同時對其進(jìn)行操作而導(dǎo)致數(shù)據(jù)錯誤。
     */
    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    /**
     * 該方法用于獲取存放所有已連接客戶端對應(yīng)的WebSocketServer對象的集合(webSocketSet)。
     * 雖然這里獲取集合的操作相對簡單,但由于webSocketSet也是一個可能被多個線程訪問的共享資源,
     * 使用synchronized關(guān)鍵字進(jìn)行同步,確保在獲取集合時,其他線程不會對其進(jìn)行修改等操作,
     * 從而保證獲取到的集合狀態(tài)是準(zhǔn)確的,可以安全地在獲取到集合后進(jìn)行后續(xù)的遍歷等操作(如在sendInfo方法中遍歷集合發(fā)送消息)
     * @return
     */
    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }
}

四、前端頁面

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Java 后端 WebSocket 的 Tomcat 實現(xiàn)</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()">關(guān)閉WebSocket連接</button>
<hr/>
<div id="message"></div>
</body>
<script type="text/javascript">
    // 定義一個全局變量websocket,用于存儲創(chuàng)建的WebSocket對象,初始值為null
    var websocket = null;
    //判斷當(dāng)前瀏覽器是否支持WebSocket
    if('WebSocket' in window) {
        // 如果瀏覽器支持WebSocket,創(chuàng)建一個WebSocket連接對象,連接到指定的服務(wù)器地址,
        // 這里連接到本地的8080端口,路徑為/api/websocket/100,其中100可能是一個示例的連接標(biāo)識或參數(shù)
        websocket = new WebSocket("ws://localhost:8080/api/websocket/100");
    } else {
        // 如果瀏覽器不支持WebSocket,彈出一個警告框,提示用戶當(dāng)前瀏覽器不支持WebSocket
        alert('當(dāng)前瀏覽器 Not support websocket')
    }
    // 連接發(fā)生錯誤回調(diào)方法
    // 當(dāng)WebSocket連接過程中出現(xiàn)錯誤時,會自動調(diào)用此函數(shù)
    websocket.onerror = function() {
        // 在網(wǎng)頁上顯示"WebSocket連接發(fā)生錯誤"的提示信息
        setMessageInnerHTML("WebSocket連接發(fā)生錯誤");
    };

    //連接成功建立回調(diào)方法
    // 當(dāng)WebSocket連接成功建立時,會自動調(diào)用此函數(shù)
    websocket.onopen = function() {
        // 在網(wǎng)頁上顯示"WebSocket連接成功"的提示信息
        setMessageInnerHTML("WebSocket連接成功");
    }
    var U01data, Uidata, Usdata
    //接收消息回調(diào)方法
    // 當(dāng)WebSocket服務(wù)器發(fā)送消息過來時,會自動調(diào)用此函數(shù)
    websocket.onmessage = function(event) {
        //在控制臺打印接收到的消息事件對象,用于調(diào)試查看消息的詳細(xì)信息
        console.log(event);
        // 將接收到的消息內(nèi)容顯示在網(wǎng)頁上
        setMessageInnerHTML(event.data);
    }

    //連接關(guān)閉回調(diào)方法
    // 當(dāng)WebSocket連接關(guān)閉時,會自動調(diào)用此函數(shù)
    websocket.onclose = function() {
        setMessageInnerHTML("WebSocket連接關(guān)閉");
    }

    //監(jiān)聽窗口關(guān)閉事件
    // 當(dāng)用戶嘗試關(guān)閉瀏覽器窗口時,會自動調(diào)用此函數(shù)
    window.onbeforeunload = function() {
        // 調(diào)用closeWebSocket函數(shù),關(guān)閉當(dāng)前的WebSocket連接
        closeWebSocket();
    }

    //將消息顯示在網(wǎng)頁上
    function setMessageInnerHTML(innerHTML) {
        //在控制臺打印要顯示在網(wǎng)頁上的內(nèi)容
        console.log(innerHTML)
        // 通過id獲取網(wǎng)頁上的div元素(id為"message"),并將傳入的內(nèi)容添加到該元素的innerHTML屬性中
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //關(guān)閉WebSocket連接
    function closeWebSocket() {
        // 調(diào)用WebSocket對象的close方法,關(guān)閉當(dāng)前建立的WebSocket連接
        websocket.close();
    }

    //發(fā)送消息
    function send() {
        // 通過id獲取網(wǎng)頁上文本輸入框(id為"text")中的值,即用戶輸入的消息內(nèi)容
        var message = document.getElementById('text').value;
        // 使用WebSocket對象的send方法,將用戶輸入的消息以特定格式(這里是一個包含"msg"字段的JSON字符串)發(fā)送給服務(wù)器
        websocket.send('{"msg":"' + message + '"}');
        // 調(diào)用setMessageInnerHTML函數(shù),將用戶輸入的消息顯示在網(wǎng)頁上,并添加一個換行符(&#13;)
        setMessageInnerHTML(message + "&#13;");
    }
</script>

</html>

五、運行效果

兩個瀏覽器模擬兩個用戶對話:

控制臺

到此這篇關(guān)于SpringBoot實現(xiàn)WebSocket的示例代碼的文章就介紹到這了,更多相關(guān)SpringBoot實現(xiàn)WebSocket內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • jenkins+maven+svn自動部署和發(fā)布的詳細(xì)圖文教程

    jenkins+maven+svn自動部署和發(fā)布的詳細(xì)圖文教程

    Jenkins是一個開源的、可擴(kuò)展的持續(xù)集成、交付、部署的基于web界面的平臺。這篇文章主要介紹了jenkins+maven+svn自動部署和發(fā)布的詳細(xì)圖文教程,需要的朋友可以參考下
    2020-09-09
  • Hibernate映射解析之關(guān)聯(lián)映射詳解

    Hibernate映射解析之關(guān)聯(lián)映射詳解

    所謂關(guān)聯(lián)映射就是將關(guān)聯(lián)關(guān)系映射到數(shù)據(jù)庫里,在對象模型中就是一個或多個引用。下面這篇文章詳細(xì)的給大家介紹了Hibernate映射解析之關(guān)聯(lián)映射的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-02-02
  • 解決Spring?Security升級到5.5.7、5.6.4及以上啟動報錯出現(xiàn)版本不兼容的問題

    解決Spring?Security升級到5.5.7、5.6.4及以上啟動報錯出現(xiàn)版本不兼容的問題

    這篇文章主要介紹了解決Spring?Security升級到5.5.7、5.6.4及以上啟動報錯出現(xiàn)版本不兼容的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 解決tomcat發(fā)布工程后,WEB-INF/classes下文件不編譯的問題

    解決tomcat發(fā)布工程后,WEB-INF/classes下文件不編譯的問題

    這篇文章主要介紹了解決tomcat發(fā)布工程后,WEB-INF/classes下文件不編譯的問題,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • SpringBoot集成Quartz實現(xiàn)持久化定時接口調(diào)用任務(wù)

    SpringBoot集成Quartz實現(xiàn)持久化定時接口調(diào)用任務(wù)

    Quartz是功能強(qiáng)大的開源作業(yè)調(diào)度庫,幾乎可以集成到任何?Java?應(yīng)用程序中,從最小的獨立應(yīng)用程序到最大的電子商務(wù)系統(tǒng),本文將通過代碼示例給大家介紹SpringBoot集成Quartz實現(xiàn)持久化定時接口調(diào)用任務(wù),需要的朋友可以參考下
    2023-07-07
  • 詳細(xì)分析java并發(fā)之volatile關(guān)鍵字

    詳細(xì)分析java并發(fā)之volatile關(guān)鍵字

    這篇文章主要介紹了java并發(fā)之volatile關(guān)鍵字的的相關(guān)資料,文中代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • += 和 ++ 操作符區(qū)別簡單介紹

    += 和 ++ 操作符區(qū)別簡單介紹

    這篇文章主要介紹了+= 和 ++ 操作符區(qū)別簡單介紹的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-09-09
  • Java中實現(xiàn)簡單的Excel導(dǎo)出

    Java中實現(xiàn)簡單的Excel導(dǎo)出

    今天小編就為大家分享一篇關(guān)于Java中實現(xiàn)簡單的Excel導(dǎo)出,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • Java中ThreadLocal避免內(nèi)存泄漏的方法詳解

    Java中ThreadLocal避免內(nèi)存泄漏的方法詳解

    ThreadLocal是Java中的一個線程本地存儲機(jī)制,它允許每個線程擁有一個獨立的本地存儲空間,用于存儲該線程的變量,本文主要介紹了ThreadLocal如何避免內(nèi)存泄漏,需要的朋友可以參考下
    2023-05-05
  • MyBatis-Plus實現(xiàn)公共字段自動填充功能詳解

    MyBatis-Plus實現(xiàn)公共字段自動填充功能詳解

    在開發(fā)中經(jīng)常遇到多個實體類有共同的屬性字段,這些字段屬于公共字段,也就是很多表中都有這些字段,能不能對于這些公共字段在某個地方統(tǒng)一處理,來簡化開發(fā)呢?MyBatis-Plus就提供了這一功能,本文就來為大家詳細(xì)講講
    2022-08-08

最新評論