国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解

這篇具有很好參考價值的文章主要介紹了spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、WebSocket概述

1、WebSocket簡介

WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議。它實現(xiàn)了瀏覽器與服務(wù)器全雙工(full-duplex)通信——允許服務(wù)器主動發(fā)送信息給客戶端。

2、為什么需要WebSocket

HTTP 是基于請求響應(yīng)式的,即通信只能由客戶端發(fā)起,服務(wù)端做出響應(yīng),無狀態(tài),無連接。

無狀態(tài):每次連接只處理一個請求,請求結(jié)束后斷開連接。
無連接:對于事務(wù)處理沒有記憶能力,服務(wù)器不知道客戶端是什么狀態(tài)。
通過HTTP實現(xiàn)即時通訊,只能是頁面輪詢向服務(wù)器發(fā)出請求,服務(wù)器返回查詢結(jié)果。輪詢的效率低,非常浪費(fèi)資源,因為必須不停連接,或者 HTTP 連接始終打開。

WebSocket的最大特點就是,服務(wù)器可以主動向客戶端推送信息,客戶端也可以主動向服務(wù)器發(fā)送信息,是真正的雙向平等對話。

WebSocket特點:

(1)建立在 TCP 協(xié)議之上,服務(wù)器端的實現(xiàn)比較容易。
(2)與 HTTP 協(xié)議有著良好的兼容性。默認(rèn)端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此握手時不容易屏蔽,能通過各種 HTTP 代理服務(wù)器。
(3)數(shù)據(jù)格式比較輕量,性能開銷小,通信高效。
(4)可以發(fā)送文本,也可以發(fā)送二進(jìn)制數(shù)據(jù)。
(5)沒有同源限制,客戶端可以與任意服務(wù)器通信。
(6)協(xié)議標(biāo)識符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是 URL。

二、SpringBoot整合WebSocket

創(chuàng)建 SpringBoot項目,引入 WebSocket依賴,前端這里比較簡陋。

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
            <version>2.7.12</version>
        </dependency>

application.yml:

server:
  port: 8081

spring:
  thymeleaf:
    mode: HTML
    cache: true
    prefix: classpath:/templates/
    encoding: UTF-8
    suffix: .html
    check-template-location: true
    template-resolver-order: 1

1、WebSocketConfig

啟用 WebSocket的支持也是很簡單。

/**
 * WebSocket配置類。開啟WebSocket的支持
 */
@Configuration
public class WebSocketConfig {

    /**
     * bean注冊:會自動掃描帶有@ServerEndpoint注解聲明的Websocket Endpoint(端點),注冊成為Websocket bean。
     * 要注意,如果項目使用外置的servlet容器,而不是直接使用springboot內(nèi)置容器的話,就不要注入ServerEndpointExporter,因為它將由容器自己提供和管理。
     */
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }

}

2、WebSocketServer
這里就是重點了,核心都在這里。

因為WebSocket是類似客戶端服務(wù)端的形式(采用ws協(xié)議),那么這里的WebSocketServer其實就相當(dāng)于一個ws協(xié)議的Controller
直接@ServerEndpoint("/imserver/{userId}") 、@Component啟用即可,然后在里面實現(xiàn)@OnOpen開啟連接,@onClose關(guān)閉連接,@onMessage接收消息等方法。
新建一個ConcurrentHashMap用于接收當(dāng)前userId的WebSocket或者Session信息,方便IM之間對userId進(jìn)行推送消息。單機(jī)版實現(xiàn)到這里就可以。
集群版(多個ws節(jié)點)還需要借助 MySQL或者 Redis等進(jìn)行訂閱廣播方式處理,改造對應(yīng)的 sendMessage方法即可。

/**
 * WebSocket的操作類
 */
@Component
@Slf4j
/**
 * html頁面與之關(guān)聯(lián)的接口
 * var reqUrl = "http://localhost:8081/websocket/" + cid;
 * socket = new WebSocket(reqUrl.replace("http", "ws"));
 */
@ServerEndpoint("/websocket/{sid}")
public class WebSocketServer {

