SpringBoot實現WebSocket發送接收消息 + Vue實現SocketJs接收發送消息

来源:https://www.cnblogs.com/kakarotto-chen/archive/2023/05/19/17415808.html
-Advertisement-
Play Games

# SpringBoot實現WebSocket發送接收消息 + Vue實現SocketJs接收發送消息 ### 參考: 1、https://www.mchweb.net/index.php/dev/887.html 2、https://itonline.blog.csdn.net/article/d ...


SpringBoot實現WebSocket發送接收消息 + Vue實現SocketJs接收發送消息

參考:

1、https://www.mchweb.net/index.php/dev/887.html

2、https://itonline.blog.csdn.net/article/details/81221103?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-81221103-blog-121078449.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2~default~CTRLIST~default-1-81221103-blog-121078449.pc_relevant_aa&utm_relevant_index=1

3、https://blog.csdn.net/yingxiake/article/details/51224569

使用場景

廣播模式 :使用場景:給所有連接了這個通道的客戶端發送消息。

  • convertAndSend()
  • @SendTo

點對點模式 :使用場景:單獨給當前用戶發送消息。

  • 下麵兩種方式,都預設加了一個首碼:/user

  • convertAndSendToUser()

  • @SendToUser

一、後端SpringBoot + WebSocket基礎配置

1、導包

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

2、配置config

  • 細節:必須配置跨域。低版本的SpringBoot(2.1.5.RELEASE 就不行)不行,需要使用高版本。低版本的解決方案還未找到。
  • 跨域配置使用:.setAllowedOriginPatterns("*")。。不能使用:.setAllowedOrigins("*")
package com.cc.ws.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;

/**
 * <p>@EnableWebSocketMessageBroker 的作用</p>
 * <li>註解開啟使用STOMP協議來傳輸基於代理(message broker)的消息,</li>
 * <li>這時控制器支持使用 @MessageMapping,就像使用 @RequestMapping一樣</li>
 * @author cc
 *
 */
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

    /** <p>啟動簡單Broker</p>
     * <p>表示客戶端訂閱地址的首碼信息,也就是客戶端接收服務端消息的地址的首碼信息</p>
     * <p>代理的名字:都是自定義的</p>
     *
     * /user     點對點(預設也是/user,可以自定義,但是必須和setUserDestinationPrefix中的設置一致)
     * /topic1   廣播模式1
     * /topic2   廣播模式2
     *
     * /mass     廣播模式:群發
     */
    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker(
                "/user", "/topic1", "/topic2", "/mass"
        );
        // 點對點使用的訂閱首碼(客戶端訂閱路徑上會體現出來),不設置的話,預設也是 /user/
        // 註意,這裡必須和上面設置的Broker:/user 一致(兩個都可以自定義,但必須一致)。否則連接不上
        registry.setUserDestinationPrefix("/user/");
        // 指服務端接收地址的首碼,意思就是說客戶端給服務端發消息的地址的首碼
//        registry.setApplicationDestinationPrefixes("/socket");
    }

    /**
     * 這個方法的作用是添加一個服務端點,來接收客戶端的連接。
     * registry.addEndpoint("/socket")表示添加了一個/socket端點,客戶端(前端)就可以通過這個端點來進行連接。
     * withSockJS()的作用是開啟SockJS支持。
     * @param registry registry
     */
    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        // 註冊一個STOMP的endpoint端點,並指定使用SockJS協議
        // 前端使用這個地址連接後端 WebSocket介面
        registry.addEndpoint("/broadcast", "/point")
                // 允許所有源跨域。還可以指定ip配置:http://ip:*
                // 低版本的SpringBoot(2.1.5.RELEASE 就不行)不行
                .setAllowedOriginPatterns("*")
                .withSockJS();
    }

}

3、啟動類,配置定時器

  • @EnableScheduling
@SpringBootApplication
@EnableScheduling
public class WebSocketDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebSocketDemoApplication.class, args);
    }
}

二、前端基礎配置

    let socket1 = new SockJS('http://伺服器ip:伺服器埠/broadcast');
   
    let stompClient1 = Stomp.over(socket1);//廣播模式

    stompClient1.connect({}, (frame) => {
      stompClient1.subscribe('/topic1/', (message) => {
        console.log(message.body);
      });
    });

三、後端不接收,只發送

  • 使用spring Scheduled 定時發送消息

  • 直接使用:SimpMessagingTemplate 的 convertAndSend廣播模式 和 convertAndSendToUser點對點模式

