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

SpringBoot中使用WebSocket的教程分享

 更新時(shí)間:2023年06月01日 16:20:31   作者:X_H學(xué)Java  
這篇文章主要為大家詳細(xì)介紹了如何在SpringBoot中使用WebSocket,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,感興趣的小伙伴可以了解一下

為什么要用WebSocket

我們往往需要一些這樣的場景,服務(wù)器給客戶端推送消息,如淘寶推送消息,網(wǎng)上聊天等,這些場景下客戶端沒有主動(dòng)向服務(wù)器發(fā)請求,而是由服務(wù)器主動(dòng)的向客戶端發(fā)送消息,但是之前用的HTTP協(xié)議是一次請求一次響應(yīng)

那該如何實(shí)現(xiàn)服務(wù)器主動(dòng)的向客戶端推送消息呢?

如果繼續(xù)使用HTTP協(xié)議,可以基于輪詢的方式實(shí)現(xiàn),也就是客戶端每隔一段時(shí)間給服務(wù)器發(fā)請求,看看有沒有要發(fā)送給我的消息,如果有就獲取到消息,如果沒有就等待

上述輪詢存在一定問題:

  • 消耗更多的系統(tǒng)資源,客戶端要頻繁的向服務(wù)器發(fā)請求,而這些請求大多數(shù)是沒有響應(yīng)的
  • 獲取消息不夠及時(shí),只有輪詢的時(shí)候(下次請求的周期)才能夠獲取到消息

如果提高輪詢頻率,則將消耗更多的系統(tǒng)資源,如果降低輪詢頻率,那獲取消息就不夠及時(shí)

此時(shí)可以使用WebSocket協(xié)議,WebSocket協(xié)議也是應(yīng)用層協(xié)議,傳輸層也是基于TCP協(xié)議的,該協(xié)議可以實(shí)現(xiàn)服務(wù)器主動(dòng)向客戶端推送消息的功能

WebSocket的握手階段

先了解一下報(bào)文格式中的幾個(gè)重要信息:

  • FIN:表示是否關(guān)閉websocket
  • opcode操作碼:描述了當(dāng)前的websocket數(shù)據(jù)幀是起到了啥作用(0x1表示文本數(shù)據(jù),0x2表示二進(jìn)制數(shù)據(jù))
  • MASK:是否開啟掩碼操作,掩碼操作是為了避免緩沖區(qū)溢出
  • payload length:載荷的長度
  • payload data:載荷真正攜帶的數(shù)據(jù)

WebSocket協(xié)議的握手過程

總結(jié)如下:

  • 客戶端向服務(wù)端發(fā)一個(gè)申請建立websocket連接的HTTP請求,該請求是基于HTTP協(xié)議的,這個(gè)HTTP請求的請求頭包含了重要的Header頭,如Connection: upgrade,Upgrade: websocket,標(biāo)識(shí)要進(jìn)行協(xié)議升級(jí),并升級(jí)的協(xié)議類型為websocket
  • 服務(wù)端收到該請求后,返回一個(gè)HTTP響應(yīng),響應(yīng)狀態(tài)碼為101表示協(xié)議切換,并且響應(yīng)也會(huì)包含重要的Header頭Connection: upgrade,Upgrade: websocket
  • 客戶端與服務(wù)端建立好全雙工的websocket長連接,后續(xù)傳輸都是基于WebSocket協(xié)議

Spring Boot中使用WebSocket

添加WebSocket依賴

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>

服務(wù)器代碼編寫

主要的步驟分為以下兩步:

  • 創(chuàng)建一個(gè)類作為WebSocketHandler(處理WebSocket中各個(gè)通信流程)
  • 把上述類注冊到Spring中,配置路由(關(guān)聯(lián)上哪個(gè)路徑對(duì)應(yīng)上述的handler)

創(chuàng)建一個(gè)類繼承TextWebSocketHandler,并添加類注解@Component將該類注冊到Spring中,并重寫:

  • afterConnectionEstablished:該方法會(huì)在websocket連接成功后被調(diào)用
  • handleTextMessage:該方法是在websocket收到消息的時(shí)候自動(dòng)調(diào)用
  • handleTransportError:該方法是在websocket連接出現(xiàn)異常的時(shí)候自動(dòng)調(diào)用的
  • afterConnectionClosed:該方法是在websocket連接關(guān)閉后自動(dòng)調(diào)用的