    /**
     * 靜態(tài)變量,用來記錄當(dāng)前在線連接數(shù),線程安全的類。
     */
    private static AtomicInteger onlineSessionClientCount = new AtomicInteger(0);

    /**
     * 存放所有在線的客戶端
     */
    private static Map<String, Session> onlineSessionClientMap = new ConcurrentHashMap<>();

    /**
     * 連接sid和連接會話
     */
    private String sid;
    private Session session;

    /**
     * 連接建立成功調(diào)用的方法。由前端<code>new WebSocket</code>觸發(fā)
     *
     * @param sid     每次頁面建立連接時傳入到服務(wù)端的id,比如用戶id等??梢宰远x。
     * @param session 與某個客戶端的連接會話,需要通過它來給客戶端發(fā)送消息
     */
    @OnOpen
    public void onOpen(@PathParam("sid") String sid, Session session) {
        /**
         * session.getId():當(dāng)前session會話會自動生成一個id,從0開始累加的。
         */
        log.info("連接建立中 ==> session_id = {}, sid = {}", session.getId(), sid);
        //加入 Map中。將頁面的sid和session綁定或者session.getId()與session
        //onlineSessionIdClientMap.put(session.getId(), session);
        onlineSessionClientMap.put(sid, session);

        //在線數(shù)加1
        onlineSessionClientCount.incrementAndGet();
        this.sid = sid;
        this.session = session;
        sendToOne(sid, "連接成功");
        log.info("連接建立成功,當(dāng)前在線數(shù)為:{} ==> 開始監(jiān)聽新連接:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), sid);
    }

    /**
     * 連接關(guān)閉調(diào)用的方法。由前端<code>socket.close()</code>觸發(fā)
     *
     * @param sid
     * @param session
     */
    @OnClose
    public void onClose(@PathParam("sid") String sid, Session session) {
        //onlineSessionIdClientMap.remove(session.getId());
        // 從 Map中移除
        onlineSessionClientMap.remove(sid);

        //在線數(shù)減1
        onlineSessionClientCount.decrementAndGet();
        log.info("連接關(guān)閉成功,當(dāng)前在線數(shù)為:{} ==> 關(guān)閉該連接信息:session_id = {}, sid = {},。", onlineSessionClientCount, session.getId(), sid);
    }

    /**
     * 收到客戶端消息后調(diào)用的方法。由前端<code>socket.send</code>觸發(fā)
     * * 當(dāng)服務(wù)端執(zhí)行toSession.getAsyncRemote().sendText(xxx)后,前端的socket.onmessage得到監(jiān)聽。
     *
     * @param message
     * @param session
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        /**
         * html界面?zhèn)鬟f來得數(shù)據(jù)格式,可以自定義.
         * {"sid":"user-1","message":"hello websocket"}
         */
        JSONObject jsonObject = JSON.parseObject(message);
        String toSid = jsonObject.getString("sid");
        String msg = jsonObject.getString("message");
        log.info("服務(wù)端收到客戶端消息 ==> fromSid = {}, toSid = {}, message = {}", sid, toSid, message);

        /**
         * 模擬約定:如果未指定sid信息,則群發(fā),否則就單獨(dú)發(fā)送
         */
        if (toSid == null || toSid == "" || "".equalsIgnoreCase(toSid)) {
            sendToAll(msg);
        } else {
            sendToOne(toSid, msg);
        }
    }

    /**
     * 發(fā)生錯誤調(diào)用的方法
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket發(fā)生錯誤,錯誤信息為:" + error.getMessage());
        error.printStackTrace();
    }

    /**
     * 群發(fā)消息
     *
     * @param message 消息
     */
    private void sendToAll(String message) {
        // 遍歷在線map集合
        onlineSessionClientMap.forEach((onlineSid, toSession) -> {
            // 排除掉自己
            if (!sid.equalsIgnoreCase(onlineSid)) {
                log.info("服務(wù)端給客戶端群發(fā)消息 ==> sid = {}, toSid = {}, message = {}", sid, onlineSid, message);
                toSession.getAsyncRemote().sendText(message);
            }
        });
    }

