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

SpringBoot整合WebSocket實現(xiàn)實時通信功能

 更新時間:2023年11月29日 10:49:20   作者:fking86  
在當今互聯(lián)網(wǎng)時代,實時通信已經(jīng)成為了許多應用程序的基本需求,而WebSocket作為一種全雙工通信協(xié)議,為開發(fā)者提供了一種簡單、高效的實時通信解決方案,本文將介紹如何使用SpringBoot框架來實現(xiàn)WebSocket的集成,快速搭建實時通信功能,感興趣的朋友可以參考下

什么是WebSocket?

WebSocket是一種在單個TCP連接上進行全雙工通信的協(xié)議。與傳統(tǒng)的HTTP請求-響應模式不同,WebSocket允許服務器主動向客戶端推送數(shù)據(jù),實現(xiàn)了實時通信的功能。WebSocket協(xié)議基于HTTP協(xié)議,通過在握手階段升級協(xié)議,使得服務器和客戶端可以直接進行數(shù)據(jù)交換,而無需頻繁的HTTP請求。

Spring Boot中的WebSocket支持

Spring Boot提供了對WebSocket的支持,通過集成Spring WebSocket模塊,我們可以輕松地實現(xiàn)WebSocket功能。在Spring Boot中,我們可以使用注解來定義WebSocket的處理器和消息處理方法,從而實現(xiàn)實時通信。

WebSocket和HTTP優(yōu)劣勢

WebSocket的優(yōu)勢:

1.實時性:

WebSocket是一種全雙工通信協(xié)議,可以實現(xiàn)服務器主動向客戶端推送數(shù)據(jù),實現(xiàn)實時通信。相比之下,HTTP是一種請求-響應模式 的協(xié)議,需要客戶端主動發(fā)起請求才能獲取數(shù)據(jù)。

2.較低的延遲:

由于WebSocket使用單個TCP連接進行通信,避免了HTTP的握手和頭部信息的重復傳輸,因此具有較低的延遲。

3.較小的數(shù)據(jù)傳輸量:

WebSocket使用二進制數(shù)據(jù)幀進行傳輸,相比于HTTP的文本數(shù)據(jù)傳輸,可以減少數(shù)據(jù)傳輸量,提高傳輸效率。

4.更好的兼容性:

WebSocket協(xié)議可以在多種瀏覽器和平臺上使用,具有較好的兼容性。

HTTP的優(yōu)勢:

1.簡單易用:

? HTTP是一種簡單的請求-響應協(xié)議,易于理解和使用。相比之下,WebSocket需要進行握手和協(xié)議升級等復雜操作。

2.更廣泛的應用:

HTTP協(xié)議廣泛應用于Web開發(fā)中,支持各種類型的請求和響應,可以用于傳輸文本、圖片、視頻等多種數(shù)據(jù)格式。

3.更好的安全性:

HTTP協(xié)議支持HTTPS加密傳輸,可以保證數(shù)據(jù)的安全性。

綜上,WebSocket適用于需要實時通信和較低延遲的場景,而HTTP適用于傳輸各種類型的數(shù)據(jù)和簡單的請求-響應模式。在實際應用中,可以根據(jù)具體需求選擇合適的協(xié)議。

示例

版本依賴

模塊版本
SpringBoot3.1.0
JDK17

代碼

WebSocketConfig

@Configuration
public class WebSocketConfig {
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }
}

WebSocketServer

@Component
@ServerEndpoint("/server/{uid}")
@Slf4j
public class WebSocketServer {

    /**
     * 記錄當前在線連接數(shù)
     */
    private static int onlineCount = 0;

    /**
     * 使用線程安全的ConcurrentHashMap來存放每個客戶端對應的WebSocket對象
     */
    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();

    /**
     * 與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù)
     */
    private Session session;

    /**
     * 接收客戶端消息的uid
     */
    private String uid = "";

    /**
     * 連接建立成功調(diào)用的方法
     * @param session
     * @param uid
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("uid") String uid) {
        this.session = session;
        this.uid = uid;
        if (webSocketMap.containsKey(uid)) {
            webSocketMap.remove(uid);
            //加入到set中
            webSocketMap.put(uid, this);
        } else {
            //加入set中
            webSocketMap.put(uid, this);
            //在線數(shù)加1
            addOnlineCount();
        }

        log.info("用戶【" + uid + "】連接成功,當前在線人數(shù)為:" + getOnlineCount());
        try {
            sendMsg("連接成功");
        } catch (IOException e) {
            log.error("用戶【" + uid + "】網(wǎng)絡異常!", e);
        }
    }

    /**
     * 連接關閉調(diào)用的方法
     */
    @OnClose
    public void onClose() {
        if (webSocketMap.containsKey(uid)) {
            webSocketMap.remove(uid);
            //從set中刪除
            subOnlineCount();
        }
        log.info("用戶【" + uid + "】退出,當前在線人數(shù)為:" + getOnlineCount());
    }

