<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          spring-boot之websocket · 下

          共 15527字,需瀏覽 32分鐘

           ·

          2021-07-31 01:58

          前言

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

          websocket兼容

          STOMP的全稱是Simple (or Streaming) Text Orientated Messaging Protocol,中文的意思是簡單(流)文本定向消息協(xié)議,也就是說,我們其實使用了消息組件來兼容的。

          配置類

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

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

          @Configuration
          @EnableWebSocketMessageBroker
          public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {

              /**
               * 注冊服務器端點
               * @param registry
               */

              @Override
              public void registerStompEndpoints(StompEndpointRegistry registry) {
                  // 增加一個聊天服務端點
                  registry.addEndpoint("/socket").withSockJS();
                  // 增加一個用戶服務端點
                  registry.addEndpoint("/wsuser").withSockJS();
              }

              /**
               * 定義服務器端點請求和訂閱前綴
               * @param registry
               */

              @Override
              public void configureMessageBroker(MessageBrokerRegistry registry) {
                  // 客戶端訂閱路徑前綴
                  registry.enableSimpleBroker("/sub""/queue");
                  // 服務端點請求前綴
                  registry.setApplicationDestinationPrefixes("/request");
              }
          }

          消息接收接口

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

          @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ā)來消息:%s", webSocketService.getNameMap().get(srcUser), args[1]);
                  // 發(fā)送到用戶和監(jiān)聽地址
                  simpMessagingTemplate.convertAndSendToUser(desUser, "/queue/customer", message);

              }

          }

          前端頁面

          普通消息發(fā)送

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

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

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

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

          <!DOCTYPE html>
          <html lang="en">
          <head>
              <meta charset="UTF-8">
              <title>websocket STOMP</title>
          </head>
          <body>
          websocket兼容STOMP測試<br>
          <div>
              <div>
                  <button id = "connect" onclick="connect()">連接</button>
                  <button id = "disconnect" disabled="disabled" onclick="disconnect()">斷開連接</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)到消息接收頁</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;
              // 設置連接
              function setConnected(connected{
                  $("#connect").attr({"disabled": connected});
                  $("#disconnect").attr({"disabled": !connected});
                  if (connected) {
                      $("#conversationDiv").show();
                  } else {
                      $("#conversationDiv").hide();
                  }
                  $("#response").html("")
              }

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

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

          接收頁面和發(fā)送頁面對應,sockJS的地址必須一樣,因為是接收消息,所以這里執(zhí)行的是stompClientsubscribe(訂閱消息),這里的地址也必須和發(fā)送頁面一致,否則無法收到消息

          <!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 ({
                  // 連接服務器端點
                  var s = new SockJS('/socket');
                  //客戶端
                  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>
          普通文本測試

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

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

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

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

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

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

          <script type="text/javascript">


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

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

          這里也只是js發(fā)生變化,節(jié)點名稱和發(fā)生頁面一致,訂閱地址和配置類中的一致。

          <script type="text/javascript">
              var noticeSocket = function ({
                  // 連接服務器端點
                  var s = new SockJS('/wsuser');
                  //客戶端
                  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>
          給指定用戶發(fā)送消息測試

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

          總結(jié)

          相比于昨天我們直接通過websocket通信,通過STOMP通信,前端要稍過復雜一些,但總體來說,也不是特別復雜。

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

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

          - END -


          瀏覽 18
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  伊人大香蕉电影网 | 黄在线观看网站 | 欧美国产日韩色图 | 91精品国产综合久久久蜜臀酒店 | 18禁91|