    /**
     * 指定發(fā)送消息
     *
     * @param toSid
     * @param message
     */
    private void sendToOne(String toSid, String message) {
        // 通過sid查詢map中是否存在
        Session toSession = onlineSessionClientMap.get(toSid);
        if (toSession == null) {
            log.error("服務(wù)端給客戶端發(fā)送消息 ==> toSid = {} 不存在, message = {}", toSid, message);
            return;
        }
        // 異步發(fā)送
        log.info("服務(wù)端給客戶端發(fā)送消息 ==> toSid = {}, message = {}", toSid, message);
        toSession.getAsyncRemote().sendText(message);
        /*
        // 同步發(fā)送
        try {
            toSession.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("發(fā)送消息失敗,WebSocket IO異常");
            e.printStackTrace();
        }*/
    }

}

3、controller

controller中只有一個簡單的界面跳轉(zhuǎn)操作,其他的不需要。

@Controller
@RequestMapping("/demo")
public class DemoController {

    /**
     * 跳轉(zhuǎn)到websocketDemo.html頁面,攜帶自定義的cid信息。
     * http://localhost:8081/demo/toWebSocketDemo/user-1
     *
     * @param cid
     * @param model
     * @return
     */
    @GetMapping("/toWebSocketDemo/{cid}")
    public String toWebSocketDemo(@PathVariable String cid, Model model) {
        model.addAttribute("cid", cid);
        return "websocketDemo";
    }

}

4、websocketDemo.html

新建一個文件,放到 templates目錄下面。頁面簡單使用js代碼調(diào)用WebSocket。

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>666666</title>
</head>
<body>
    傳遞來的數(shù)據(jù)值cid:
    <input type="text" th:value="${cid}" id="cid"/>
    <p>【toUserId】:
    <div><input id="toUserId" name="toUserId" type="text" value="user-1"></div>
    <p>【toUserId】:
    <div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
    <p>【操作】:
    <div>
        <button type="button" onclick="sendMessage()">發(fā)送消息</button>
    </div>
</body>

<script type="text/javascript">
    var socket;
    if (typeof (WebSocket) == "undefined") {
        console.log("您的瀏覽器不支持WebSocket");
    } else {
        console.log("您的瀏覽器支持WebSocket");
        //實現(xiàn)化WebSocket對象,指定要連接的服務(wù)器地址與端口  建立連接

        var cid = document.getElementById("cid").value;
        console.log("cid-->" + cid);
        var reqUrl = "http://localhost:8081/websocket/" + cid;
        socket = new WebSocket(reqUrl.replace("http", "ws"));
        //打開事件
        socket.onopen = function () {
            console.log("Socket 已打開");
            //socket.send("這是來自客戶端的消息" + location.href + new Date());
        };
        //獲得消息事件
        socket.onmessage = function (msg) {
            console.log("onmessage--" + msg.data);
            //發(fā)現(xiàn)消息進(jìn)入    開始處理前端觸發(fā)邏輯
        };
        //關(guān)閉事件
        socket.onclose = function () {
            console.log("Socket已關(guān)閉");
        };
        //發(fā)生了錯誤事件
        socket.onerror = function () {
            alert("Socket發(fā)生了錯誤");
            //此時可以嘗試刷新頁面
        }
        //離開頁面時,關(guān)閉socket
        //jquery1.8中已經(jīng)被廢棄,3.0中已經(jīng)移除
        // $(window).unload(function(){
        //     socket.close();
        //});
    }

    function sendMessage() {
        if (typeof (WebSocket) == "undefined") {
            console.log("您的瀏覽器不支持WebSocket");
        } else {
            // console.log("您的瀏覽器支持WebSocket");
            var toUserId = document.getElementById('toUserId').value;
            var contentText = document.getElementById('contentText').value;
            var msg = '{"sid":"' + toUserId + '","message":"' + contentText + '"}';
            console.log(msg);
            socket.send(msg);
        }
    }

</script>
</html>

5、測試運(yùn)行效果

(1)訪問頁面,建立連接

啟動項目,訪問 http://localhost:8081/demo/toWebSocketDemo/{cid} 跳轉(zhuǎn)到頁面,然后就可以和WebSocket交互了。

