<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Spring Boot 集成 WebSocket 實現服務端推送消息到客戶端

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

      ajax 輪詢

      在長時間不更新的情況下,反復地去詢問會對服務器造成很大的壓力,對網絡也有很大的消耗,如果定時的時間比較大,服務端有更新的話,客戶端可能需要等待定時器達到以后才能獲知,這個信息也不能很及時地獲取到。

      而有了 WebSocket 協議,就能很好地解決這些問題,WebSocket 可以反向通知的,通常向服務端訂閱一類消息,服務端發現這類消息有更新就會不停地通知客戶端。

      WebSocket

      WebSocket 簡介

      WebSocket 協議是基于 TCP 的一種新的網絡協議,它實現了瀏覽器與服務器全雙工(full-duplex)通信—允許服務器主動發送信息給客戶端,這樣就可以實現從客戶端發送消息到服務器,而服務器又可以轉發消息到客戶端,這樣就能夠實現客戶端之間的交互。對于 WebSocket 的開發,Spring 也提供了良好的支持,目前很多瀏覽器已經實現了 WebSocket 協議,但是依舊存在著很多瀏覽器沒有實現該協議,為了兼容那些沒有實現該協議的瀏覽器,往往還需要通過 STOMP 協議來完成這些兼容。

      下面我們在 Spring Boot 中集成 WebSocket 來實現服務端推送消息到客戶端。

      Spring Boot 集成 WebSocket

      首先創建一個 Spring Boot 項目,然后在 pom.xml 加入如下依賴集成 WebSocket:

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

      開啟配置

      接下來在 config 包下創建一個 WebSocket 配置類 WebSocketConfiguration,在配置類上加入注解 @EnableWebSocket,表明開啟 WebSocket,內部實例化 ServerEndpointExporter 的 Bean,該 Bean 會自動注冊 @ServerEndpoint 注解聲明的端點,代碼如下:

      @Configuration
      @EnableWebSocket
      public class WebSocketConfiguration {
      
          @Bean
          public ServerEndpointExporter serverEndpointExporter() {
              return new ServerEndpointExporter();
          }
      }
      

      編寫端點服務類

      接下來使用 @ServerEndpoint 定義一個端點服務類,在端點服務類中,可以定義 WebSocket 的打開、關閉、錯誤和發送消息的方法,具體代碼如下所示:

      @ServerEndpoint("/websocket/{userId}")
      @Component
      public class WebSocketServer {
      
          private static final Logger log = LoggerFactory.getLogger(WebSocketServer.class);
      
          /**
           * 當前在線連接數
           */
          private static AtomicInteger onlineCount = new AtomicInteger(0);
      
          /**
           * 用來存放每個客戶端對應的 WebSocketServer 對象
           */
          private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
      
          /**
           * 與某個客戶端的連接會話,需要通過它來給客戶端發送數據
           */
          private Session session;
      
          /**
           * 接收 userId
           */
          private String userId = "";
      
          /**
           * 連接建立成功調用的方法
           */
          @OnOpen
          public void onOpen(Session session, @PathParam("userId") String userId) {
              this.session = session;
              this.userId = userId;
              if (webSocketMap.containsKey(userId)) {
                  webSocketMap.remove(userId);
                  webSocketMap.put(userId, this);
              } else {
                  webSocketMap.put(userId, this);
                  addOnlineCount();
              }
              log.info("用戶連接:" + userId + ",當前在線人數為:" + getOnlineCount());
              try {
                  sendMessage("連接成功!");
              } catch (IOException e) {
                  log.error("用戶:" + userId + ",網絡異常!!!!!!");
              }
          }
      
          /**
           * 連接關閉調用的方法
           */
          @OnClose
          public void onClose() {
              if (webSocketMap.containsKey(userId)) {
                  webSocketMap.remove(userId);
                  subOnlineCount();
              }
              log.info("用戶退出:" + userId + ",當前在線人數為:" + getOnlineCount());
          }
      
          /**
           * 收到客戶端消息后調用的方法
           *
           * @param message 客戶端發送過來的消息
           */
          @OnMessage
          public void onMessage(String message, Session session) {
              log.info("用戶消息:" + userId + ",報文:" + message);
              if (!StringUtils.isEmpty(message)) {
                  try {
                      JSONObject jsonObject = JSON.parseObject(message);
                      jsonObject.put("fromUserId", this.userId);
                      String toUserId = jsonObject.getString("toUserId");
                      if (!StringUtils.isEmpty(toUserId) && webSocketMap.containsKey(toUserId)) {
                          webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
                      } else {
                          log.error("請求的 userId:" + toUserId + "不在該服務器上");
                      }
                  } catch (Exception e) {
                      e.printStackTrace();
                  }
              }
          }
      
          /**
           * 發生錯誤時調用
           *
           * @param session
           * @param error
           */
          @OnError
          public void onError(Session session, Throwable error) {
              log.error("用戶錯誤:" + this.userId + ",原因:" + error.getMessage());
              error.printStackTrace();
          }
      
          /**
           * 實現服務器主動推送
           */
          public void sendMessage(String message) throws IOException {
              this.session.getBasicRemote().sendText(message);
          }
      
          public static synchronized AtomicInteger getOnlineCount() {
              return onlineCount;
          }
      
          public static synchronized void addOnlineCount() {
              WebSocketServer.onlineCount.getAndIncrement();
          }
      
          public static synchronized void subOnlineCount() {
              WebSocketServer.onlineCount.getAndDecrement();
          }
      }
      

      其中,@ServerEndpoint("/websocket/{userId}")表示讓 Spring 創建 WebSocket 的服務端點,其中請求地址是 /websocket/{userId}

      另外 WebSocket 一共有四個事件,分別對應 JSR-356 定義的 @OnOpen、@OnMessage、@OnClose、@OnError 注解。

      • @OnOpen:標注客戶端打開 WebSocket 服務端點調用方法
      • @OnClose:標注客戶端關閉 WebSocket 服務端點調用方法
      • @OnMessage:標注客戶端發送消息,WebSocket 服務端點調用方法
      • @OnError:標注客戶端請求 WebSocket 服務端點發生異常調用方法

      接下來啟動項目,使用 WebSocket 在線測試工具(http://www.easyswoole.com/wstool.html)進行測試,有能力的也可以自己寫個 html 測試。

      打開網頁后,在服務地址中輸入ws://127.0.0.1:8080/websocket/wupx,點擊開啟連接按鈕,消息記錄中會多一條由服務器端發送的連接成功!記錄。

      接下來再打開一個網頁,服務地址中輸入ws://127.0.0.1:8080/websocket/huxy,點擊開啟連接按鈕,然后回到第一次打開的網頁在消息框中輸入{"toUserId":"huxy","message":"i love you"},點擊發送到服務端,第二個網頁中會收到服務端推送的消息{"fromUserId":"wupx","message":"i love you","toUserId":"huxy"}

      同樣,項目的日志中也會有相應的日志:

      2020-06-30 12:40:48.894  INFO 78908 --- [nio-8080-exec-1] com.wupx.server.WebSocketServer          : 用戶連接:wupx,當前在線人數為:1
      2020-06-30 12:40:58.073  INFO 78908 --- [nio-8080-exec-2] com.wupx.server.WebSocketServer          : 用戶連接:huxy,當前在線人數為:2
      2020-06-30 12:41:05.870  INFO 78908 --- [nio-8080-exec-3] com.wupx.server.WebSocketServer          : 用戶消息:wupx,報文:{"toUserId":"huxy","message":"i love you"}
      

      總結

      本文簡單地介紹了 Spring Boot 集成 WebSocket 實現服務端主動推送消息到客戶端,是不是十分簡單呢?大家可以自己也寫個 demo 試試!

      本文的完整代碼在 https://github.com/wupeixuan/SpringBoot-Learnwebsocket 目錄下。

      最好的關系就是互相成就,大家的點贊、在看、轉發、留言就是我創作的最大動力。

      參考

      https://github.com/wupeixuan/SpringBoot-Learn

      《深入淺出Spring Boot 2.x》

      posted @ 2020-07-28 10:40  武培軒  閱讀(8303)  評論(1)    收藏  舉報
      主站蜘蛛池模板: 人妻中文字幕不卡精品| 亚洲aⅴ男人的天堂在线观看 | 国产亚洲AV电影院之毛片| 国产精品小仙女自拍视频| 亚洲精品久久久久久下一站| 男女猛烈无遮挡免费视频| 国产福利视频区一区二区| 亚洲综合一区二区三区不卡| 精品国产中文字幕在线| 潮喷无码正在播放| 少妇又爽又刺激视频| 亚洲中文字幕综合小综合| 精品激情视频一区二区三区| 久久久欧美国产精品人妻噜噜| 精品无码久久久久久尤物| 九九热在线精品视频观看| 国产精品午夜福利小视频| 蜜臀视频在线观看一区二区| 亚洲第一精品一二三区| 9191国语精品高清在线| 国产 麻豆 日韩 欧美 久久| 国产成人免费高清激情视频| 国产欧美日韩精品丝袜高跟鞋| 无码乱人伦一区二区亚洲| 日本一区不卡高清更新二区| 久久久久久综合网天天| 北海市| 亚洲暴爽av天天爽日日碰| 亚洲精品中文字幕尤物综合| 免费a级毛片18以上观看精品| 亚洲天天堂天堂激情性色| 国产成人亚洲老熟女精品| 中文在线天堂中文在线天堂| 泰和县| 成人自拍小视频免费观看| 在线天堂最新版资源| 亚洲午夜成人精品电影在线观看| 激情内射亚洲一区二区三区| 韩国精品久久久久久无码| 亚洲爽爆av一区二区| 欧美浓毛大泬视频|