    /**
     * 收到客戶端消息后調(diào)用的方法
     * @param message 客戶端發(fā)送過來的消息
     * @param session 會話
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("用戶【" + uid + "】發(fā)送報文:" + message);
        //群發(fā)消息
        //消息保存到數(shù)據(jù)庫或者redis
        if (StringUtils.isNotBlank(message)) {
            try {
                //解析發(fā)送的報文
                ObjectMapper objectMapper = new ObjectMapper();
                Map<String, String> map = objectMapper.readValue(message, new TypeReference<Map<String, String>>(){});
                //追加發(fā)送人(防止串改)
                map.put("fromUID", this.uid);
                String toUID = map.get("toUID");
                //傳送給對應的toUserId用戶的WebSocket
                if (StringUtils.isNotBlank(toUID) && webSocketMap.containsKey(toUID)) {
                    webSocketMap.get(toUID).sendMsg(objectMapper.writeValueAsString(map));
                } else {
                    //若果不在這個服務器上,可以考慮發(fā)送到mysql或者redis
                    log.error("請求目標用戶【" + toUID + "】不在該服務器上");
                }
            } catch (Exception e) {
                log.error("用戶【" + uid + "】發(fā)送消息異常!", e);
            }
        }
    }

    /**
     * 處理錯誤
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("用戶【" + this.uid + "】處理消息錯誤,原因:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 實現(xiàn)服務器主動推送
     * @param msg
     * @throws IOException
     */
    private void sendMsg(String msg) throws IOException {
        this.session.getBasicRemote().sendText(msg);
    }

    /**
     * 發(fā)送自定義消息
     * @param message
     * @param uid
     * @throws IOException
     */
    public static void sendInfo(String message, @PathParam("uid") String uid) throws IOException {
        log.info("發(fā)送消息到用戶【" + uid + "】發(fā)送的報文:" + message);
        if (!StringUtils.isEmpty(uid) && webSocketMap.containsKey(uid)) {
            webSocketMap.get(uid).sendMsg(message);
        } else {
            log.error("用戶【" + uid + "】不在線!");
        }
    }

    private static synchronized int getOnlineCount() {
        return onlineCount;
    }

    private static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    private static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}

WebSocketController

@RestController
public class WebSocketController {

    @GetMapping("/page")
    public ModelAndView page() {
        return new ModelAndView("webSocket");
    }

    @RequestMapping("/push/{toUID}")
    public ResponseEntity<String> pushToClient(String message, @PathVariable String toUID) throws Exception {
        WebSocketServer.sendInfo(message, toUID);
        return ResponseEntity.ok("Send Success!");
    }
}

webSocket.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>WebSocket消息通知</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    var socket;

    //打開WebSocket
    function openSocket() {
        if (typeof (WebSocket) === "undefined") {
            console.log("您的瀏覽器不支持WebSocket");
        } else {
            console.log("您的瀏覽器支持WebSocket");
            //實現(xiàn)化WebSocket對象,指定要連接的服務器地址與端口,建立連接.
            var socketUrl = "http://localhost:8080/socket/server/" + $("#uid").val();
            //將https與http協(xié)議替換為ws協(xié)議
            socketUrl = socketUrl.replace("https", "ws").replace("http", "ws");
            console.log(socketUrl);
            if (socket != null) {
                socket.close();
                socket = null;
            }
            socket = new WebSocket(socketUrl);
            //打開事件
            socket.onopen = function () {
                console.log("WebSocket已打開");
                //socket.send("這是來自客戶端的消息" + location.href + new Date());
            };
            //獲得消息事件
            socket.onmessage = function (msg) {
                console.log(msg.data);
                //發(fā)現(xiàn)消息進入,開始處理前端觸發(fā)邏輯
            };
            //關閉事件
            socket.onclose = function () {
                console.log("WebSocket已關閉");
            };
            //發(fā)生了錯誤事件
            socket.onerror = function () {
                console.log("WebSocket發(fā)生了錯誤");
            }
        }
    }

    //發(fā)送消息
    function sendMessage() {
        if (typeof (WebSocket) === "undefined") {
            console.log("您的瀏覽器不支持WebSocket");
        } else {
            console.log("您的瀏覽器支持WebSocket");
            console.log('{"toUID":"' + $("#toUID").val() + '","Msg":"' + $("#msg").val() + '"}');
            socket.send('{"toUID":"' + $("#toUID").val() + '","Msg":"' + $("#msg").val() + '"}');
        }
    }