這里開啟三個瀏覽器的窗口:

http://localhost:8081/demo/toWebSocketDemo/user-1

此時瀏覽器的console顯示如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

此時瀏覽器的network 顯示如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

服務(wù)端打印如下圖所示內(nèi)容:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端
http://localhost:8081/demo/toWebSocketDemo/user-2

此時瀏覽器的network 顯示如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

此時瀏覽器的network 顯示如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

服務(wù)端打印如下圖所示內(nèi)容:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端
http://localhost:8081/demo/toWebSocketDemo/user-3

此時瀏覽器的network 顯示如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

此時瀏覽器的network 顯示如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

服務(wù)端打印如下圖所示內(nèi)容:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

(2)、在user-2給user-1發(fā)消息

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

此時user-2的瀏覽器network里面并沒有再請求接口

?spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

此時查看服務(wù)端的console,截圖如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端?查看user-1的console,如下所示:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

user-1的network并沒有再請求接口。

(3)、給全員發(fā)消息

在user-3頁面,給所有用戶發(fā)消息

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

user-2頁面console如下

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端

user-1頁面的console如下

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端?此時服務(wù)端的console打印如下:

spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解,Spring Boot,spring boot,websocket,后端文章來源地址http://www.zghlxwxcb.cn/news/detail-812133.html

