1. 程式人生 > >Spring整合WebSocket

Spring整合WebSocket

WebSocket,幹什麼用的?我們有了HTTP,為什麼還要用WebSocket?很多同學都會有這樣的疑問。我們先來看一個場景,大家的手機裡都有微信,在微信中,只要有新的訊息,這個聯絡人的前面就會有一個紅點,這個需求要怎麼實現呢?大家思考3秒鐘。哈哈,最簡單,最笨的方法就行客戶端輪詢,在微信的客戶端每隔一段時間(比如:1s或者2s),向服務端傳送一個請求,查詢是否有新的訊息,如果有訊息就顯示紅點。這種方法是不是太笨了呢?每次都要客戶端去發起請求,難道就不能從服務端發起請求嗎?這樣客戶端不就省事了嗎。再看看股票軟體,每個股票的當前價格都是實時的,這我們怎麼做,每個一秒請求後臺查詢當前股票的價格嗎?這樣效率也太低了吧,而且時效性也很低。這就需要我們今天的主角WebSocket去實現了。 ## 什麼是WebSocket WebSocket協議,[RFC 6455](https://tools.ietf.org/html/rfc6455)這個大家有興趣可以看看,太深,太底層。它是通過一個TCP連線,在客服端與服務端之間建立的一個全雙工、雙向的通訊渠道。它是一個不同於HTTP的TCP協議,但是它通過HTTP工作。它的預設埠也是80和443,和HTTP是一樣的。 一個WebSocket的互動開始於一個HTTP請求,這是一個握手請求,這個請求中包含一個Upgrade請求頭,具體如下: ```shell GET /spring-websocket-portfolio/portfolio HTTP/1.1 Host: localhost:8080 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg== Sec-WebSocket-Protocol: v10.stomp, v11.stomp Sec-WebSocket-Version: 13 Origin: http://localhost:8080 ``` 我們看到的第3行和第4行就是這個特殊的請求頭,既然包含了這個特殊的請求頭,那麼請求就要升級,升級成WebSocket請求。這個握手請求的響應也比較特殊,它的成功狀態碼是101,而不是HTTP的200,如下: ```shell HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0= Sec-WebSocket-Protocol: v10.stomp ``` 在這次成功的握手請求以後,在客戶端和服務端之間的socket被開啟,客戶端和服務端可以進行訊息的傳送和接收。 ## 程式實現 我們還是使用現在流程的SpringBoot去搭建我們的專案,在專案中,我們新增兩個依賴,如下: ```xml ``` * spring-boot-starter-websocket,這是我們今天的主角,我們WebSocket的實現都依賴於這個jar包; * spring-boot-starter-thymeleaf,這只是起個輔助作用,在專案中要寫個頁面; 好了,基礎工作準備好了,下面進入最核心的程式碼,先寫個WebSocketHandler,這個是用於在服務端接收和返回訊息使用的。如下: ```java public class MyHandler extends TextWebSocketHandler { @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { String payload = message.getPayload(); System.out.println("我接收到的訊息:"+payload); String rtnMsg = "我回復了"; for (int i=0;i<10;i++) { Thread.sleep(2000); session.sendMessage(new TextMessage(rtnMsg+i)); } super.handleTextMessage(session, message); } } ``` * 我們建立一個MyHandler類,繼承TextWebSocketHandler類,這個類主要是處理文字的,當然也可以繼承其他的類,比如:處理二進位制的BinaryWebSocketHandler; * 然後,我們實現handleTextMessage方法,這個方法有兩個引數,WebSocketSession和TextMessage,TextMessage是接收客戶端發來的訊息。WebSocketSession用於設定WebSocket會話和向客戶端傳送訊息; * 在具體的方法實現中,我們呼叫TextMessage的getPayload方法,可以取出客戶端傳送的訊息; * 最後我們通過WebSocketSession的sendMessage方法向客戶端傳送訊息,這裡進行10次迴圈,每次迴圈我們間隔2秒; 好了,到這裡最核心的處理接收訊息的方法,我們已經寫好了,然後我們將這個handler指定一個URL,如下: ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(),"/websocket"); } @Bean public MyHandler myHandler() { return new MyHandler(); } } ``` * 首先,我們寫一個WebSocket的配置類WebSocketConfig去實現WebSocketConfigurer介面; * 由於這是一個配置類,所以在類上加上註解@Configuration,同時因為要做WebSocket的配置,還要加上@EnableWebSocket這個註解; * 這個類要實現註冊WebSocketHandler的方法registerWebSocketHandlers,在這裡,我們將前面寫的Handler對映到/websocket這個URL; * 例項化前面寫的MyHandler這個類; 到這裡,WebSocket的服務端的內容就寫好了,接下來,我們再寫個簡單的頁面,在頁面中,使用js進行socket的呼叫,具體頁面內容如下: ```html ``` * 我們先寫個div,在這個div中展示服務端返回內容; * 引入jquery,主要進行div內容的操作; * 在第二個script中,我們進行websocket的連線,注意,協議名稱是ws,地址就是我們在WebSocketConfig中配置的地址; * 接下來就是onopen,onmessage,onclose方法,分別對應著socket開啟,接收服務端訊息和socket關閉的方法。我們在onmessage方法中,接收到服務端的訊息,將其新增到div當中。 最後,我們再給這個html頁面寫個controller對映,如下: ```java @Controller public class MyController { @RequestMapping("index") public String index() { return "index"; } } ``` 這個就不過多解釋了,我們啟動一下應用,在瀏覽器中訪問一下這個html頁面吧。 ![](https://img2020.cnblogs.com/blog/1191201/202008/1191201-20200831144202233-1724437390.png) * 我們訪問的連線是:http://localhost:8080/index,這對應我們寫的html頁面; * 在這個頁面中,我們通過js訪問了服務端的websocket; * socket連線成功後,每隔2s向服務端傳送一條訊息; * 在html頁面中,通過onmessage方法接收訊息,並將訊息新增到div當中; 如果使用以前輪詢的方法,我們需要在html頁面中,定時輪詢請求後臺。而現在,我們通過websocket,服務端可以向客戶端傳送訊息,大大提高了效率。 好了,通過Spring整合WebSocket就先給大家介紹到這