@Component
public class WebSocketAPI extends TextWebSocketHandler {
    @Override //該方法會(huì)在websocket連接成功后被調(diào)用
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        //WebSocketSession是websocket連接對(duì)應(yīng)的會(huì)話
        System.out.println("建立連接了");
    }
    @Override //該方法是在websocket收到消息的時(shí)候自動(dòng)調(diào)用
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        //message 為收到的消息
        System.out.println("發(fā)送消息:"+message.toString());
        //session是個(gè)會(huì)話,里面記錄了通信雙方,通過session對(duì)象調(diào)用send方法實(shí)現(xiàn)服務(wù)器推送消息
        session.sendMessage(message);
        message.getPayload(); //獲取的message字符串
    }
    @Override //該方法是在websocket連接出現(xiàn)異常的時(shí)候自動(dòng)調(diào)用的
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        //exception記錄了異常信息
        System.out.println("連接出現(xiàn)異常了");
    }
    @Override //該方法是在websocket連接關(guān)閉后自動(dòng)調(diào)用的
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        //status 為關(guān)閉的狀態(tài)
        System.out.println("連接關(guān)閉了");
    }
}

創(chuàng)建另一個(gè)類實(shí)現(xiàn)WebSocketConfigurer接口,在類上添加@Configuration,@EnableWebSocket,并重寫registerWebSocketHandlers方法

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Autowired
    private WebSocketAPI webSocketAPI;
    @Override //通過該方法,把創(chuàng)建好的Handler類注冊到具體的路徑上
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        //當(dāng)瀏覽器,websocket的請求路徑是/test的時(shí)候,就會(huì)調(diào)用到webSocketTest中的方法
        registry.addHandler(webSocketAPI,"/websocketMessage");
    }
}

每個(gè)和服務(wù)端建立websocket連接的客戶端,都會(huì)在服務(wù)器這邊有與之對(duì)應(yīng)的WebSocketSession對(duì)象,服務(wù)器要想給誰發(fā)消息,就必須使用誰的WebSocketSession對(duì)象調(diào)用sendMessage方法發(fā)送消息,服務(wù)器向客戶端推送消息使用session.sendMessage(String message)發(fā)送消息,session為每個(gè)服務(wù)器與客戶端建立的websocket會(huì)話WebSocketSession

WebSocketSession如何獲取用戶信息

我們通常需要獲取websocket保存的用戶會(huì)話的用戶信息,那如何獲取到連接用戶的用戶信息呢?

通過注冊特定的HttpSession攔截器,就可以把用戶給HttpSession中添加的Attribute鍵值對(duì),往WebSocketSession中也添加一份

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    @Autowired
    private WebSocketAPI webSocketAPI;
    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(webSocketAPI,"/websocketMessage").
                // 通過注冊特定的HttpSession攔截器,就可以把
                // 用戶給HttpSession中添加的Attribute鍵值對(duì),往WebSocketSession中也添加一份
                addInterceptors(new HttpSessionHandshakeInterceptor());
    }
}

添加完后,可以使用WebSocketSession對(duì)象調(diào)用getAttributes().get("user")方法獲取用戶在HttpSession中保存的用戶信息

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        User user = (User)session.getAttributes().get("user");
        System.out.println("建立連接");
    }

創(chuàng)建管理類管理用戶與會(huì)話

可以使用HashMap來維護(hù)用戶與WebSocketSession的關(guān)系,key為用戶id,value為WebSocketSession對(duì)象,只是此時(shí)使用線程安全的集合類ConcurrentHashMap

@Component
public class WebSocketSessionManage {
    private ConcurrentHashMap<Integer, WebSocketSession> websocketSessions = new ConcurrentHashMap<>();
    //用戶連接,添加連接關(guān)系
    public void addWebSocketSession(Integer userId,WebSocketSession webSocketSession){
        //用戶已經(jīng)上線,防止多開
        if(websocketSessions.containsKey(userId)){
            return;
        }
        websocketSessions.put(userId,webSocketSession);
    }
    //用戶掉線,刪除連接關(guān)系
    public void delWebSocketSession(Integer userId,WebSocketSession webSocketSession){
        WebSocketSession get = websocketSessions.get(userId);
        //只有關(guān)系中存在自己的連接信息,才刪除
        if(get == webSocketSession){
            websocketSessions.remove(userId);
        }
    }
    //根據(jù)用戶id獲取WebSocketSession
    public WebSocketSession getWebSocketSession(Integer userId){
        return websocketSessions.get(userId);
    }
}

客戶端代碼

客戶端使用WebSocket的實(shí)例調(diào)用send方法即可向服務(wù)器發(fā)送消息,發(fā)送的消息一般為json字符串,所以我們可以使用websocket.send(JSON.stringfy(js))將js對(duì)象序列換為json字符串發(fā)送

 //websocket傳輸消息
	 //創(chuàng)建websocket實(shí)例
	let websocket = new WebSocket("ws://" + location.host + "/websocketMessage");
	//綁定一些函數(shù)
	websocket.onopen = function(){
	    console.log('建立連接')
	}
	websocket.onmessage = function(e){
	    //e.data為收到服務(wù)端推送的消息
	    //e.data為一個(gè)json字符串,可以使用JSON.prase(e.data)轉(zhuǎn)換為js對(duì)象
	    let resp = JSON.prase(e.data);
	    console.log('收到消息:'+resp)
	}
	websocket.onerror = function(){
	    console.log('出現(xiàn)異常')
	}
	websocket.onclose = function(){
	    console.log('關(guān)閉連接')
	}
	//使用websocket實(shí)例調(diào)用send方法即可向服務(wù)器發(fā)送消息
	//注意:參數(shù)為字符串,不能為js對(duì)象
	//要發(fā)送json格式的數(shù)據(jù),將json對(duì)象序列化為字符串,JSON.stringfy(json)
	websocket.send("hehe");