到了這里,關(guān)于spring boot學(xué)習(xí)第六篇:SpringBoot 集成WebSocket詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進(jìn)行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring Boot 集成 WebSocket(原生注解與Spring封裝)

    Spring Boot 集成 WebSocket(原生注解與Spring封裝)

    本章節(jié)將介紹 Spring Boot 集成 WebSocket 的兩種主要方式:原生注解與Spring封裝。 在線WebSocket測試工具 ?? Spring Boot 2.x 實踐案例(代碼倉庫) 引入依賴 配置文件 處理消息 @ServerEndpoint:將目前的類定義成一個websocket服務(wù)器端,注解的值將被用于監(jiān)聽用戶連接的終端訪問URL地址,

    2024年02月02日
    瀏覽(57)
  • Spring Boot集成WebSocket Demo,簡單明了

    Spring Boot集成WebSocket Demo,簡單明了

    如果是初次搭建Spring Boot+WebSocket項目,不需要太復(fù)雜,只需要快速上手,那么你搜到的大部分文章可能都不適合你,我的這篇文章以最精簡的方式搭建一個可以運(yùn)行并通信的Spring Boot+WebSocket的Demo項目,有了根基之后再進(jìn)行復(fù)雜化就不是難事了。 搭建Spring Boot項目都會吧,下面

    2024年02月09日
    瀏覽(15)
  • 【Spring進(jìn)階系列丨第六篇】Spring的Bean管理(基于注解)

    【Spring進(jìn)階系列丨第六篇】Spring的Bean管理(基于注解)

    回顧一下 基于xml配置的Spring對Bean的管理 ,對Bean的完整管理如下所示: 分析可以發(fā)現(xiàn):我們對Bean的管理就四個方面,分別是: 用于創(chuàng)建對象的 用于注入數(shù)據(jù)的 用于改變Bean的作用域的 和Bean的生命周期相關(guān)的 其實對于注解來說,也是包括了這四個方面,換句話說, 使用注

    2024年02月03日
    瀏覽(26)
  • Spring Boot 集成 WebSocket 實現(xiàn)服務(wù)端推送消息到客戶端

    Spring Boot 集成 WebSocket 實現(xiàn)服務(wù)端推送消息到客戶端

    ? ? ? 假設(shè)有這樣一個場景:服務(wù)端的資源經(jīng)常在更新,客戶端需要盡量及時地了解到這些更新發(fā)生后展示給用戶,如果是 HTTP 1.1,通常會開啟 ajax 請求詢問服務(wù)端是否有更新,通過定時器反復(fù)輪詢服務(wù)端響應(yīng)的資源是否有更新。 ? ? ? ? ? ? ? ?? ? ? ? ?在長時間不更新

    2024年02月16日
    瀏覽(87)
  • Java學(xué)習(xí)手冊——第六篇輸入輸出

    Java學(xué)習(xí)手冊——第六篇輸入輸出

    幾乎所有的開發(fā)語言都會有輸入輸出,程序的定義里面也有輸入輸出,可以見得輸入輸出是何等的重要。如果沒有輸入,人類如何與計算機(jī)交流?如果沒有輸出,一切努力都是白費(fèi),因為我們看不到結(jié)果。 這里的輸入輸出你可以簡單的理解為人與人之間的溝通交流,雖然我們

    2024年02月02日
    瀏覽(23)
  • Spring Boot 集成 WebSocket 實例 | 前端持續(xù)打印遠(yuǎn)程日志文件更新內(nèi)容(模擬 tail 命令)

    Spring Boot 集成 WebSocket 實例 | 前端持續(xù)打印遠(yuǎn)程日志文件更新內(nèi)容(模擬 tail 命令)

    這個是我在 CSDN 的第一百篇原則博文,留念?? 先說下項目結(jié)構(gòu),后端基于 Spring Boot 3,前端為 node.js 開發(fā)的控制臺程序?,F(xiàn)在希望能夠在前端模擬 tail 命令,持續(xù)輸出后端的日志文件。 這個方案實施較為簡單,通過前端不斷(定時)發(fā)起請求,并攜帶已讀的內(nèi)容坐標(biāo)(posi

    2024年03月18日
    瀏覽(31)
  • 【夜深人靜學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法 | 第六篇】貪心算法

    【夜深人靜學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)與算法 | 第六篇】貪心算法

    目錄 前言: 引入: 貪心算法:? ?? 455. 分發(fā)餅干 - 力扣(LeetCode) 376. 擺動序列 - 力扣(LeetCode) 53. 最大子數(shù)組和 - 力扣(LeetCode) 122. 買賣股票的最佳時機(jī) II - 力扣(LeetCode) ? ? ? ? 在本文我們將為大家介紹在計算機(jī)中比較常見的一種算法:貪心算法。他并沒有具體的代

    2024年02月09日
    瀏覽(23)
  • spring boot集成Elasticsearch-SpringBoot(25)

    spring boot集成Elasticsearch-SpringBoot(25)

    ??搜索引擎(search engine )通常意義上是指:根據(jù)特定策略,運(yùn)用特定的爬蟲程序從互聯(lián)網(wǎng)上搜集信息,然后對信息進(jìn)行處理后,為用戶提供檢索服務(wù),將檢索到的相關(guān)信息展示給用戶的系統(tǒng)。 ??而我們講解的是捜索的索引和檢索,不涉及爬蟲程序的內(nèi)容爬取。大部分公司

    2023年04月09日
    瀏覽(24)
  • Qt6 Qt Quick UI原型學(xué)習(xí)QML第六篇

    Qt6 Qt Quick UI原型學(xué)習(xí)QML第六篇

    import QtQuick 2.12 :導(dǎo)入QtQuick模塊的版本2.12,用于創(chuàng)建Qt快速應(yīng)用程序的用戶界面。 import QtQuick.Window 2.12 :導(dǎo)入QtQuick.Window模塊的版本2.12,用于創(chuàng)建窗口對象。 import QtQuick.Controls 2.12 :導(dǎo)入QtQuick.Controls模塊的版本2.12,用于創(chuàng)建用戶界面控件。 Window {} :定義了一個窗口對象,

    2024年02月16日
    瀏覽(24)
  • 【SpringBoot3】Spring Boot 3.0 集成 Redis 緩存

    Redis緩存是一個開源的使用ANSIC語言編寫、支持網(wǎng)絡(luò)、可基于內(nèi)存亦可持久化的日志型、Key-Value數(shù)據(jù)庫,并提供多種語言的API。它主要用于作為數(shù)據(jù)庫、緩存和消息中間件,以快速讀寫和豐富的數(shù)據(jù)結(jié)構(gòu)支持而著稱。 在應(yīng)用程序和數(shù)據(jù)庫之間,Redis緩存作為一個中間層起著關(guān)鍵

    2024年02月21日
    瀏覽(90)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包