</script>
<body>
<p>【uid】:
<div><input id="uid" name="uid" type="text" value="1"></div>
<p>【toUID】:
<div><input id="toUID" name="toUID" type="text" value="2"></div>
<p>【Msg】:
<div><input id="msg" name="msg" type="text" value="hello WebSocket2"></div>
<p>【第一步操作:】:
<div>
    <button onclick="openSocket()">開啟socket</button>
</div>
<p>【第二步操作:】:
<div>
    <button onclick="sendMessage()">發(fā)送消息</button>
</div>
</body>

</html>

測試

打開2個頁面

第一個:

http://localhost:8080/socket/page

第二個:

http://localhost:8080/socket/page

都點擊開啟socket

都點擊發(fā)送

至此示例發(fā)送完成

總結(jié)

通過本文的介紹,我們了解了Spring Boot中如何集成WebSocket,實現(xiàn)實時通信的功能。

WebSocket作為一種高效的實時通信協(xié)議,為開發(fā)者提供了更好的用戶體驗和交互性。

希望本文能夠幫助快速掌握Spring Boot整合WebSocket的方法,為應用程序添加實時通信功能。

以上就是SpringBoot整合WebSocket實現(xiàn)實時通信功能的詳細內(nèi)容,更多關于SpringBoot WebSocket通信的資料請關注腳本之家其它相關文章!

相關文章

  • 教你用Java實現(xiàn)一個簡單的代碼生成器

    教你用Java實現(xiàn)一個簡單的代碼生成器

    今天給大家?guī)淼氖顷P于Java的相關知識,文章圍繞著如何用Java實現(xiàn)一個簡單的代碼生成器展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java中的指令重排詳解

    Java中的指令重排詳解

    在 Java 中,指令重排是一種性能優(yōu)化技術,它涉及到編譯器和處理器對程序中指令的執(zhí)行順序進行調(diào)整,以提高執(zhí)行效率,本文給大家詳細介紹了Java中的指令重排,需要的朋友可以參考下
    2023-12-12
  • 淺談從Java中的棧和堆,進而衍生到值傳遞

    淺談從Java中的棧和堆,進而衍生到值傳遞

    這篇文章主要介紹了淺談從Java中的棧和堆,進而衍生到值傳遞,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Spring中的REST分頁的實現(xiàn)代碼

    Spring中的REST分頁的實現(xiàn)代碼

    本文將介紹在REST API中實現(xiàn)分頁的基礎知識。我們將專注于使用Spring Boot和Spring Data 在Spring MVC中構(gòu)建REST分頁,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • mybatis-plus使用問題小結(jié)

    mybatis-plus使用問題小結(jié)

    這篇文章主要介紹了mybatis-plus使用問題匯總,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03
  • idea中方法、注釋、導入類折疊或是展開的設置方法

    idea中方法、注釋、導入類折疊或是展開的設置方法

    這篇文章主要介紹了idea中方法、注釋、導入類折疊或是展開的設置,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-04-04
  • jar包手動添加到本地maven倉庫的步驟詳解

    jar包手動添加到本地maven倉庫的步驟詳解

    在寫程序的過程中,有時候會遇到私服里沒有需要的jar包的情況,這時候我們就可以手動導入jar包到本地倉庫進行使用,下面這篇文章主要給大家介紹了關于jar包手動添加到本地maven倉庫的相關資料,需要的朋友可以參考下
    2022-08-08
  • Java實現(xiàn)石頭剪刀布游戲

    Java實現(xiàn)石頭剪刀布游戲

    這篇文章主要為大家詳細介紹了Java實現(xiàn)石頭剪刀布游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-10-10
  • Eclipse 出現(xiàn)A configuration with this name already exists問題解決方法

    Eclipse 出現(xiàn)A configuration with this name already exists問題解決方

    這篇文章主要介紹了Eclipse 出現(xiàn)A configuration with this name already exists問題解決方法的相關資料,需要的朋友可以參考下
    2016-11-11
  • java配置變量的解釋,搬運他人優(yōu)質(zhì)評論(推薦)

    java配置變量的解釋,搬運他人優(yōu)質(zhì)評論(推薦)

    這篇文章主要介紹了java配置變量,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-04-04

最新評論