Springboot整合WebSocket實(shí)戰(zhàn)教程
1.WebSocket 簡(jiǎn)介
WebSocket是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡(jiǎn)單,允許服務(wù)端主動(dòng)向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。
WebSocket特點(diǎn):
1.建立在 TCP 協(xié)議之上,服務(wù)器端的實(shí)現(xiàn)比較容易。
2.與 HTTP 協(xié)議有著良好的兼容性。默認(rèn)端口也是80和443,并且握手階段采用 HTTP 協(xié)議,因此3.握手時(shí)不容易屏蔽,能通過各種HTTP 代理服務(wù)器。
4.數(shù)據(jù)格式比較輕量,性能開銷小,通信高效。
5.可以發(fā)送文本,也可以發(fā)送二進(jìn)制數(shù)據(jù)。
6.沒有同源限制,客戶端可以與任意服務(wù)器通信。
7.協(xié)議標(biāo)識(shí)符是ws(如果加密,則為wss),服務(wù)器網(wǎng)址就是 URL。
HTTP缺點(diǎn):通過反復(fù)的輪訓(xùn)去查看資源是否有更新,對(duì)網(wǎng)絡(luò)和資源有很大的消耗
websocket可以反向通知,雙向通訊
2.WebSocket 實(shí)戰(zhàn)
導(dǎo)入依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
配置類
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
WebSocketServer類
@Component @ServerEndpoint("/websocket/{userId}") public class WebSocketServer { /** * 日志工具 */ protected static final Logger logger= LoggerFactory.getLogger(WebSocketServer.class); /** * 與某個(gè)客戶端的連接會(huì)話,需要通過它來給客戶端發(fā)送數(shù)據(jù) */ private Session session; /** * 用戶id */ private String userId; /** * 用來存放每個(gè)客戶端對(duì)應(yīng)的MyWebSocket對(duì)象 */ private static CopyOnWriteArraySet<WebSocketServer> webSockets = new CopyOnWriteArraySet<>(); /** * 用來存在線連接用戶信息 */ private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<String, Session>(); /** * 鏈接成功調(diào)用的方法 */ @OnOpen public void onOpen(Session session, @PathParam(value = "userId") String userId) { try { this.session = session; this.userId = userId; webSockets.add(this); sessionPool.put(userId, session); logger.info("有新的客戶連接,總數(shù)為:" + webSockets.size()); } catch (Exception e) { } } /** * 鏈接關(guān)閉調(diào)用的方法 */ @OnClose public void onClose() { try { webSockets.remove(this); sessionPool.remove(this.userId); logger.info("【websocket消息】連接斷開,總數(shù)為:" + webSockets.size()); } catch (Exception e) { } } /** * 收到客戶端消息后調(diào)用的方法 */ @OnMessage public void onMessage(String message) { logger.info("【websocket消息】收到客戶端消息:" + message); } /** * 發(fā)送錯(cuò)誤時(shí)的處理 * * @param session * @param error */ @OnError public void onError(Session session, Throwable error) { logger.info("用戶錯(cuò)誤,原因:" + error.getMessage()); error.printStackTrace(); } /** * 此為廣播消息 */ public void sendAllMessage(String message) { logger.info("【websocket消息】廣播消息:" + message); for (WebSocketServer webSocket : webSockets) { try { if (webSocket.session.isOpen()) { webSocket.session.getAsyncRemote().sendText(message); } } catch (Exception e) { e.printStackTrace(); } } } /** * 此為單點(diǎn)消息 */ public void sendOneMessage(String userId, String message) { Session session = sessionPool.get(userId); if (session != null && session.isOpen()) { try { logger.info("【websocket消息】 單點(diǎn)消息:" + message); session.getAsyncRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } /** * 此為單點(diǎn)消息(多人) */ public void sendMoreMessage(String[] userIds, String message) { for (String userId : userIds) { Session session = sessionPool.get(userId); if (session != null && session.isOpen()) { try { logger.info("【websocket消息】 單點(diǎn)消息:" + message); session.getAsyncRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } } }
服務(wù)端發(fā)送消息實(shí)例
@GetMapping("/hello") public void hello(){ JSONObject jsonObject=new JSONObject(); jsonObject.put("key","hello"); webSocketServer.sendAllMessage(JSONObject.toJSONString(jsonObject)); }
客戶端
<html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" rel="external nofollow" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite + Vue</title> </head> <body> <p>【socket開啟者的ID信息】:<div><input id="userId" name="userId" type="text" value="10"></div> <div><input id="contentText" name="contentText" type="text" value="hello websocket"></div> <p>【操作】:<button><a onclick="openSocket()">發(fā)送消息</a></button> </body> <script> let socket; function openSocket() { const socketUrl = "ws://localhost:8080/websocket/"+$("#userId").val(); socket = new WebSocket(socketUrl); //打開事件 socket.onopen = function() { console.log("websocket已打開"); socket.send('{"toUserId":"'+$("#userId").val()+'","contentText":"'+$("#contentText").val()+'"}'); console.log('{"toUserId":"'+$("#userId").val()+'","contentText":"'+$("#contentText").val()+'"}'); }; //獲得消息事件 socket.onmessage = function(msg) { console.log(msg.data); //發(fā)現(xiàn)消息進(jìn)入,開始處理前端觸發(fā)邏輯 }; //關(guān)閉事件 socket.onclose = function() { console.log("websocket已關(guān)閉"); }; //發(fā)生了錯(cuò)誤事件 socket.onerror = function() { console.log("websocket發(fā)生了錯(cuò)誤"); } } </script> </html>
到此這篇關(guān)于Springboot整合WebSocket實(shí)戰(zhàn)的文章就介紹到這了,更多相關(guān)Springboot整合WebSocket內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot整合Netty+Websocket實(shí)現(xiàn)消息推送的示例代碼
- springboot整合websocket后啟動(dòng)報(bào)錯(cuò)(javax.websocket.server.ServerContainer not available)
- SpringBoot 整合WebSocket 前端 uniapp 訪問的詳細(xì)方法
- SpringBoot整合WebSocket的客戶端和服務(wù)端的實(shí)現(xiàn)代碼
- SpringBoot中HttpSessionListener的簡(jiǎn)單使用方式
- 空指針HttpSession異常之SpringBoot集成WebSocket的方法
相關(guān)文章
如何使用@ConditionalOnExpression決定是否生效注釋
這篇文章主要介紹了如何使用@ConditionalOnExpression決定是否生效注釋的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Spring Boot使用JSR-380進(jìn)行校驗(yàn)的示例
這篇文章主要介紹了Spring Boot使用JSR-380進(jìn)行校驗(yàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03SpringBoot根據(jù)各地區(qū)時(shí)間設(shè)置接口有效時(shí)間的實(shí)現(xiàn)方式
這篇文章給大家介紹了SpringBoot根據(jù)各地區(qū)時(shí)間設(shè)置接口有效時(shí)間的實(shí)現(xiàn)方式,文中通過代碼示例給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2024-01-01java數(shù)組、泛型、集合在多態(tài)中的使用及對(duì)比
本文主要介紹了java數(shù)組、泛型、集合在多態(tài)中的使用及對(duì)比。具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-03-03Java中ArrayList和LinkedList的遍歷與性能分析
這篇文章主要給大家介紹了ArrayList和LinkedList這兩種list的五種循環(huán)遍歷方式,各種方式的性能測(cè)試對(duì)比,根據(jù)ArrayList和LinkedList的源碼實(shí)現(xiàn)分析性能結(jié)果,總結(jié)結(jié)論。相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考價(jià)值,有需要的朋友們下面跟著小編一起來學(xué)習(xí)學(xué)習(xí)吧。2016-12-12SpringCloud之熔斷器Hystrix的實(shí)現(xiàn)
這篇文章主要介紹了SpringCloud之熔斷器Hystrix的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08spring boot加載freemarker模板路徑的方法
這篇文章主要介紹了spring boot加載freemarker模板路徑的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11WebSocket獲取httpSession空指針異常的解決辦法
這篇文章主要介紹了在使用WebSocket實(shí)現(xiàn)p2p或一對(duì)多聊天功能時(shí),如何獲取HttpSession來獲取用戶信息,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友一起看看吧2025-01-01