1、後端

  • 註意點對點發送:

convertAndSendToUser的預設首碼(/user)是在WebSocketConfig配置文件中配置的。

代碼:

    @Resource
    private SimpMessagingTemplate simpMsgTemp;

    /** 廣播推送消息1:會發送給所有連接了 topic1 這個通道的客戶端。
     * topic1:在Broker中配置
     **/
    @Scheduled(cron = "0/1 * * * * ?")
    public void getSocket(){
        String msg = String.format("%s 的第 %s 個消息", "topic1", LocalDateTime.now().getSecond());
        log.info("{}",msg);
        simpMsgTemp.convertAndSend("/topic1/", msg);
    }

    /** 廣播推送消息2:多指定一個uri。相當於另一條通道(推薦使用)
     * <li>自定義url尾碼,還可以實現用戶和用戶單點發送。</li>
     * topic2:在Broker中配置
     * custom:是自定義的
     */
    @Scheduled(cron = "0/1 * * * * ?")
    public void getSocketUser(){
        String msg = String.format("topic2 的第 %s 個消息", LocalDateTime.now().getSecond());
        log.info("{}",msg);
        simpMsgTemp.convertAndSend("/topic2/custom" ,msg);
    }

    /**點對點發送 convertAndSendToUser(第一個參數:一般是用戶id)
     *  -> 假如用戶id是1。用用戶id是1的在兩個地方登陸了客戶端(比如不同的瀏覽器登陸同一個用戶),
     *  -> convertAndSendToUser會把消息發送到用戶1登陸的兩個客戶端中
     * 發送到:/user/{userId}/cs 下。cs是自定義的,且必須自定義一個。
     */
    @Scheduled(cron = "0/1 * * * * ?")
    public void pointToPoint(){
        //這個用戶id是後端獲取的當前登陸的用戶id
        String userId = "123";
        String msg = String.format("點對點:第 %s 個消息。用戶id:%s", LocalDateTime.now().getSecond(), userId);
        log.info("{}",msg);
        //發送
        simpMsgTemp.convertAndSendToUser(userId,"/cs/" ,msg);
    }

2、前端

  • 註意點對點的接收方式,用戶id需要取出前端存的用戶id
    //這樣才能同時接收後端來的三套不同通道的消息。
    // broadcast 和後端:registerStompEndpoints中的配置必須一致
    // point     和後端:registerStompEndpoints中的配置必須一致
    // broadcast、point 也可以只用一個,這裡只是為了好區分。
    let socket1 = new SockJS('http://172.16.8.1:8099/broadcast');
    let socket2 = new SockJS('http://172.16.8.1:8099/broadcast');
    let socket3 = new SockJS('http://172.16.8.1:8099/point');
    // console.log("wb:" + socket)

    let stompClient1 = Stomp.over(socket1);
    let stompClient2 = Stomp.over(socket2);
    let stompClient3 = Stomp.over(socket3);

    // ----------------廣播模式1--------------------
    stompClient1.connect({}, (frame) => {
      console.log('-----------frame1', frame)
      stompClient1.subscribe('/topic1/', (message) => {
        console.log(message.body);
        this.msg = message.body;
        // console.log(JSON.parse(message.body));
      });
    });

    // ----------------廣播模式2--------------------
    stompClient2.connect({}, (frame) => {
      console.log('-----------frame2', frame)
      stompClient2.subscribe('/topic2/custom', (message) => {
        console.log(message.body);
        this.user = message.body;
        // console.log(JSON.parse(message.body));
      });
    });

    // ----------------點對點模式--------------------
    //前端獲取的 userId
    let userId = '123';
    //連接WebSocket服務端
    stompClient3.connect({},(frame) => {
      console.log('Connected:' + frame);
      stompClient3.subscribe('/user/' + userId + '/cs/',
          (response) => {
            this.peer = response.body;
      });
    });

四、後端接收、接收後再發送

  • 也可以只接收消息,不發送。看業務需求。
  • 使用 @MessageMapping 接收前端發送過來的消息
  • 使用:@SendTo 廣播模式、@SendToUser 點對點模式
  • 使用:SimpMessagingTemplate 的 convertAndSend廣播模式 和 convertAndSendToUser 點對點模式

