SpringCloud整合WebSocket實現用戶監控

来源:https://www.cnblogs.com/folyh/archive/2022/08/13/16513280.html
-Advertisement-
Play Games

@(文章目錄) 前言 一、建項目 1. 在父項目ams-cloud下建立maven子項目ams-websocket 2.pom文件添加常用依賴,另外添加redis依賴等,我這裡直接引用common模塊 <dependencies> <dependency> <groupId>com.alibaba. ...


@

目錄


前言




一、建項目

1. 在父項目ams-cloud下建立maven子項目ams-websocket

在這裡插入圖片描述

2.pom文件添加常用依賴,另外添加redis依賴等,我這裡直接引用common模塊

    <dependencies>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

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

        <dependency>
            <groupId>com.ams</groupId>
            <artifactId>ams-common</artifactId>
            <version>${ams.version}</version>
        </dependency>

    </dependencies>

3.添加bootstrap.yml文件

server:
  port: 21000

spring:
  application:
    name: ams-websocket
  cloud:
    nacos:
      # 註冊中心
      discovery:
        server-addr: http://192.168.132.129:8848
      # 配置中心
      config:
        server-addr: ${spring.cloud.nacos.discovery.server-addr}
        file-extension: yaml
        shared-configs[0]:
          data-id: ams-common.yaml
          refresh: true
          
logging:
  level:
    spring.: DEBUG

4.創建application

@EnableDiscoveryClient
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@ComponentScan("com.ams")
public class WebsocketApp {
    public static void main(String[] args) {
        SpringApplication.run(WebsocketApp.class,args);
    }
}

二、添加config類、攔截器類、處理器類等

1.添加config類


@Configuration
@EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        // 註冊websocket組件 添加處理器和攔截器
        // websocket是websocket伺服器的請求路徑可以自己定義
        registry.addHandler(new WebsocketHandler(redisUtils),"/websocket")
                //指定自定義攔截器
                .addInterceptors(new WebsocketInterceptor(redisUtils))
                //允許跨域
                .setAllowedOrigins("*");

        //在某些低版本的瀏覽器中不支持websocket可以用sock-js替代
        registry.addHandler(new WebsocketHandler(redisUtils),"/sock-js")
                // 指定自定義攔截器
                .addInterceptors(new WebsocketInterceptor(redisUtils))
                // 允許跨域
                .setAllowedOrigins("*")
                // 開啟sockJs支持
                .withSockJS();

    }

}

2.添加攔截器類

@Slf4j
public class WebsocketInterceptor extends HttpSessionHandshakeInterceptor  {

    private final RedisUtils redisUtils;
    public WebsocketInterceptor(RedisUtils redisUtils){
        this.redisUtils=redisUtils;
    }
    
	/** 管理握手過程,存入用戶信息 */
    @Override
    public boolean beforeHandshake(ServerHttpRequest request,
                                   ServerHttpResponse response,
                                   WebSocketHandler handler,
                                   Map<String, Object> map) throws Exception {
        String header_key = "Sec-WebSocket-Protocol";
        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst(header_key);
        log.info("token = [{}]", token);
        HttpHeaders responseHeaders = response.getHeaders();
        UserAuthDTO userAuthDTO = getUserInfo(token);
        if(userAuthDTO == null){
            log.error("socket連接失敗 ---> token過期 ---> [{}]", token);
            response.setStatusCode(HttpStatus.NETWORK_AUTHENTICATION_REQUIRED);
            return false;
        }
        map.put("userAuthDTO",userAuthDTO);
        responseHeaders.add(header_key,token);
        return super.beforeHandshake(request, response, handler, map);

    }

    /** 通過redis讀取用戶信息 **/
    public UserAuthDTO getUserInfo(String token) {
        String key = token;
        if(StrUtil.isEmpty(key)){
            return null;
        }
        UserAuthDTO userAuthDTO = (UserAuthDTO) redisUtils.get(key);
        if(userAuthDTO==null){
            log.error("redis用戶信息空 ---> 登錄過期/token不正確");
            return null;
        }
        return userAuthDTO;
    }
}

3.添加處理器類

@Slf4j
public class WebsocketHandler extends AbstractWebSocketHandler  {

    //定義全局變數用於保存所有用戶的會話
    /** 系統管理員 **/
    public static final Map<String, WebSocketSession> SYSUSER_SOCKETS = new HashMap<>();

    private static RedisUtils redisUtils;
    public WebsocketHandler(RedisUtils redisUtils){
        WebsocketHandler.redisUtils = redisUtils;
    }

