[WebSocket長連接]SpringBoot2.0集成WebSocket,實現后台向前端推送信息


感謝作者,支持原創: https://blog.csdn.net/moshowgame/article/details/80275084

什么是WebSocket?

WebSocket協議是基於TCP的一種新的網絡協議。它實現了瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發送信息給客戶端。

 

為什么需要 WebSocket?

初次接觸 WebSocket 的人,都會問同樣的問題:我們已經有了 HTTP 協議,為什么還需要另一個協議?它能帶來什么好處?

  • 答案很簡單,因為 HTTP 協議有一個缺陷:通信只能由客戶端發起,HTTP 協議做不到服務器主動向客戶端推送信息。

舉例來說,我們想要查詢當前的排隊情況,只能是頁面輪詢向服務器發出請求,服務器返回查詢結果。輪詢的效率低,非常浪費資源(因為必須不停連接,或者 HTTP 連接始終打開)。因此WebSocket 就是這樣發明的。

 

Maven依賴

 1         <!--springboot的高級組件會自動引用基礎的組件-->
 2         <!--,像spring-boot-starter-websocket就引入了spring-boot-starter-web和spring-boot-starter,-->
 3         <!--所以不要重復引入。-->
 4         <!--JavaEE標准-->
 5         <dependency>
 6             <groupId>javax</groupId>
 7             <artifactId>javaee-api</artifactId>
 8             <scope>provided</scope>
 9         </dependency>
10         <!--websocket-->
11         <dependency>
12             <groupId>org.springframework.boot</groupId>
13             <artifactId>spring-boot-starter-websocket</artifactId>
14         </dependency>

 

WebSocket配置類

 1 package com.zr.demo.config;
 2 
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.Configuration;
 5 import org.springframework.web.socket.server.standard.ServerEndpointExporter;
 6 
 7 /**
 8  * @Author: Hujh
 9  * @Date: 2019/7/16 11:10
10  * @Description: WebSocket配置類
11  */
12 @Configuration
13 public class WebSocketConfig {
14 
15     /*使用@ServerEndpoint創立websocket endpoint*/
16     @Bean
17     public ServerEndpointExporter serverEndpointExporter() {
18         return new ServerEndpointExporter();
19     }
20 }

 

WebSocketServer

因為WebSocket是類似客戶端服務端的形式(采用ws協議),那么這里的WebSocketServer其實就相當於一個ws協議的Controller直接@ServerEndpoint("/websocket")@Component啟用即可,然后在里面實現@OnOpen,@onClose,@onMessage等方法

 

  1 package com.zr.demo.socket;
  2 
  3 import org.springframework.stereotype.Component;
  4 
  5 import javax.websocket.OnClose;
  6 import javax.websocket.OnMessage;
  7 import javax.websocket.OnOpen;
  8 import javax.websocket.Session;
  9 import javax.websocket.server.ServerEndpoint;
 10 import java.io.IOException;
 11 import java.util.concurrent.CopyOnWriteArraySet;
 12 
 13 /**
 14  * @Author: Hujh
 15  * @Date: 2019/7/16 11:13
 16  * @Description: webSocket實現類
 17  */
 18 @ServerEndpoint(value = "/webSocket")
 19 @Component
 20 public class WebSocket {
 21     //靜態變量,用來記錄當前在線連接數。應該把它設計成線程安全的。
 22     private static int onlineCount = 0;
 23 
 24     //concurrent包的線程安全Set,用來存放每個客戶端對應的MyWebSocket對象。
 25     private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<WebSocket>();
 26 
 27     //與某個客戶端的連接會話,需要通過它來給客戶端發送數據
 28     private Session session;
 29 
 30     /**
 31      * 連接建立成功調用的方法
 32      */
 33     @OnOpen
 34     public void onOpen(Session session) {
 35         this.session = session;   //加入set中
 36         webSocketSet.add(this);
 37         addOnlineCount();  //在線數加1
 38         System.out.println("有新連接加入!當前在線人數為:" + getOnlineCount());
 39         try {
 40             sendMessage("連接成功");
 41         } catch (IOException e) {
 42             System.out.println("IO異常");
 43         }
 44     }
 45 
 46     /**
 47      * 連接關閉調用的方法
 48      */
 49     @OnClose
 50     public void onClose() {
 51         webSocketSet.remove(this);  //從set中刪除
 52         subOnlineCount();           //在線數減1
 53         System.out.println("有一連接關閉!當前在線人數為" + getOnlineCount());
 54     }
 55 
 56     /**
 57      * 收到客戶端消息后調用的方法
 58      * @param message 客戶端發送過來的消息
 59      */
 60     @OnMessage
 61     public void onMessage(String message, Session session) {
 62         System.out.println("來自客戶端的消息:" + message);
 63 
 64         //群發消息
 65         for (WebSocket item : webSocketSet) {
 66             try {
 67                 item.sendMessage(message);
 68             } catch (IOException e) {
 69                 e.printStackTrace();
 70             }
 71         }
 72     }
 73 
 74     /**
 75      * 發生錯誤時調用
 76      @OnError
 77      */
 78      public void onError(Session session, Throwable error) {
 79      System.out.println("發生錯誤");
 80      error.printStackTrace();
 81      }
 82 
 83     /*
 84      * @Title: sendMessage
 85      * @Author : Hujh
 86      * @Date: 2019/7/17 10:52
 87      * @Description : 發送消息
 88      * @param : message
 89      * @Return : void
 90      */
 91      public void sendMessage(String message) throws IOException {
 92         this.session.getBasicRemote().sendText(message);
 93      //this.session.getAsyncRemote().sendText(message);
 94      }
 95 
 96 
 97      /*
 98       * @Title: sendInfo
 99       * @Author : Hujh
100       * @Date: 2019/7/17 10:52
101       * @Description : 群發自定義消息
102       * @param : message
103       * @Return : void
104       */
105     public static void sendInfo(String message) throws IOException {
106         for (WebSocket item : webSocketSet) {
107             try {
108                 item.sendMessage(message);
109             } catch (IOException e) {
110                 continue;
111             }
112         }
113     }
114 
115     /*
116      * @Title: getOnlineCount
117      * @Author : Hujh
118      * @Date: 2019/7/17 10:51
119      * @Description : 獲得當前在線人數
120      * @param :
121      * @Return : int
122      */
123     public static synchronized int getOnlineCount() {
124         return onlineCount;
125     }
126 
127     /*
128      * @Title: addOnlineCount
129      * @Author : Hujh
130      * @Date: 2019/7/17 10:51
131      * @Description : 在線人數+1
132      * @param :
133      * @Return : void
134      */
135     public static synchronized void addOnlineCount() {
136         WebSocket.onlineCount++;
137     }
138 
139     /*
140      * @Title: subOnlineCount
141      * @Author : Hujh
142      * @Date: 2019/7/17 10:52
143      * @Description :在線人數-1
144      * @param :
145      * @Return : void
146      */
147     public static synchronized void subOnlineCount() {
148         WebSocket.onlineCount--;
149     }
150 
151 }

 