1、後端

    @Resource
    private SimpMessagingTemplate simpMsgTemp;

    /** <p>廣播模式一、接收前端的消息,處理後給前端返回一個消息。</p>
     * <li>後端 把消息處理後 發送到 /mass/getResponse 路徑下</li>
     * <ol>
     *     <li>@MessageMapping("/massRequest1") :作用:接收前端來的消息。類似於@RestController</li>
     *     <li>@SendTo("/mass/getResponse1"):作用跟convertAndSend類似,廣播發給與該通道相連的客戶端。SendTo 發送至 Broker 下的指定訂閱路徑 </li>
     *     <li>@SendToUser("/mass/getResponse1"):作用跟convertAndSendToUser類似,定點發送。SendTo 發送至 Broker 下的指定訂閱路徑 </li>
     *     <li>/mass 必須在配置文件配置</li>
     *     <li>/getResponse1 自定義的尾碼</li>
     * </ol>
     */
    @MessageMapping("/massRequest1")
    @SendTo("/mass/getResponse1")
    public String mass1(String chatRoomRequest){
        //處理前端消息……
        log.info("前端消息:{}",chatRoomRequest);
        //返回消息
        return "@SendTo 廣播一(單次) 後端處理完成!";
    }

    /** 廣播模式二、接收前端的消息,可以多次給前端發消息
     * <li>/mass 必須在配置文件配置</li>
     * <li>/getResponse2 自定義的尾碼</li>
     */
    @MessageMapping("/massRequest2")
    public void mass2(String chatRoomRequest){
        log.info("前端的消息:{}",chatRoomRequest);

        for (int i = 0; i < 5; i++) {
            String msg = "後端處理後的 廣播二(多次):" + i;
            simpMsgTemp.convertAndSend("/mass/getResponse2", msg);
        }
        simpMsgTemp.convertAndSend("/mass/getResponse2",
                "後端處理後的 廣播二(多次),後端處理完成!");
    }

    /** <p>點對點一、接收前端消息,只能返回一次消息(必須登陸系統才能使用。)</p>
     * <li>只有發送原始消息的客戶端才會收到響應消息,而不是所有連接的客戶端都會收到響應消息。</li>
     * <li>/alone/getResponse1:自定義的,不需要在配置文件配置。</li>
     *
     * <p>@SendToUser</p>
     * <li>預設該註解首碼為 /user</li>
     * <li>broadcast屬性,表明是否廣播。就是當有同一個用戶登錄多個session時,是否都能收到。取值true/false.</li>
     *
     * @param principal Principal :登陸用戶的信息,需要使用spring s安全框架寫入信息?
     */
    @MessageMapping("/aloneRequest1")
    @SendToUser("/alone/getResponse1")
    public String alone1(String chatRoomRequest){
        //處理前端消息……
        log.info("前端消息:{}",chatRoomRequest);
        //返回消息
        return "@SendToUser 點對點一(單次) 後端處理完成!";
    }

    /** 點對點二、接收前端消息,可以多次給前端發消息
     * <li>convertAndSendToUser —— 發送消息給指定用戶id的</li>
     * <li>如果用戶1在兩個地方(A/B)登陸可以客戶端,並且連接了該通道,其中一個如A給後端發消息,後端返回消息,A/B兩個地方都會收到消息</li>
     * <ol>
     *     <li>@MessageMapping("/aloneRequest2") 接收前端指定用戶消息,</li>
     *     <li>/alone/getResponse2 不用在配置文件中配置</li>
     *     <li>返回消息 發送到 user/{userId}/alone/getResponse2 下 (定點發送)</li>
     * </ol>
     */
    @MessageMapping("/aloneRequest2")
    public void alone2(String chatRoomRequest){
        //後端獲取的當前登陸的用戶的id(和前端一致)
        String userId = "456";
        log.info("前端的消息:{}",chatRoomRequest);

        for (int i = 0; i < 5; i++) {
            String msg = "後端處理後的 點對點二(多次):" + i;
            simpMsgTemp.convertAndSendToUser(userId,"/alone/getResponse2", msg);
        }
        simpMsgTemp.convertAndSendToUser(userId,"/alone/getResponse2",
                "後端處理後的 點對點二(多次),後端處理完成!");
    }