到此這篇關(guān)于SpringBoot中使用WebSocket的教程分享的文章就介紹到這了,更多相關(guān)SpringBoot WebSocket內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • ActiveMQ簡單入門(新手必看篇)

    ActiveMQ簡單入門(新手必看篇)

    下面小編就為大家?guī)硪黄狝ctiveMQ簡單入門(新手必看篇)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-06-06
  • Spring-Retry(重試機(jī)制)解讀

    Spring-Retry(重試機(jī)制)解讀

    這篇文章主要介紹了Spring-Retry(重試機(jī)制),具有很好的價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-08-08
  • Java中List集合的常用方法詳解

    Java中List集合的常用方法詳解

    本篇文章給大家?guī)淼膬?nèi)容是關(guān)于Java中List集合的常用方法詳解,有一定的參考價(jià)值,有需要的朋友可以參考一下,希望對(duì)你有所幫助。下面我們就來學(xué)習(xí)一下吧
    2021-11-11
  • 如何解決SpringBoot集成百度UEditor圖片上傳后直接訪問404

    如何解決SpringBoot集成百度UEditor圖片上傳后直接訪問404

    在本篇文章里小編給大家整理的是一篇關(guān)于如何解決SpringBoot集成百度UEditor圖片上傳后直接訪問404相關(guān)文章,需要的朋友們學(xué)習(xí)下。
    2019-11-11
  • java模擬cookie登陸操作

    java模擬cookie登陸操作

    這篇文章主要為大家詳細(xì)介紹了java模擬cookie登陸操作,模擬登陸,取得cookie以記錄身份,下次請求時(shí)發(fā)送cookie以表明身份,感興趣的小伙伴們可以參考一下
    2016-07-07
  • Java使用Apache POI庫讀取Excel表格文檔的示例

    Java使用Apache POI庫讀取Excel表格文檔的示例

    POI庫是Apache提供的用于在Windows下讀寫各類微軟Office文檔的Java庫,這里我們就來看一下Java使用Apache POI庫讀取Excel表格文檔的示例:
    2016-06-06
  • Springboot創(chuàng)建子父工程過程圖解

    Springboot創(chuàng)建子父工程過程圖解

    這篇文章主要介紹了Springboot創(chuàng)建子父工程過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • SpringBoot如何使用MyBatisPlus逆向工程自動(dòng)生成代碼

    SpringBoot如何使用MyBatisPlus逆向工程自動(dòng)生成代碼

    本文介紹如何使用SpringBoot、MyBatis-Plus進(jìn)行逆向工程自動(dòng)生成代碼,并結(jié)合Swagger3.0實(shí)現(xiàn)API文檔的自動(dòng)生成和訪問,通過詳細(xì)步驟和配置,確保Swagger與SpringBoot版本兼容,并通過配置文件和測試類實(shí)現(xiàn)代碼生成和Swagger文檔的訪問
    2024-12-12
  • idea導(dǎo)入jar包的詳細(xì)圖文教程

    idea導(dǎo)入jar包的詳細(xì)圖文教程

    這篇文章主要給大家介紹了關(guān)于idea導(dǎo)入jar包的詳細(xì)圖文教程,文中通過圖文將導(dǎo)入的步驟介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2023-03-03
  • Spring?AOP的注解實(shí)現(xiàn)方式實(shí)例詳解

    Spring?AOP的注解實(shí)現(xiàn)方式實(shí)例詳解

    AOP是一種對(duì)某一類事情集中處理的思想,本文給大家介紹Spring?AOP的注解實(shí)現(xiàn)方式實(shí)例詳解,感興趣的朋友一起看看吧
    2025-04-04

最新評(píng)論

南召县| 嵊泗县| 青铜峡市| 西和县| 湛江市| 涡阳县| 金乡县| 张家口市| 巴东县| 定边县| 收藏| 江源县| 嘉祥县| 镇赉县| 柘荣县| 宜丰县| 民和| 冕宁县| 唐海县| 靖宇县| 怀远县| 永修县| 萨迦县| 石景山区| 柳江县| 桑日县| 百色市| 隆化县| 鄢陵县| 淳安县| 无极县| 诏安县| 海城市| 微山县| 兴文县| 襄城县| 东兰县| 双江| 始兴县| 双城市| 聊城市|