通過實例講解springboot整合WebSocket
一、背景
我們都知道 http 協(xié)議只能瀏覽器單方面向服務(wù)器發(fā)起請求獲得響應(yīng),服務(wù)器不能主動向瀏覽器推送消息。想要實現(xiàn)瀏覽器的主動推送有兩種主流實現(xiàn)方式:
- 輪詢:缺點很多,但是實現(xiàn)簡單
- websocket:在瀏覽器和服務(wù)器之間建立 tcp 連接,實現(xiàn)全雙工通信
springboot 使用 websocket 有兩種方式,一種是實現(xiàn)簡單的 websocket,另外一種是實現(xiàn)STOMP協(xié)議。這一篇實現(xiàn)簡單的 websocket,STOMP 下一篇在講。
注意:如下都是針對使用 springboot 內(nèi)置容器
二、實現(xiàn)
1、依賴引入
要使用 websocket 關(guān)鍵是@ServerEndpoint這個注解,該注解是 javaee 標(biāo)準(zhǔn)中的注解,tomcat7 及以上已經(jīng)實現(xiàn)了,如果使用傳統(tǒng)方法將 war 包部署到 tomcat 中,只需要引入如下 javaee 標(biāo)準(zhǔn)依賴即可:
<dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency>
如使用 springboot 內(nèi)置容器,無需引入,springboot 已經(jīng)做了包含。我們只需引入如下依賴即可:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>1.5.3.RELEASE</version> <type>pom</type> </dependency>
2、注入 Bean
首先注入一個ServerEndpointExporterBean,該 Bean 會自動注冊使用@ServerEndpoint 注解申明的 websocket endpoint。代碼如下:
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
3、申明 endpoint
建立MyWebSocket.java類,在該類中處理 websocket 邏輯
@ServerEndpoint(value = "/websocket") //接受websocket請求路徑 @Component //注冊到spring容器中 public class MyWebSocket { //保存所有在線socket連接 private static Map<String,MyWebSocket> webSocketMap = new LinkedHashMap<>(); //記錄當(dāng)前在線數(shù)目 private static int count=0; //當(dāng)前連接(每個websocket連入都會創(chuàng)建一個MyWebSocket實例 private Session session; private Logger log = LoggerFactory.getLogger(this.getClass()); //處理連接建立 @OnOpen public void onOpen(Session session){ this.session=session; webSocketMap.put(session.getId(),this); addCount(); log.info("新的連接加入:{}",session.getId()); } //接受消息 @OnMessage public void onMessage(String message,Session session){ log.info("收到客戶端{}消息:{}",session.getId(),message); try{ this.sendMessage("收到消息:"+message); }catch (Exception e){ e.printStackTrace(); } } //處理錯誤 @OnError public void onError(Throwable error,Session session){ log.info("發(fā)生錯誤{},{}",session.getId(),error.getMessage()); } //處理連接關(guān)閉 @OnClose public void onClose(){ webSocketMap.remove(this.session.getId()); reduceCount(); log.info("連接關(guān)閉:{}",this.session.getId()); } //群發(fā)消息 //發(fā)送消息 public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } //廣播消息 public static void broadcast(){ MyWebSocket.webSocketMap.forEach((k,v)->{ try{ v.sendMessage("這是一條測試廣播"); }catch (Exception e){ } }); } //獲取在線連接數(shù)目 public static int getCount(){ return count; } //操作count,使用synchronized確保線程安全 public static synchronized void addCount(){ MyWebSocket.count++; } public static synchronized void reduceCount(){ MyWebSocket.count--; } }
4、客戶的實現(xiàn)
客戶端使用 h5 原生 websocket,部分瀏覽器可能不支持。代碼如下:
<html> <head> <title>websocket測試</title> <meta charset="utf-8" /> </head> <body> <button onclick="sendMessage()">測試</button> <script> let socket = new WebSocket("ws://localhost:8080/websocket"); socket.onerror = err => { console.log(err); }; socket.onopen = event => { console.log(event); }; socket.onmessage = mess => { console.log(mess); }; socket.onclose = () => { console.log("連接關(guān)閉"); }; function sendMessage() { if (socket.readyState === 1) socket.send("這是一個測試數(shù)據(jù)"); else alert("尚未建立websocket連接"); } </script> </body> </html>
三、測試
建立一個 controller 測試群發(fā),代碼如下:
@RestController public class HomeController { @GetMapping("/broadcast") public void broadcast(){ MyWebSocket.broadcast(); } }
然后打開上面的 html,可以看到瀏覽器和服務(wù)器都輸出連接成功的信息:
瀏覽器: Event {isTrusted: true, type: "open", target: WebSocket, currentTarget: WebSocket, eventPhase: 2, …} 服務(wù)端: 2018-08-01 14:05:34.727 INFO 12708 --- [nio-8080-exec-1] com.fxb.h5websocket.MyWebSocket : 新的連接加入:0
點擊測試按鈕,可在服務(wù)端看到如下輸出:
2018-08-01 15:00:34.644 INFO 12708 --- [nio-8080-exec-6] com.fxb.h5websocket.MyWebSocket : 收到客戶端2消息:這是一個測試數(shù)據(jù)
再次打開 html 頁面,這樣就有兩個 websocket 客戶端,然后在瀏覽器訪問localhost:8080/broadcast測試群發(fā)功能,每個客戶端都會輸出如下信息:
MessageEvent {isTrusted: true, data: "這是一條測試廣播", origin: "ws://localhost:8080", lastEventId: "", source: null, …}
源碼可在 github 上下載
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- SpringBoot3集成WebSocket的全過程
- SpringBoot整合Netty+Websocket實現(xiàn)消息推送的示例代碼
- springboot整合websocket后啟動報錯(javax.websocket.server.ServerContainer not available)
- SpringBoot 整合WebSocket 前端 uniapp 訪問的詳細方法
- Springboot整合WebSocket實戰(zhàn)教程
- SpringBoot整合WebSocket的客戶端和服務(wù)端的實現(xiàn)代碼
- SpringBoot整合Netty實現(xiàn)WebSocket的示例代碼
- springboot整合websocket最基礎(chǔ)入門使用教程詳解
- SpringBoot3整合WebSocket詳細指南
相關(guān)文章
SpringCloud可視化鏈路追蹤系統(tǒng)Zipkin部署過程
這篇文章主要介紹了SpringCloud可視化鏈路追蹤系統(tǒng)Zipkin部署過程,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03Feign調(diào)用服務(wù)時丟失Cookie和Header信息的解決方案
這篇文章主要介紹了Feign調(diào)用服務(wù)時丟失Cookie和Header信息的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03SpringBoot整合JavaMail實現(xiàn)發(fā)郵件的項目實踐
本文主要介紹了SpringBoot整合JavaMail實現(xiàn)發(fā)郵件的項目實踐,詳細闡述了使用SpringBoot和JavaMail發(fā)送郵件的步驟,具有一定的參考價值,感興趣的可以了解一下2023-10-10解決fastjson從1.1.41升級到1.2.28后報錯問題詳解
這篇文章主要介紹了解決fastjson從1.1.41升級到1.2.28后報錯問題詳解,需要的朋友可以參考下2020-02-02Java實現(xiàn)XML格式與JSON格式互相轉(zhuǎn)換的方法
這篇文章主要介紹了Java實現(xiàn)XML格式與JSON格式互相轉(zhuǎn)換的方法,方法通過實例代碼給大家介紹的非常詳細,選擇使用哪種格式通常取決于項目的需求和上下文,所以格式轉(zhuǎn)換就成了我們必備的技能,具體實現(xiàn)代碼跟隨小編一起看看吧2023-10-10