1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        spring-boot之websocket · 下

        共 15527字,需瀏覽 32分鐘

         ·

        2021-07-31 01:58

        前言

        昨天我們提到,并不是所有的瀏覽器都支持websokcet協(xié)議,對(duì)于不支持的瀏覽器,我們要通過(guò)STOMP協(xié)議來(lái)進(jìn)行兼容,今天我們就來(lái)看下如何通過(guò)STOMP來(lái)兼容websocket。

        websocket兼容

        STOMP的全稱(chēng)是Simple (or Streaming) Text Orientated Messaging Protocol,中文的意思是簡(jiǎn)單(流)文本定向消息協(xié)議,也就是說(shuō),我們其實(shí)使用了消息組件來(lái)兼容的。

        配置類(lèi)

        對(duì)于不支持websocket的瀏覽器我們需要通過(guò)STOMP來(lái)兼容,兼容的解決方案涉及兩方面知識(shí),一個(gè)是SockJs,一個(gè)就是WebSocketMessageBroker。SockJs一種讓前端可以支持socket通信的技術(shù)解決方案,WebSocketMessageBroker是基于消息組件實(shí)現(xiàn)的一種通信協(xié)議。

        下面是我們的STOMP解決方案的配置類(lèi),注釋已經(jīng)夠詳細(xì)了,所以這里就不在贅述。

        @Configuration
        @EnableWebSocketMessageBroker
        public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

            /**
             * 注冊(cè)服務(wù)器端點(diǎn)
             * @param registry
             */

            @Override
            public void registerStompEndpoints(StompEndpointRegistry registry) {
                // 增加一個(gè)聊天服務(wù)端點(diǎn)
                registry.addEndpoint("/socket").withSockJS();
                // 增加一個(gè)用戶(hù)服務(wù)端點(diǎn)
                registry.addEndpoint("/wsuser").withSockJS();
            }

            /**
             * 定義服務(wù)器端點(diǎn)請(qǐng)求和訂閱前綴
             * @param registry
             */

            @Override
            public void configureMessageBroker(MessageBrokerRegistry registry) {
                // 客戶(hù)端訂閱路徑前綴
                registry.enableSimpleBroker("/sub""/queue");
                // 服務(wù)端點(diǎn)請(qǐng)求前綴
                registry.setApplicationDestinationPrefixes("/request");
            }
        }

        消息接收接口

        這里定義兩個(gè)接口,一個(gè)是接收通用消息的(/send),一個(gè)是發(fā)給指定用戶(hù)的(/sendToUser)。這里需要補(bǔ)充說(shuō)明的是,@SendTo注解的作用是將接收到的消息發(fā)送到指定的路由目的地,所有訂閱該消息的用戶(hù)都能收到,屬于廣播。

        @RestController
        public class WebsocketController {
            private final Logger logger = LoggerFactory.getLogger(WebsocketController.class);

            @Autowired
            private SimpMessagingTemplate simpMessagingTemplate;

            @Autowired
            private WebSocketService webSocketService;

            @MessageMapping("/send")
            @SendTo("/sub/chat")
            public String sendMessage(String value) {
                logger.info("發(fā)送消息內(nèi)容:{}", value);
                return value;
            }

            @MessageMapping("/sendToUser")
            public void sendToUser(Principal principal, String body) {
                String srcUser = principal.getName();
                String[] args = body.split(": ");
                String desUser = args[0];
                String message = String.format("【%s】給你發(fā)來(lái)消息:%s", webSocketService.getNameMap().get(srcUser), args[1]);
                // 發(fā)送到用戶(hù)和監(jiān)聽(tīng)地址
                simpMessagingTemplate.convertAndSendToUser(desUser, "/queue/customer", message);

            }

        }

        前端頁(yè)面

        普通消息發(fā)送

        首先要引入jquery.js、stomp.jssockjs.js,這個(gè)三個(gè)js就可以確保前端頁(yè)面也支持STOMP協(xié)議。

        然后我們定義了三個(gè)方法:connect()、disconnect()sendMessage()方法。

        connect方法內(nèi)部,我們通過(guò)SockJS初始化了stompClient實(shí)例,SockJS的節(jié)點(diǎn)地址就是我們配置類(lèi)中定義的聊天服務(wù)節(jié)點(diǎn),然后建立stomp連接。

        發(fā)送消息的時(shí)候,我們直接調(diào)用stomp客戶(hù)端的send方法即可,這里需要指定發(fā)送消息的地址,要和消息接收方的地址一致。

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>websocket STOMP</title>
        </head>
        <body>
        websocket兼容STOMP測(cè)試<br>
        <div>
            <div>
                <button id = "connect" onclick="connect()">連接</button>
                <button id = "disconnect" disabled="disabled" onclick="disconnect()">斷開(kāi)連接</button>
        </div>
            <div id = "conversationDiv">
                <p>
                    <label>發(fā)送消息內(nèi)容</label>
                </p>
                <p>
                    <textarea id="message" rows = "5"></textarea>
                </p>
                <p>
                    <button id = "sendMsg" onclick="sendMessage()">發(fā)送</button>
                </p>
                <p id = "response">

                </p>
            </div>

            <a href="#" target="/websocket-receive">跳轉(zhuǎn)到消息接收頁(yè)</a>
        </div>

        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
        <script type="text/javascript">
            var stompClient = null;
            // 設(shè)置連接
            function setConnected(connected{
                $("#connect").attr({"disabled": connected});
                $("#disconnect").attr({"disabled": !connected});
                if (connected) {
                    $("#conversationDiv").show();
                } else {
                    $("#conversationDiv").hide();
                }
                $("#response").html("")
            }

            function connect({
                // 定義請(qǐng)求服務(wù)器的端點(diǎn)
                var socket = new SockJS('/socket');
                // stomp客戶(hù)端
                stompClient = Stomp.over(socket);
                // 連接服務(wù)器端點(diǎn)
                stompClient.connect({}, function (frame{
                    // 建立連接后的回調(diào)
                    setConnected(true);
                })
            }
            // 斷開(kāi)socket連接
            function disconnect({
                if (stompClient != null) {
                    stompClient.disconnect();
                }
                setConnected(false);
                console.log("Disconnected");
            }
            // 向/request/send服務(wù)端發(fā)送消息
            function sendMessage({
                var message = $("#message").val();
                // 發(fā)送消息到"/request/send",其中/request是服務(wù)器定義的前綴
                // 而/send則是@MessageMapping所配置的路徑
                stompClient.send("/request/send", {}, message);
            }
            connect();
        </script>

        </body>
        </html>
        普通文本消息接收

        接收頁(yè)面和發(fā)送頁(yè)面對(duì)應(yīng),sockJS的地址必須一樣,因?yàn)槭墙邮障?,所以這里執(zhí)行的是stompClientsubscribe(訂閱消息),這里的地址也必須和發(fā)送頁(yè)面一致,否則無(wú)法收到消息

        <!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>websocket-stomp-receive</title>
        </head>
        <body>

        <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
        <script src="https://cdn.bootcdn.net/ajax/libs/stomp.js/2.3.3/stomp.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
        <script type="text/javascript">
            var noticeSocket = function ({
                // 連接服務(wù)器端點(diǎn)
                var s = new SockJS('/socket');
                //客戶(hù)端
                var stompClient = Stomp.over(s);
                stompClient.connect({}, function ({
                    console.log("notice socket connected !");
                    // 訂閱消息地址
                    stompClient.subscribe('/sub/chat'function (data{
                        $('#receive').html(data.body);
                    });
                });
            };
            noticeSocket();
        </script>
        <h1><span id="receive">等待接收消息</span></h1>

        </body>
        </html>
        普通文本測(cè)試

        我登陸了兩個(gè)賬號(hào),用其中一個(gè)賬號(hào)發(fā)送消息,他自己以及另一個(gè)賬號(hào)都收到了發(fā)送的消息,說(shuō)明我們的實(shí)例是ok的。

        下面,我們看下如何給指定用戶(hù)發(fā)送消息。

        給指定用戶(hù)發(fā)送消息

        發(fā)送頁(yè)面沒(méi)有區(qū)別,只是js不一樣,所以這里只貼出js。

        首先第一個(gè)不一樣的地方是服務(wù)端點(diǎn)不一樣了,我們這里的SockJS監(jiān)聽(tīng)的是/wsuser,也就是給指定用戶(hù)發(fā)送消息的地址。

        然后再就是發(fā)送消息的地址也變了,指定的是/request/sendToUser,對(duì)應(yīng)的是指定用戶(hù)的發(fā)送消息的接口,剩下其他的都一模一樣。

        <script type="text/javascript">


            var stompClient = null;
            // 設(shè)置連接
            function setConnected(connected) {
                $("#connect").attr({"disabled": connected});
                $("#disconnect").attr({"disabled": !connected});
                if (connected) {
                    $("#conversationDiv").show();
                } else {
                    $("#conversationDiv").hide();
                }
                $("#response").html("")
            }

            function connect() {
                // 定義請(qǐng)求服務(wù)器的端點(diǎn)
                var socket = new SockJS('/wsuser');
                // stomp客戶(hù)端
                stompClient = Stomp.over(socket);
                // 連接服務(wù)器端點(diǎn)
                stompClient.connect({}, function (frame) {
                    // 建立連接后的回調(diào)
                    setConnected(true);
                })
            }
            // 斷開(kāi)socket連接
            function disconnect() {
                if (stompClient != null) {
                    stompClient.disconnect();
                }
                setConnected(false);
                console.log("Disconnected");
            }
            // 向/request/send服務(wù)端發(fā)送消息
            function sendMessage() {
                var message = $("#message").val();
                var user = $("#user").val();
                // 發(fā)送消息到"/request/send",其中/request是服務(wù)器定義的前綴
                // 而/send則是@MessageMapping所配置的路徑
                var messageSend = user + ": " + message
                stompClient.send("/request/sendToUser", {}, messageSend);
            }
            connect();
        </script>
        給指定用戶(hù)接收頁(yè)面

        這里也只是js發(fā)生變化,節(jié)點(diǎn)名稱(chēng)和發(fā)生頁(yè)面一致,訂閱地址和配置類(lèi)中的一致。

        <script type="text/javascript">
            var noticeSocket = function ({
                // 連接服務(wù)器端點(diǎn)
                var s = new SockJS('/wsuser');
                //客戶(hù)端
                var stompClient = Stomp.over(s);
                stompClient.connect({}, function ({
                    console.log("notice socket connected !");
                    // 訂閱消息地址
                    stompClient.subscribe('/user/queue/customer'function (data{
                        $('#receive').html(data.body);
                    });
                });
            };
            noticeSocket();
        </script>
        給指定用戶(hù)發(fā)送消息測(cè)試

        這次我們用哪吒的賬號(hào)給女?huà)z發(fā)了一條消息,最終的結(jié)果是只有女?huà)z收到了消息,也和我們預(yù)期一致。

        總結(jié)

        相比于昨天我們直接通過(guò)websocket通信,通過(guò)STOMP通信,前端要稍過(guò)復(fù)雜一些,但總體來(lái)說(shuō),也不是特別復(fù)雜。

        通篇來(lái)看,其實(shí)STOMP就是后端啟動(dòng)一個(gè)消息池,然后將消息發(fā)送接口暴露給前端,前端調(diào)用發(fā)送消息接口發(fā)消息,消息由后端轉(zhuǎn)發(fā)到消息池中指定的隊(duì)列(類(lèi)似消息中繼站),然后消費(fèi)者(訂閱該隊(duì)列的消息接收方)接收并消費(fèi)其中的消息。

        如果知道了這點(diǎn),那我們完全可以自己根據(jù)mq的相關(guān)文檔開(kāi)發(fā)一套,而且現(xiàn)在好多mq都提供了對(duì)ajax的支持,比如activemq

        - END -


        瀏覽 18
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日韩精品人妻 | 免费的操逼网 | 精产国品少妇在线视频 | 久久精品国产电影另类稀缺 | 草比视频网 | 台湾三级台湾三级dvd影视 | 国产东北农村女人av | 婷婷丁香五月精品 | 强开小嫩苞一区二区三区图片 | 亚洲爽|