WebSocket入門與結合redis

WebSocket是什么

WebSocket 是一種用于在客戶端和服務器之間建立雙向通信的協議,它能實現實時、持久的連接。與傳統的 HTTP 請求響應模式不同,WebSocket 在建立連接后允許客戶端和服務器之間相互發送消息,直到連接關閉。由于 WebSocket 具有低延遲、雙向通信和高效的特點,因此適用于多種實時應用場景。

源碼在下面

相關依賴

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>

?websocket必須配置

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;/*** WebSocket 配置*/
@Configuration
public class WebSocketConfig {/*** ServerEndpointExporter 作用** 這個Bean會自動注冊使用@ServerEndpoint注解聲明的websocket endpoint** @return*/@Beanpublic ServerEndpointExporter serverEndpointExporter() {return new ServerEndpointExporter();}
}

一、入門例子

代碼demo

import jakarta.websocket.*;
import org.springframework.stereotype.Component;import java.io.IOException;/*** @Description:* @Author: sh* @Date: 2024/12/15 00:06*/
@Component
@ServerEndpoint("/websocket/WEBSOCKET_MSG_TOPIC")
public class WebSocketServer {@OnOpenpublic void onOpen(Session session) {System.out.println("客戶端已連接: " + session.getId());}@OnMessagepublic void onMessage(Session session, String message) {System.out.println("收到消息: " + message);try {session.getBasicRemote().sendText("消息已收到: " + message);} catch (IOException e) {e.printStackTrace();}}@OnClosepublic void onClose(Session session) {System.out.println("客戶端已關閉: " + session.getId());}@OnErrorpublic void onError(Session session, Throwable throwable) {System.out.println("發生錯誤: " + throwable.getMessage());}
}

測試demo