2、前端

  • 3點對點一 未實現。
    //連接SockJS的 broadcast
    let socket1 = new SockJS('http://172.16.8.7:8099/broadcast');
    let socket2 = new SockJS('http://172.16.8.7:8099/broadcast');
    let socket3 = new SockJS('http://172.16.8.7:8099/point');
    let socket4 = new SockJS('http://172.16.8.7:8099/point');
    //使用STMOP子協議的WebSocket客戶端
    let stompClient1 = Stomp.over(socket1);
    let stompClient2 = Stomp.over(socket2);
    let stompClient3 = Stomp.over(socket3);
    let stompClient4 = Stomp.over(socket4);

    //1廣播模式一
    stompClient1.connect({},(frame) => {
      console.log('廣播模式一:' + frame);
      //1發送消息
      stompClient1.send("/massRequest1",{},"我是前端來 廣播模式一 的消息!");

      //2接收消息
      stompClient1.subscribe('/mass/getResponse1',(response) => {
        this.broadcast1 = response.body
      });
    });

    //2廣播模式二
    stompClient2.connect({},(frame) => {
      console.log('廣播模式二:' + frame);
      //1發送消息
      stompClient2.send("/massRequest2",{},"我是前端來 廣播模式二 的消息");

      //2接收消息
      stompClient2.subscribe('/mass/getResponse2',(response) => {
        this.broadcast2 = response.body
      });
    });

    //3點對點一 :必須登陸系統才能實現。要往:Principal設置用戶登陸信息才行
    //1發送消息
    // stompClient3.send("/aloneRequest1",{},"我是前端來 點對點一 的消息");
    stompClient3.connect({},(frame) => {
      console.log('點對點一1:' + frame);
      stompClient3.send("/aloneRequest1",{},"我是前端來 點對點一 的消息");
      //2接收消息
      stompClient3.subscribe('/user/alone/getResponse1' ,(response) => {
        console.log('-------response.body', response.body)
        this.point1 = response.body
      });
    });

    //4點對點二:必須獲取現在登陸了的用戶id,且必須和後端一致才行。
    stompClient4.connect({},(frame) => {
      console.log('點對點二:' + frame);
      //1發送消息
      stompClient4.send("/aloneRequest2",{},"我是前端來 點對點二 的消息");

      //2接收消息
      //前端獲取的當前登陸的用戶userId(和後端一致)
      let userId = '456';
      stompClient4.subscribe('/user/'+userId+'/alone/getResponse2',(response) => {
        this.point2 = response.body
      });
    });

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

-Advertisement-
Play Games
更多相關文章
  • 馬上就要520了,也許你能用到這款《文生圖》工具!把字藏在圖裡,發給女神,大膽去表白吧~,文末附源碼喲!預覽地址:https://dombro.site/tools#/text-image ...
  • 當定義和調用函數時,JavaScript 函數對象會自動具有一些特定的屬性,以下是一些常見的屬性和方法。 1. arguments : arguments 是一個類數組對象,它包含了函數調用時傳遞的參數。它允許你在函數內部訪問傳遞給函數的參數列表,即使在函數定義時未明確聲明這些參數。可以通過索引訪問 ...
  • 關於JWT,可以說是分散式系統下的一個利器,我在我的很多項目實踐中,認證系統的第一選擇都是JWT。它的優勢會讓你欲罷不能,就像你領優惠券一樣。 ...
  • 有很多人問過我,學習開源項目消息推送平臺austin需要有什麼基礎,我往往會回答:**有`SpringBoot`基礎就夠了**。 我在幾年前總結過從零學習`Java`的路線,現在看來也沒有很過時: - `Java`基礎:流程式控制制-->面向對象(包括語法)-->集合-->`IO`流-->異常-->多線 ...
  • # C++ 如何快速實現一個容器的迭代器 ## 引言 C++的標準庫中的容器都會提供迭代器,如果一個容器滿足forward_range,那麼這個容器一般會提供以下成員類型和函數: - iterator - const_iterator - begin - end - begin - cend 如果該 ...
  • pom引入:有MP了就不要再引入mybatis了,會出bug的 ```xml com.baomidou mybatis-plus-boot-starter 3.5.3.1 com.baomidou mybatis-plus-generator 3.5.3.1 junit junit 4.13.2 ` ...
  • - [c++函數參數和返回值](#c函數參數和返回值) - [函數存儲位置](#函數存儲位置) - [函數參數入棧順序](#函數參數入棧順序) - [初始化列表](#初始化列表) - [函數的返回值](#函數的返回值) - [用參數引用來返回](#用參數引用來返回) - [返回一個參數指針](#返回 ...
  • ## 一、環境介紹 * JDK 1.8+ * EasyExcel 2.2.7 ## 二、功能實現 此功能可以實現根據傳入自定義的 導出實體類或Map 進行excel文件導出。若根據Map導出,導出列的順序可以自定義。 **話不多說,直接看代碼** ### 導出實體類 點擊查看代碼 ``` impor ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...