javascript
Spring Boot 集成 WebSocket通信信息推送!
一、什么是websocket?
WebSocket 協議是基于 TCP 的一種新的網絡協議。
它實現了客戶端與服務器之間的全雙工通信,學過計算機網絡都知道,既然是全雙工,就說明了服務器可以主動發送信息給客戶端。
這與我們的推送技術或者是多人在線聊天的功能不謀而合。
為什么不使用 HTTP 協議呢?
這是因為HTTP是單工通信,通信只能由客戶端發起,客戶端請求一下,服務器處理一下,這就太麻煩了。
于是 websocket 應運而生。
下面我們就直接開始使用 Spring Boot 開始整合。以下案例都在我自己的電腦上測試成功,你可以根據自己的功能進行修改即可。
我的項目結構如下:
二、使用步驟
1.添加依賴
Maven 依賴:
<dependency>??<groupId>org.springframework.boot</groupId>??<artifactId>spring-boot-starter-websocket</artifactId>?? </dependency>?2.啟用Springboot對WebSocket的支持
啟用 WebSocket 的支持也是很簡單,幾句代碼搞定。
import?org.springframework.context.annotation.Bean; import?org.springframework.context.annotation.Configuration; import?org.springframework.web.socket.server.standard.ServerEndpointExporter; /***?@?Auther:?馬超偉*?@?Date:?2020/06/16/14:35*?@?Description:?開啟WebSocket支持*/ @Configuration public?class?WebSocketConfig?{@Beanpublic?ServerEndpointExporter?serverEndpointExporter()?{return?new?ServerEndpointExporter();} }3.核心配置:WebSocketServer
因為 Web Socket 是類似客戶端服務端的形式(采用 ws 協議),那么這里的 WebSocketServer 其實就相當于一個 ws 協議的 Controller。
@ServerEndpoint 注解這是一個類層次的注解,它的功能主要是將目前的類定義成一個 websocket 服務器端。注解的值將被用于監聽用戶連接的終端訪問 URL 地址,客戶端可以通過這個 URL 來連接到 WebSocket 服務器端
再新建一個 ConcurrentHashMap webSocketMap 用于接收當前 userId 的 WebSocket,方便傳遞之間對 userId 進行推送消息。
下面是具體業務代碼:
package?cc.mrbird.febs.external.webScoket;import?com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import?com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import?lombok.extern.slf4j.Slf4j; import?org.springframework.stereotype.Component; import?org.springframework.stereotype.Service;import?javax.websocket.*; import?javax.websocket.server.PathParam; import?javax.websocket.server.ServerEndpoint; import?java.io.IOException; import?java.time.LocalDateTime; import?java.util.List; import?java.util.concurrent.CopyOnWriteArraySet;/***?Created?with?IntelliJ?IDEA.*?@?Auther:?馬超偉*?@?Date:?2020/06/16/14:35*?@?Description:*?@?ServerEndpoint?注解是一個類層次的注解,它的功能主要是將目前的類定義成一個websocket服務器端,*?注解的值將被用于監聽用戶連接的終端訪問URL地址,客戶端可以通過這個URL來連接到WebSocket服務器端*/ @Component @Slf4j @Service @ServerEndpoint("/api/websocket/{sid}") public?class?WebSocketServer?{//當前在線連接數private?static?int?onlineCount?=?0;//存放每個客戶端對應的MyWebSocket對象private?static?CopyOnWriteArraySet<WebSocketServer>?webSocketSet?=?new?CopyOnWriteArraySet<WebSocketServer>();private?Session?session;//接收sidprivate?String?sid?=?"";/***?連接建立成功調用的方法*/@OnOpenpublic?void?onOpen(Session?session,?@PathParam("sid")?String?sid)?{this.session?=?session;webSocketSet.add(this);?????//加入set中this.sid?=?sid;addOnlineCount();???????????//在線數加1try?{sendMessage("conn_success");log.info("有新窗口開始監聽:"?+?sid?+?",當前在線人數為:"?+?getOnlineCount());}?catch?(IOException?e)?{log.error("websocket?IO?Exception");}}/***?連接關閉調用的方法*/@OnClosepublic?void?onClose()?{webSocketSet.remove(this);??//從set中刪除subOnlineCount();???????????//在線數減1log.info("釋放的sid為:"+sid);log.info("有一連接關閉!當前在線人數為"?+?getOnlineCount());}/***?收到客戶端消息后調用的方法*?@?Param?message?客戶端發送過來的消息*/@OnMessagepublic?void?onMessage(String?message,?Session?session)?{log.info("收到來自窗口"?+?sid?+?"的信息:"?+?message);//群發消息for?(WebSocketServer?item?:?webSocketSet)?{try?{item.sendMessage(message);}?catch?(IOException?e)?{e.printStackTrace();}}}/***?@?Param?session*?@?Param?error*/@OnErrorpublic?void?onError(Session?session,?Throwable?error)?{log.error("發生錯誤");error.printStackTrace();}/***?實現服務器主動推送*/public?void?sendMessage(String?message)?throws?IOException?{this.session.getBasicRemote().sendText(message);}/***?群發自定義消息*/public?static?void?sendInfo(String?message,?@PathParam("sid")?String?sid)?throws?IOException?{log.info("推送消息到窗口"?+?sid?+?",推送內容:"?+?message);for?(WebSocketServer?item?:?webSocketSet)?{try?{//為null則全部推送if?(sid?==?null)?{ //????????????????????item.sendMessage(message);}?else?if?(item.sid.equals(sid))?{item.sendMessage(message);}}?catch?(IOException?e)?{continue;}}}public?static?synchronized?int?getOnlineCount()?{return?onlineCount;}public?static?synchronized?void?addOnlineCount()?{WebSocketServer.onlineCount++;}public?static?synchronized?void?subOnlineCount()?{WebSocketServer.onlineCount--;}public?static?CopyOnWriteArraySet<WebSocketServer>?getWebSocketSet()?{return?webSocketSet;} }4.測試Controller
import?org.springframework.stereotype.Controller; import?org.springframework.web.bind.annotation.GetMapping; import?org.springframework.web.bind.annotation.PathVariable; import?org.springframework.web.bind.annotation.RequestMapping; import?org.springframework.web.bind.annotation.ResponseBody; import?org.springframework.web.servlet.ModelAndView;import?java.io.IOException; import?java.util.HashMap; import?java.util.Map;/***?Created?with?IntelliJ?IDEA.**?@?Auther:?馬超偉*?@?Date:?2020/06/16/14:38*?@?Description:*/ @Controller("web_Scoket_system") @RequestMapping("/api/socket") public?class?SystemController?{//頁面請求@GetMapping("/index/{userId}")public?ModelAndView?socket(@PathVariable?String?userId)?{ModelAndView?mav?=?new?ModelAndView("/socket1");mav.addObject("userId",?userId);return?mav;}//推送數據接口@ResponseBody@RequestMapping("/socket/push/{cid}")public?Map?pushToWeb(@PathVariable?String?cid,?String?message)?{Map<String,Object>?result?=?new?HashMap<>();try?{WebSocketServer.sendInfo(message,?cid);result.put("code",?cid);result.put("msg",?message);}?catch?(IOException?e)?{e.printStackTrace();}return?result;} }5.測試頁面index.html
<!DOCTYPE?html> <html><head><meta?charset="utf-8"><title>Java 后端 WebSocket 的 Tomcat 實現</title><script?type="text/javascript"?src="js/jquery.min.js"></script></head><body><div?id="main"?style="width:?1200px;height:800px;"></div>Welcome<br/><input?id="text"?type="text"?/><button?onclick="send()">發送消息</button><hr/><button?onclick="closeWebSocket()">關閉WebSocket連接</button><hr/><div?id="message"></div></body><script?type="text/javascript">var?websocket?=?null;//判斷當前瀏覽器是否支持WebSocketif('WebSocket'?in?window)?{websocket?=?new?WebSocket("ws://192.168.100.196:8082/api/websocket/100");}?else?{alert('當前瀏覽器?Not?support?websocket')}//連接發生錯誤回調方法websocket.onerror?=?function()?{setMessageInnerHTML("WebSocket連接發生錯誤");};//連接成功建立回調方法websocket.onopen?=?function()?{setMessageInnerHTML("WebSocket連接成功");}var?U01data,?Uidata,?Usdata//接收消息回調方法websocket.onmessage?=?function(event)?{console.log(event);setMessageInnerHTML(event);setechart()}//連接關閉回調方法websocket.onclose?=?function()?{setMessageInnerHTML("WebSocket連接關閉");}//監聽窗口關閉事件window.onbeforeunload?=?function()?{closeWebSocket();}//將消息顯示在網頁上function?setMessageInnerHTML(innerHTML)?{document.getElementById('message').innerHTML?+=?innerHTML?+?'<br/>';}//關閉WebSocket連接function?closeWebSocket()?{websocket.close();}//發送消息function?send()?{var?message?=?document.getElementById('text').value;websocket.send('{"msg":"'?+?message?+?'"}');setMessageInnerHTML(message?+?" ");}</script></html>6.結果展示
后臺:
如果有連接請求
前臺顯示:
總結
這中間我遇到一個問題,就是說 WebSocket 啟動的時候優先于 spring 容器,從而導致在 WebSocketServer 中調用業務Service會報空指針異常。
所以需要在 WebSocketServer 中將所需要用到的 service 給靜態初始化一下:
如圖所示:
還需要做如下配置:
原文:blog.csdn.net/MacWx/article/details/111319558
版權聲明:本文為CSDN博主「大樹先生.」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
IT技術分享社區 個人博客網站:https://programmerblog.xyz文章推薦程序員效率:畫流程圖常用的工具程序員效率:整理常用的在線筆記軟件遠程辦公:常用的遠程協助軟件,你都知道嗎?51單片機程序下載、ISP及串口基礎知識硬件:斷路器、接觸器、繼電器基礎知識總結
以上是生活随笔為你收集整理的Spring Boot 集成 WebSocket通信信息推送!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: winrar 4.20注册码
- 下一篇: 盘点三个JavaScript案例——实现