    /**
     * webSocket連接創建後調用
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Map<String, Object> attrMap = session.getAttributes();
        UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
        SYSUSER_SOCKETS.put(userAuthDTO.getUserId().toString(),session);
        log.info("管理員[{}]連接成功,當前線上人數[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
    }

    /**
     * 接收到消息會調用
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        try {
       		log.info("收到客戶端消息[{}]", message);
            if(session.isOpen()){
                session.sendMessage(message);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 連接關閉會調用
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        log.info("客戶端關閉連接....");
        Map<String, Object> attrMap = session.getAttributes();
        // 刪除緩存
        deleteSocket(attrMap);
        // 關閉連接
        session.close();
        log.info("已關閉socket連接");
    }

    /**
     * 刪除socket緩存
     */
    public static void deleteSocket(Map<String, Object> attr) {
        UserAuthDTO userAuthDTO = (UserAuthDTO) attr.get("userAuthDTO");
        if (!SYSUSER_SOCKETS.isEmpty()) {
            SYSUSER_SOCKETS.remove(userAuthDTO.getUserId().toString());
            log.info("管理員[{}]關閉連接了,當前線上人數[{}]", userAuthDTO.getUsername(), SYSUSER_SOCKETS.size());
        }
    }

    /**
     * 連接出錯會調用
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("socket連接出錯...");
        exception.printStackTrace();
        Map<String, Object> attrMap = session.getAttributes();
        //刪除緩存
        deleteSocket(attrMap);
        // 關閉連接
        session.close();
        log.error("已關閉socket連接");
    }
}

三、添加controller

1.controller如下:

@RestController
@RequestMapping("/websocket")
@Slf4j
@RequiredArgsConstructor
public class WebsocketController {

    /** 獲取線上管理用戶 */
    @GetMapping(value = "getLoginSysUser")
    public R<List<UserAuthDTO>> getLoginSysUser(){
        Map<String, WebSocketSession> userMap = WebsocketHandler.SYSUSER_SOCKETS;
        List<UserAuthDTO> list = new ArrayList<>();
        userMap.forEach((k,v)->{
            Map<String, Object> attrMap = v.getAttributes();
            UserAuthDTO userAuthDTO = (UserAuthDTO) attrMap.get("userAuthDTO");
            list.add(userAuthDTO);
        });
        return R.ok(list);
    }
    
}


2.運行結果
2022-03-04 16:58:56.822  INFO 15272 --- [nio-21000-exec-2] c.c.f.m.w.config.WebsocketInterceptor    : token = [83868c09-a744-4a7a-a16e-24dc3d7e8cdc]
2022-03-04 16:58:59.335  INFO 15272 --- [nio-21000-exec-2] c.c.f.m.w.handler.WebsocketHandler       : 管理員[admin]連接成功,當前線上人數[1]


*隨心所往,看見未來。Follow your heart,see night!*
**歡迎點贊、關註、留言,一起學習、交流!**

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 最近在做需求的時候,涉及到登錄token,產品提出一個問題:能不能讓token過期時間長一點,我頻繁的要去登錄。 前端:後端,你能不能把token 過期時間設置的長一點。 後端:可以,但是那樣做不安全,你可以用更好的方法。 前端:什麼方法? 後端:給你刷新token的介面,定時去刷新token ...
  • 當微服務是個壞主意時 這篇文章可能是給大家潑冷水,請各位理性看待。從書面上看,微服務聽起來很好。它們是模塊化、可擴展和容錯的。很多公司使用這種模式取得了巨大的成功,所以微服務可能自然而然地成為卓越的架構和啟動新應用程式的最佳方式。然而,大多數利用微服務取得成功的公司並不是從微服務開始的。考慮一下Ai ...
  • 一、環境準備 1.資料庫 創建2個庫2個表: xdclass_shop_order_0 product_order_0 product_order_1 ad_config product_order_item_0 product_order_item_1 xdclass_shop_order_1 p ...
  • 1.什麼是序列化組件 在django中,自帶一個序列化組件,它是用來將數據進行整理、轉化成特定的為一個特定的格式(比如json數據格式),然後傳輸給前端,以便前端對數據進行處理操作。 2.為什麼要用序列化組件 當我們從資料庫取出一些數據時,我們需要將數據轉成特定的格式,比如列表套字典的形式,然後將這 ...
  • @(文章目錄) 提示:本文僅供學習交流,請勿用於非法活動! 前言 本文大概內容: 例如:隨著MongoDB的廣泛應用,電商用到MongoDB也越來越多。本文主要是在將購物車模塊切換到MongoDB框架前,如何快速將Mysql中購物車大批量訂單拷貝到MongoDB資料庫中? 一、原來代碼 如下,我們將 ...
  • 目錄 一.簡介 二.效果演示 三.源碼下載 四.猜你喜歡 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 基礎 零基礎 OpenGL (ES) 學習路線推薦 : OpenGL (ES) 學習目錄 >> OpenGL ES 轉場 零基礎 O ...
  • @(文章目錄) 提示:本文僅供學習交流,請勿用於非法活動! 前言 本文內容: 日誌搭建 一、依賴 <!-- Spring集成日誌包 --> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</arti ...
  • 一、基本 1.hashmap: 1.1 轉紅黑樹條件: a.數組長度大於等於64(預設16,要經過2次擴容--當達到16*預設擴容因數0.75=12就擴容) b.鏈表長度大於8 1.2 hashmap先計算hash值,再用hash值計算下標。 2.sleep與await: 1.1 sleep是線程方 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...