SpringBoot+WebSocket實現消息推送功能
背景
項目中經常會用到消息推送功能,關於推送技術的實現,我們通常會聯想到輪詢、comet長連接技術,雖然這些技術能夠實現,但是需要反復連接,對於服務資源消耗過大,隨著技術的發展,HtML5定義瞭WebSocket協議,能更好的節省服務器資源和帶寬,並且能夠更實時地進行通訊。本文將介紹如何采用websocket實現消息推送。
WebSocket簡介
WebSocket協議是基於TCP的一種新的網絡協議。它實現瞭瀏覽器與服務器全雙工(full-duplex)通信——允許服務器主動發送信息給客戶端。瀏覽器和服務器僅需一次握手,兩者之間就直接可以創建持久性的連接,並進行雙向數據傳輸。
協議原理
Websocket協議基於Http協議,針對Http協議進行瞭相關的改善,且Websocket協議也需要建立TCP連接來實現數據傳輸,具體實現如下圖:
說明:
- 客戶端發起http請求,經過3次握手後,建立起TCP連接;http請求裡存放WebSocket支持的版本號等信息,如:Upgrade、Connection、WebSocket-Version等。
- 服務器收到客戶端的握手請求後,同樣采用HTTP協議回饋數據
- 客戶端收到連接成功的消息後,開始借助於TCP傳輸信道進行全雙工通信.
WebSocket與HTTP協議的區別
相同點:都是一樣基於TCP的,都是可靠性傳輸協議。都是應用層協議。
不同點:
- WebSocket是雙向通信協議,可以雙向發送或接受信息,而HTTP是單向協議
- WebSocket需要瀏覽器和服務器握手進行建立連接的,而http是瀏覽器發起向服務器的連接。
WebSocket特點
- 建立在TCP協議之上,服務器端的實現比較容易。
- 數據格式比較輕量,性能開銷小,通信高效。
- 支持多種數據格式,可以發送文本、二進制數據。
- 客戶端可以與任意服務器通信,無同源限制。
應用場景
- 即時聊天通信
- 在線協同編輯/編輯
- 實時數據流的拉取與推送
- 實時地圖位置
系統集成Websocket
jar包引入
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.4.RELEASE</version> <relativePath/> </parent> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
Websocket配置
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
具體實現
@ServerEndpoint(value="/websocket/{uid}") @Component public class WebSocketServer { private Logger logger = LoggerFactory.getLogger(WebSocketServer.class); private static final AtomicInteger onlineCount = new AtomicInteger(0); private static CopyOnWriteArraySet<Session> sessionSet = new CopyOnWriteArraySet<Session>(); @OnOpen public void onOpen(Session session,@PathParam("uid") String uid) { logger.info("open message uid:{}",uid); sessionSet.add(session); onlineCount.incrementAndGet(); logger.info("窗口開始監聽uid:{},當前在線人數:{}",uid,onlineCount); } @OnClose public void onClose(Session session) { String sessionId=session.getId(); logger.info("sessionid:{} close",sessionId); sessionSet.remove(this); int count=onlineCount.decrementAndGet(); logger.info("有一連接關閉!當前在線人數為:{}",count); } @OnError public void onError(Session session, Throwable error) { logger.error("消息發生錯誤:{},Session ID: {}",error.getMessage(),session.getId()); } public void batchSendMesasge(String uid,String message) throws IOException { logger.info("推送消息到窗口:{},推送內容:{}",uid,message); for(Session session:sessionSet){ sendMessage(session, message); } } public void sendMessage(Session session, String message) throws IOException { if(session!=null) { synchronized (session) { session.getBasicRemote().sendText(message); } } } }
說明: @OnOpen :當有新的WebSocket連接進入時調用 @OnClose:當有WebSocket連接關閉時調用 @OnError :當有WebSocket拋出異常時調用 @OnMessage:當接收到字符串消息時,對該方法進行回調
測試示例
@Controller public class WebScoketController { @Autowired private WebSocketServer webSocketServer; @ResponseBody @RequestMapping("/sendMessage") public String batchMessage(String uid,String message) { Map<String, String> map =new HashMap<String, String>(); try { map.put("code", "200"); webSocketServer.batchSendMesasge(uid,message); } catch (Exception e) { map.put("code", "-1"); map.put("message", e.getMessage()); } return JSON.toJSONString(map); } @GetMapping("/enter") public String enter() { return "webscoketTest.html"; } }
頁面請求websocket
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>websocket test</title> <script type="text/javascript"> if ("WebSocket" in window) { console.log("您的瀏覽器支持 WebSocket!"); var ws = new WebSocket("ws://127.0.0.1:9092/websocket/1234"); console.log('ws連接狀態:' + ws.readyState); //打開 ws.onopen = function() { ws.send("message test"); console.log("mesage sending"); }; //發送消息 ws.onmessage = function (evt) { var received_msg = evt.data; alert(received_msg); }; //關閉 ws.onclose = function() { // 關閉 websocket console.log("socket is close"); }; } else { console.log("您的瀏覽器不支持 WebSocket!"); } </script> </head> </html>
測試效果
啟動程序:運行http://localhost:9092/enter 進入頁面開啟websocket。
用戶發送消息:http://localhost:9092/sendMessage?uid=1235&message=this%20is%20message1
執行的結果如下:
open message uid:1234
[nio-9092-exec-2] c.s.f.w.controller.WebSocketServer: 窗口開始監聽uid:1234,當前在線人數:1
[nio-9092-exec-5] c.s.f.w.controller.WebSocketServer: 推送消息到窗口:1234,推送內容:this is message
以上就是SpringBoot+WebSocket實現消息推送功能的詳細內容,更多關於SpringBoot WebSocket消息推送的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- SpringBoot WebSocket實時監控異常的詳細流程
- SpringBoot集成WebSocket實現後臺向前端推送信息的示例
- springboot簡單接入websocket的操作方法
- 詳解springboot集成websocket的兩種實現方式
- SpringBoot2.0集成WebSocket實現後臺向前端推送信息