Java實(shí)現(xiàn)使用Websocket發(fā)送消息詳細(xì)代碼舉例
前言
- 需求背景:之前做了個(gè)樓棟房間數(shù)量出租了多少,需要在數(shù)據(jù)大屏上實(shí)時(shí)展示
- 解決方案:以切面攔截出租接口,當(dāng)有房間出租時(shí)重新查詢相關(guān)數(shù)據(jù),封裝好用websocket實(shí)時(shí)傳送前端展示
一、websocket 簡介
WebSocket 是一種在單個(gè)TCP連接上進(jìn)行全雙工通信的協(xié)議。WebSocket 使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進(jìn)行雙向數(shù)據(jù)傳輸。
二、websocket 如何使用
1.引入依賴包
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
2.創(chuàng)建 WebSocketConfig
package com.alpari.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** * @author wangrui * @date 2023/11/8 **/ @Configuration @EnableWebSocket public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpoint() { return new ServerEndpointExporter(); } /** * 注意事項(xiàng): * WebSocket啟動的時(shí)候優(yōu)先于spring容器,從而導(dǎo)致在WebSocketServer中調(diào)用業(yè)務(wù)Service會報(bào)空指針異常 * 所以需要在WebSocketServer中將所需要用到的service給靜態(tài)初始化一下 * 此處提前注入 */ // @Autowired // private void setXxx(XxxService xxxService) { // WebSocketServer.xxxService = xxxService; // } }
3.創(chuàng)建 WebSocketServer
package com.alpari.config; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; /** * @author wangrui * @date 2023/11/8 * @description: 若在此類中直接調(diào)用service方法失敗,需要加上:public static XxxService xxxService; 另外在config中注入實(shí)例 **/ @Slf4j @Component @ServerEndpoint(value = "/websocket/{userId}") public class WebSocketServer { /** * 當(dāng)前連接數(shù) */ private static int onlineCount = 0; /** * concurrent包的線程安全Set,用來存放每個(gè)客戶端對應(yīng)的MyWebSocket對象 */ private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<>(); /** * 與某個(gè)客戶端的連接會話,需要通過它來給客戶端發(fā)送數(shù)據(jù) */ private Session session; /** * 接收的用戶id */ private String userId; /** * 連接建立成功調(diào)用的方法 */ @OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { this.session = session; webSocketSet.add(this); addOnlineCount(); //在線數(shù)加1 log.info("有新連接加入!當(dāng)前在線人數(shù)為" + getOnlineCount()); this.userId = userId; try { sendMessage("連接成功"); } catch (IOException e) { log.error("websocket IO異常", e); } } /** * 連接關(guān)閉調(diào)用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); subOnlineCount(); //在線數(shù)減1 log.info("有一連接關(guān)閉!當(dāng)前在線人數(shù)為" + getOnlineCount()); } /** * 收到客戶端消息后調(diào)用的方法 * * @param message 客戶端發(fā)送過來的消息 */ @OnMessage public void onMessage(String message) { log.info("來自客戶端的消息:" + message); //群發(fā)消息 for (WebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { log.error("發(fā)送消息失敗", e); } } } /** * @param error 錯誤 */ @OnError public void onError( Throwable error) { log.error("發(fā)生錯誤", error); } /** * 發(fā)送消息 * @param message 消息 * @throws IOException 異常 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 群發(fā)自定義消息 */ public static void sendInfo(String message, @PathParam("userId") String userId) { log.info("消息內(nèi)容:" + message); for (WebSocketServer item : webSocketSet) { try { //這里可以設(shè)定只推送給這個(gè)sid的,為null則全部推送 if (userId == null) { item.sendMessage(message); } else if (item.userId.equals(userId)) { item.sendMessage(message); } } catch (IOException e) { log.error("消息發(fā)送失敗", e); } } } /** * 獲取在線人數(shù) * @return 在線人數(shù) */ public static synchronized int getOnlineCount() { return onlineCount; } /** * 在線人數(shù)加一 */ public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } /** * 在線人數(shù)減一 */ public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } }
4.在線測試
在線ws測試地址:http://www.jsons.cn/websocket/
- 輸入測試
- 后端返回的結(jié)果
5.模擬消息發(fā)送
/** * 切面攔截?cái)?shù)據(jù)模擬給指定用戶或全部用戶發(fā)消息 */ public void sendMessage(String userid) { // 此處模擬數(shù)據(jù)大屏推送,以切面方式攔截相關(guān)接口,若數(shù)據(jù)發(fā)生變化,則將數(shù)據(jù)推送,不傳id則全部發(fā)送 String msg = "模擬數(shù)據(jù)"; WebSocketServer.sendInfo(msg, userid); log.info("發(fā)送消息成功,消息內(nèi)容:{},接收人:{}", msg, userid); }
總結(jié)
到此這篇關(guān)于Java實(shí)現(xiàn)使用Websocket發(fā)送消息的文章就介紹到這了,更多相關(guān)Java Websocket發(fā)送消息內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java中使用WebSocket的幾種方式
- 如何在Java中使用WebSocket協(xié)議
- springboot整合websocket后啟動報(bào)錯(javax.websocket.server.ServerContainer not available)
- Java WebSocket客戶端接收大量數(shù)據(jù)的三種方案
- 使用Java WebSocket獲取客戶端IP地址的示例代碼
- Java中實(shí)現(xiàn)WebSocket方法詳解
- 教你如何使用Java實(shí)現(xiàn)WebSocket
- 一步步教你如何使用Java實(shí)現(xiàn)WebSocket
- java后端+前端使用WebSocket實(shí)現(xiàn)消息推送的詳細(xì)流程
- JAVA 日常開發(fā)中Websocket示例詳解
相關(guān)文章
Java如何使用Jetty實(shí)現(xiàn)嵌入式的Servlet容器
這篇文章主要介紹了Java使用Jetty實(shí)現(xiàn)嵌入式的Servlet容器,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來一起了解一下吧2019-06-06使用Springboot+Vue實(shí)現(xiàn)文件上傳和下載功能
本文介紹了如何使用Springboot結(jié)合Vue進(jìn)行圖書信息管理系統(tǒng)開發(fā),包括數(shù)據(jù)庫表的創(chuàng)建,實(shí)體類、Dao層、Service層和Controller層的編寫,重點(diǎn)講解了文件上傳和下載功能的實(shí)現(xiàn),感興趣的朋友跟隨小編一起看看吧2024-09-09java中靜態(tài)導(dǎo)入機(jī)制用法實(shí)例詳解
這篇文章主要介紹了java中靜態(tài)導(dǎo)入機(jī)制用法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-07-07Java超詳細(xì)教你寫一個(gè)銀行存款系統(tǒng)案例
這篇文章主要介紹了怎么用Java來寫一個(gè)銀行的存款系統(tǒng),銀行存款主要有賬號和存款金額兩個(gè)屬性,感興趣的朋友跟隨文章往下看看吧2022-03-03springboot+thymeleaf+druid+mybatis 多模塊實(shí)現(xiàn)用戶登錄功能
這篇文章主要介紹了springboot+thymeleaf+druid+mybatis 多模塊實(shí)現(xiàn)用戶登錄功能,本文通過示例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07