最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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)文章

  • IDEA中scala生成變量后自動顯示變量類型問題

    IDEA中scala生成變量后自動顯示變量類型問題

    這篇文章主要介紹了IDEA中scala生成變量后自動顯示變量類型問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • 關(guān)于BufferedReader的讀取效率問題

    關(guān)于BufferedReader的讀取效率問題

    這篇文章主要介紹了關(guān)于BufferedReader的讀取效率問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • Java通俗易懂系列設(shè)計模式之觀察者模式

    Java通俗易懂系列設(shè)計模式之觀察者模式

    這篇文章主要介紹了Java通俗易懂系列設(shè)計模式之觀察者模式,對設(shè)計模式感興趣的同學(xué),一定要看一下
    2021-04-04
  • Spring Boot 搭建 ELK正確看日志的配置流程

    Spring Boot 搭建 ELK正確看日志的配置流程

    這篇文章主要介紹了Spring Boot 搭建 ELK正確看日志的配置流程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • feign調(diào)用中文參數(shù)被encode編譯的問題

    feign調(diào)用中文參數(shù)被encode編譯的問題

    這篇文章主要介紹了feign調(diào)用中文參數(shù)被encode編譯的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java怎么獲取多網(wǎng)卡本地ip

    Java怎么獲取多網(wǎng)卡本地ip

    java獲取本地ip,獲取多網(wǎng)卡本地ip在項目中經(jīng)常會用到,下面小編把代碼分享到腳本之家平臺,供大家參考
    2016-03-03
  • Springboot Redis?哨兵模式的實現(xiàn)示例

    Springboot Redis?哨兵模式的實現(xiàn)示例

    本文主要介紹了Springboot Redis?哨兵模式的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java Mail郵件發(fā)送如何實現(xiàn)簡單封裝

    Java Mail郵件發(fā)送如何實現(xiàn)簡單封裝

    這篇文章主要介紹了Java Mail郵件發(fā)送如何實現(xiàn)簡單封裝,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • java向多線程中傳遞參數(shù)的三種方法詳細(xì)介紹

    java向多線程中傳遞參數(shù)的三種方法詳細(xì)介紹

    但在多線程的異步開發(fā)模式下,數(shù)據(jù)的傳遞和返回和同步開發(fā)模式有很大的區(qū)別。由于線程的運行和結(jié)束是不可預(yù)料的,因此,在傳遞和返回數(shù)據(jù)時就無法象函數(shù)一樣通過函數(shù)參數(shù)和return語句來返回數(shù)據(jù)
    2012-11-11
  • Mybatis-Plus更新時間字段不生效的解決

    Mybatis-Plus更新時間字段不生效的解決

    在使用Mybatis-Plus時,可能會遇到updateTime字段不自動更新的問題,通過分析,原因在于selectById獲取舊數(shù)據(jù)后,如果字段已有值,更新操作不會自動填充更新時間,可以通過直接在實體中設(shè)置更新時間或在更新操作時指定時間來解決此問題
    2024-09-09

最新評論

嘉黎县| 盐源县| 青州市| 西青区| 铜鼓县| 涞源县| 内江市| 习水县| 区。| 新乡市| 略阳县| 灯塔市| 阿鲁科尔沁旗| 陵川县| 游戏| 原平市| 喀喇沁旗| 泽普县| 巢湖市| 乐业县| 长兴县| 洛川县| 胶南市| 遂溪县| 铜川市| 高平市| 和林格尔县| 将乐县| 许昌市| 南召县| 贡觉县| 桂阳县| 鄂尔多斯市| 瑞昌市| 浙江省| 房产| 聂拉木县| 建水县| 石柱| 阳朔县| 大竹县|