import com.alipay.api.java_websocket.client.WebSocketClient;
import com.alipay.api.java_websocket.handshake.ServerHandshake;import java.net.URI;
import java.net.URISyntaxException;/*** @Description:* @Author: sh* @Date: 2024/12/15 00:04*/
public class WebSocketClientExample {public static void main(String[] args) throws URISyntaxException {WebSocketClient client = new WebSocketClient(new URI("ws://localhost:8080/websocket/WEBSOCKET_MSG_TOPIC")) {@Overridepublic void onOpen(ServerHandshake handshakedata) {System.out.println("連接已打開");send("Hello, Server!"); // 發送消息到 WebSocket 服務器}@Overridepublic void onMessage(String message) {System.out.println("收到消息: " + message);}@Overridepublic void onClose(int code, String reason, boolean remote) {System.out.println("連接關閉: " + reason);}@Overridepublic void onError(Exception ex) {System.out.println("發生錯誤: " + ex.getMessage());}};client.connect();}
}

二、進階與redis結合

進階demo

直接從redis中獲取數據通過訂閱從redis中獲取數據

import com.macro.mall.websocket.listener.WebSocketSubscribeListener;
import jakarta.annotation.Resource;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;/*** @Description:* @Author: sh* @Date: 2024/12/13 15:38*/
@Component
//@ServerEndpoint(value="/websocket/WEBSOCKET_MSG_TOPIC", decoders = MyMessageDecoder.class)
@ServerEndpoint(value="/websocket/WEBSOCKET_MSG_TOPIC")
public class JavaDemo {/*** 日志對象*/private static Logger logger = LoggerFactory.getLogger(JavaDemo.class);/*** redis消息監聽者容器,此處不好直接注入*/private static RedisMessageListenerContainer redisMessageListenerContainer;private static RedisTemplate redisTemplate;@Resourcepublic void setRedisMessageListenerContainer(RedisMessageListenerContainer redisMessageListenerContainer) {JavaDemo.redisMessageListenerContainer = redisMessageListenerContainer;}@Resourcepublic void setRedisTemplate(RedisTemplate redisTemplate) {JavaDemo.redisTemplate = redisTemplate;}/*** concurrent包的線程安全Set,用來存放每個客戶端對應的webSocket對象。若要實現服務端與單一客戶端通信的話,可以使用Map來存放,其中Key可以為用戶標識*/private static CopyOnWriteArraySet<JavaDemo> webSocketSet = new CopyOnWriteArraySet<>();/*** websocket訂閱監聽器*/private WebSocketSubscribeListener subscribeListener;@OnOpenpublic void onOpen(Session session, EndpointConfig config) {webSocketSet.add(this);subscribeListener = new WebSocketSubscribeListener();subscribeListener.setSession(session);// 設置訂閱topicredisMessageListenerContainer.addMessageListener(subscribeListener, new ChannelTopic("WEBSOCKET_MSG_TOPIC"));}@OnMessagepublic void onMessage(String message, Session session) {logger.debug("get msg from websocket client: {}", message);//1獲取redis數據String result = (String) redisTemplate.opsForValue().get(message);//2.訂閱獲取redis數據
//        Object result = null;
//        // 處理消息并準備發送給前端
//        if ("WEBSOCKET_MSG_TOPIC".equals(new String(message.getChannel()))) {
//            String responseMessage = "服務器收到的消息: " + new String(message.getBody());
//
//            result = redisTemplate.opsForValue().get(new String(message.getBody()));
//        }// 使用 Session 發送消息回客戶端try {session.getBasicRemote().sendText(result.toString());} catch (IOException e) {logger.error("發送消息失敗: {}", e.getMessage());}}@OnClosepublic void onClose(Session session) {// 移除session對象webSocketSet.remove(this);// 移除訂閱對象redisMessageListenerContainer.removeMessageListener(subscribeListener);}@OnErrorpublic void onError(Session session, Throwable error) {}
}

redis配置

@Configuration
public class RedisConfig extends BaseRedisConfig {@Beanpublic RedisConnectionFactory redisConnectionFactory() {return new LettuceConnectionFactory();}// 配置 Redis 消息監聽容器@Beanpublic RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory,MessageListener subscribeListener,  // 注意這里是 inject 消息監聽器ChannelTopic channelTopic) {RedisMessageListenerContainer container = new RedisMessageListenerContainer();container.setConnectionFactory(redisConnectionFactory);container.addMessageListener(subscribeListener, channelTopic);  // 訂閱監聽器return container;}// 配置 ChannelTopic@Beanpublic ChannelTopic channelTopic() {return new ChannelTopic("WEBSOCKET_MSG_TOPIC");  // 你可以更改為你實際需要的頻道名}// 配置消息監聽器(假設你的 subscribeListener 是一個 MessageListener)@Beanpublic MessageListener subscribeListener() {return new WebSocketSubscribeListener();  // 假設你有一個自定義的 MessageListener 類}
}

redis的sub監聽器,監聽websocket收到的消息

/*** @Description:subscribe監聽器* @Author: sh* @Date: 2024/12/13 16:00*/
public class WebSocketSubscribeListener implements MessageListener {/*** 日志對象*/private Logger logger = LoggerFactory.getLogger(WebSocketSubscribeListener.class);/*** websocket連接對象* -- GETTER --*  獲取websocket連接對象** @return websocket連接對象*/@Getterprivate Session session;/*** 設置websocket連接對象** @param session websocket連接對象*/public void setSession(Session session) {this.session = session;}@Overridepublic void onMessage(Message message, byte[] bytes) {// 獲取消息String msg = new String(message.getBody());try {session.getBasicRemote().sendText(msg);} catch (IOException e) {throw new RuntimeException(e);}}
}

Html頁面測試demo

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>WebSocket Test</title>
</head>
<body>
<h1>WebSocket 測試</h1>
<div id="status">未連接</div>
<textarea id="messages" rows="10" cols="30" readonly></textarea><br>
<input type="text" id="messageInput" placeholder="輸入消息" />
<button onclick="sendMessage()">發送</button>
<button onclick="closeConnection()">關閉連接</button><script>let websocket;// 創建 WebSocket 連接function connect() {websocket = new WebSocket('ws://127.0.0.1:8080/websocket/WEBSOCKET_MSG_TOPIC'); // 連接到后端 WebSocket 服務// WebSocket 連接打開時websocket.onopen = () => {document.getElementById("status").textContent = "連接已建立";};// 處理接收到的消息websocket.onmessage = (event) => {const message = event.data;// 假設服務器發送的是 JSON 格式的消息try {const parsedMessage = JSON.parse(message);// 假設服務器返回的數據格式是 { "user": "username", "content": "message text" }document.getElementById("messages").value += `來自 ${parsedMessage.user}: ${parsedMessage.content}\n`;} catch (e) {// 如果解析失敗,則顯示原始消息document.getElementById("messages").value += '收到: ' + message + '\n';}};// 連接關閉時websocket.onclose = () => {document.getElementById("status").textContent = "連接已關閉";};// 連接錯誤時websocket.onerror = (error) => {console.error("WebSocket 錯誤:", error);document.getElementById("status").textContent = "連接錯誤";};}// 發送消息到服務器function sendMessage() {const message = document.getElementById('messageInput').value;if (websocket && websocket.readyState === WebSocket.OPEN) {websocket.send(message);document.getElementById('messageInput').value = '';  // 清空輸入框document.getElementById('messageInput').focus();  // 聚焦到輸入框} else {alert("WebSocket 連接未打開");}}// 關閉 WebSocket 連接function closeConnection() {if (websocket) {websocket.close();}}// 頁面加載時自動連接window.onload = connect;
</script>
</body>
</html>

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/63517.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/63517.shtml
英文地址,請注明出處:http://en.pswp.cn/web/63517.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Hive是什么,Hive介紹

官方網站&#xff1a;Apache Hive Hive是一個基于Hadoop的數據倉庫工具&#xff0c;主要用于處理和查詢存儲在HDSF上的大規模數據?。Hive通過將結構化的數據文件映射為數據庫表&#xff0c;并提供類SQL的查詢功能&#xff0c;使得用戶可以使用SQL語句來執行復雜的?MapReduce任…

OpenHarmony和OpenVela的技術創新以及兩者對比

兩款有名的國內開源操作系統&#xff0c;OpenHarmony&#xff0c;OpenVela都非常的優秀。本文對二者的創新進行一個簡要的介紹和對比。 一、OpenHarmony OpenHarmony具有諸多有特點的技術突破和重要貢獻&#xff0c;以下是一些主要方面&#xff1a; 架構設計創新 分層架構…

Electron-Vue 開發下 dev/prod/webpack server各種路徑設置匯總

背景 在實際開發中&#xff0c;我發現團隊對于這幾個路徑的設置上是純靠猜的&#xff0c;通過一點點地嘗試來找到可行的路徑&#xff0c;這是不應該的&#xff0c;我們應該很清晰地了解這幾個概念&#xff0c;以下通過截圖和代碼進行細節講解。 npm run dev 下的路徑如何處理&…

前端-處理數據的函數

判斷數據是否為空,對象是否存在某屬性,屬性值是否為空,對大數據進行換算,對單位進行轉換. 目錄 1.格式化數據 2.判斷值是否為空(包括對象、數組、字符串、數值類型) &#xff08;1&#xff09;值是0不表示空 &#xff08;2&#xff09;值是0表示空 3. 檢查對象是否具有指定名…

基礎入門-Web應用蜜罐系統堡壘機運維API內外接口第三方拓展架構部署影響

知識點&#xff1a; 1、基礎入門-Web應用-蜜罐系統 2、基礎入門-Web應用-堡壘機運維 3、基礎入門-Web應用-內外API接口 4、基礎入門-Web應用-第三方拓展架構 一、演示案例-Web-拓展應用-蜜罐-釣魚誘使 蜜罐&#xff1a;https://hfish.net/ 測試系統&#xff1a;Ubuntu 20.04 …

Android運行低版本項目可能遇到的問題

Android運行低版本項目可能遇到的問題 低版本項目總是遇到各種問題的&#xff0c;耐心點 一、gradle-xxx.xxx.xxx.zip一直下載不下來 在gradle-wrapper.properties可以試下 distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists zipStoreBaseGRADLE_USER_HOME …

springboot中Controller內文件上傳到本地以及阿里云

上傳文件的基本操作 <form action"/upload" method"post" enctype"multipart/form-data"> <h1>登錄</h1> 姓名&#xff1a;<input type"text" name"username" required><br> 年齡&#xf…

智慧城市工程:相關學點、優勢、未來發展

目錄 相關學點&#xff1a; 智慧城市的優勢 挑戰與未來發展 智慧城市工程是利用現代信息技術和數據分析手段&#xff0c;提升城市管理和服務水平&#xff0c;實現城市運行的智能化、便捷化和高效化的一種新型城市發展模式。智慧城市通過整合物聯網&#xff08;IoT&#xff0…

授權模型MAC

MAC&#xff08;Mandatory Access Control&#xff09;是一種授權模型&#xff0c;用于實現對系統資源訪問的強制控制。在MAC模型中&#xff0c;授權是基于預先定義的安全策略&#xff0c;且該策略由系統管理員來配置和管理。 在MAC模型中&#xff0c;每個用戶和每個資源都被賦…

看板工具助力餐飲與酒店行業實現數字化轉型,提升管理與運營效率

在餐飲與酒店行業&#xff0c;服務質量和客戶體驗是衡量企業成功的關鍵因素。隨著客戶需求的不斷多樣化以及市場競爭的加劇&#xff0c;傳統的管理模式逐漸難以滿足高效運營的需求。尤其在高峰期&#xff0c;如何優化內部流程、提高服務效率和響應速度&#xff0c;成為了許多餐…

2024年CCF 非專業級軟件能力認證CSP-J/S 第二輪( 提高組) 染色(color)

完整題目內容可前往下方鏈接&#xff1a; 染色&#xff08;color&#xff09;_C_嗨信奧-玩嗨信息奧林匹克競賽-少兒編程題庫學習中心https://www.hixinao.com/tiku/cpp/show-4118.html 若需更多真題&#xff0c;可前往題庫中心查找&#xff0c;題庫中心涵蓋白名單賽事真題&am…

OpenIPC開源FPV之Adaptive-Link天空端代碼解析

OpenIPC開源FPV之Adaptive-Link天空端代碼解析 1. 源由2. 框架代碼2.1 消息機制2.2 超時機制 3. 報文處理3.1 special報文3.2 普通報文 4. 工作流程4.1 Profile 競選4.2 Profile 研判4.2.1 回退策略4.2.2 保持策略 4.3 Profile 應用 5. 總結6. 參考資料7. 補充資料7.1 RSSI 和 …

labelme標簽批量轉換數據集json_to_dataset

文章目錄 labelme標簽批量轉換數據集json_to_dataset轉換原理單張圖片轉換多張圖片批量轉換bat腳本循環法 標注圖片提取標注圖片轉單通道 labelme標簽批量轉換數據集json_to_dataset 轉自labelme批量制作數據集教程。 轉換原理 在安裝了labelme的虛擬環境中有一個labelme_js…

Apache Kylin最簡單的解析、了解

官網&#xff1a;Overview | Apache Kylin 一、Apache Kylin是什么&#xff1f; 由中國團隊研發具有濃厚的中國韻味&#xff0c;使用神獸麒麟&#xff08;kylin&#xff09;為名 的一個OLAP多維數據分析引擎:&#xff08;據官方給出的數據&#xff09; 亞秒級響應&#xff…

01云計算HCIA學習筆記

筆者今年7月底考取了華為云計算方向的HCIE認證&#xff0c;回顧從IA到IE的學習和項目實戰&#xff0c;想整合和分享自己的學習歷程&#xff0c;歡迎志同道合的朋友們一起討論&#xff01; 第一章 云計算概述 ICT&#xff1a;ICT是世界電信協會在2001年的全球會議中提出的一個綜…

php生成圖片

前提 開啟dg2庫 去掉前面的;注釋&#xff0c;有的可能會帶.dll后綴影響不大 extensiongd2代碼 <?php $file imagecreate(100,50); //先生成圖片資源$color imagecolorallocate($file,255,255,255); //白色$c imagecolorallocate($file,0,100,255);imagefill($file,0…

免費GIS工具箱:輕松將glb文件轉換成3DTiles文件

在GIS地理信息系統領域&#xff0c;GLB文件作為GLTF文件的二進制版本&#xff0c;主要用于3D模型數據的存儲和展示。然而&#xff0c;GLB文件的使用頻率相對較低&#xff0c;這是因為GIS系統主要處理的是地理空間數據&#xff0c;如地圖、地形、地貌、植被、水系等&#xff0c;…

為何VisualRules更適合技術人員使用

什么是規則引擎 規則引擎是一種軟件組件&#xff0c;它允許將業務規則從應用程序的核心代碼中分離出來&#xff0c;以一種更加靈活、易于管理和維護的方式來定義、存儲和執行這些規則。簡單來說&#xff0c;它就像是一個專門處理規則的 “大腦”&#xff0c;可以根據預先設定的…

prometheus 搭建監控

prometheus 下載 prometheus-3.0.0.linux-amd64.tar.gztar -zxvf prometheus-3.0.0.linux-amd64.tar.gzmv prometheus-3.0.0.linux-amd64 prometheus-3vim /etc/systemd/system/prometheus.serviceprometheus.service [Unit] DescriptionPrometheus Wantsnetwork-online.t…

游戲何如防抓包

游戲抓包是指在游戲中&#xff0c;通過抓包工具捕獲和分析游戲客戶端與服務器之間傳輸的封包數據的過程。抓包工具可實現攔截、篡改、重發、丟棄游戲的上下行數據包&#xff0c;市面上常見的抓包工具有WPE、Fiddler和Charles Proxy等。 抓包工具有兩種實現方式&#xff0c;一類…