消息推送

至於推送新信息,可以再自己的Controller寫個方法調用WebSocket.sendInfo();

 1 package com.zr.demo.controller;
 2 
 3 import com.zr.demo.socket.WebSocket;
 4 import org.springframework.beans.factory.annotation.Autowired;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RequestParam;
 7 import org.springframework.web.bind.annotation.RestController;
 8 
 9 /**
10  * @Author: Hujh
11  * @Date: 2019/7/19 15:40
12  * @Description: 消息發送控制器
13  */
14 @RestController
15 public class SendMessageController {
16 
17     @Autowired
18     private WebSocket webSocket;
19 
20     @RequestMapping("sendInfo")
21     public String sendInfo(@RequestParam String msg) {
22         try {
23             webSocket.sendInfo(msg);
24         } catch (Exception e) {
25             e.printStackTrace();
26             return "信息發送異常!";
27         }
28 
29         return "發送成功~";
30     }
31 
32 }

 

頁面代碼

 1 <!DOCTYPE HTML>
 2 <html>
 3 <head>
 4     <title>WebSocket</title>
 5 </head>
 6 
 7 <body>
 8 <div style="width: 800px;height: 100%; margin: 0px auto;">
 9     <span style="color: coral; font-size: 22px;"> Welcome WebSocket</span><br/><br/>
10     <div id="message">
11     </div>
12 </div>
13 </body>
14 
15 <script type="text/javascript">
16     var websocket = null;
17     //判斷當前瀏覽器是否支持WebSocket
18     if('WebSocket' in window){
19         websocket = new WebSocket("ws://localhost:8082/webSocket");
20     }else{
21         alert('連接失敗!!')
22     }
23 
24     //連接發生錯誤的回調方法
25     websocket.onerror = function(){
26         setMessageInnerHTML("error");
27     };
28 
29     //連接成功建立的回調方法
30     websocket.onopen = function(event){
31         setMessageInnerHTML("webSocket 連接成功~");
32     }
33 
34     //接收到消息的回調方法
35     websocket.onmessage = function(event){
36         setMessageInnerHTML(event.data);
37     }
38 
39     //連接關閉的回調方法
40     websocket.onclose = function(){
41         setMessageInnerHTML("close");
42     }
43 
44     //監聽窗口關閉事件,當窗口關閉時,主動去關閉websocket連接,
45     // 防止連接還沒斷開就關閉窗口,server端會拋異常。
46     window.onbeforeunload = function(){
47         websocket.close();
48     }
49 
50     //將消息顯示在網頁上
51     function setMessageInnerHTML(innerHTML){
52         document.getElementById('message').innerHTML += innerHTML + '<br/>';
53     }
54 
55     //關閉連接
56     function closeWebSocket(){
57        websocket.close();
58     }
59 
60   61 </script>
62 </html>

 

測試效果

1.建立兩個連接

 

2.消息推送

 

 

 

 注:本文僅作為個人學習記錄,不提供任何參考價值!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM