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.rhkb.cn/news/492849.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WSL Ubuntu

文章目录 1. 概述1.1 什么是适用于 Linux 的 Windows 子系统1.2 什么是 WSL 21.3 WSL 2 中的新增功能1.4 比较 WSL 2 和 WSL 1 2. 参考资料3. 修改存储位置4. 网络访问 1. 概述 1.1 什么是适用于 Linux 的 Windows 子系统 适用于 Linux 的 Windows 子系统可让开发人员按原样运…

unity接入coze智能体

官网链接 coze智能体创建、设置 点击创建–选着智能体&#xff0c;随便起一个名字&#xff0c;就可以了 添加令牌 把随便起一个名字&#xff0c;设置时间&#xff0c;把所有选项都勾选上&#xff0c;一定要勾选所有团队空间&#xff0c;否则无法点击确定。 点击确定后&a…

基于51单片机的交通灯设计—夜间、紧急、复位、可调时间、四个数码管显示

基于51单片机的交通灯设计 &#xff08;仿真&#xff0b;程序&#xff0b;原理图&#xff0b;PCB&#xff0b;设计报告&#xff09; 功能介绍 具体功能&#xff1a; 1、采用四方向数码管设计&#xff0c;更加符合真实的交通信号灯设计&#xff1b; 2、左侧按键从上到下依次为…

省略内容在句子中间

一、使用二分查找法 每次查找时&#xff0c;将查找范围分成两半&#xff0c;并判断目标值位于哪一半&#xff0c;从而逐步缩小查找范围。 循环查找 计算中间位置 mid Math.floor((low high) / 2)。比较目标值 target 和中间位置的元素 arr[mid]&#xff1a; 如果 target ar…

Python:动态粒子爱心

预览 代码结构概述 这段代码使用了 pygame 库来创建一个动态的图形窗口&#xff0c;绘制一个心形图案&#xff0c;并在其中显示闪烁的文本。代码主要分为以下几个部分&#xff1a; 初始化和设置心形曲线的计算粒子类的定义生成粒子文本设置主循环 1. 初始化和设置 import p…

springboot449教学资源共享平台(论文+源码)_kaic

摘 要 如今社会上各行各业&#xff0c;都喜欢用自己行业的专属软件工作&#xff0c;互联网发展到这个时候&#xff0c;人们已经发现离不开了互联网。新技术的产生&#xff0c;往往能解决一些老技术的弊端问题。因为传统教学资源共享平台信息管理难度大&#xff0c;容错率低&am…

DataOps驱动数据集成创新:Apache DolphinScheduler SeaTunnel on Amazon Web Services

引言 在数字化转型的浪潮中&#xff0c;数据已成为企业最宝贵的资产之一。DataOps作为一种文化、流程和实践的集合&#xff0c;旨在提高数据管道的质量和效率&#xff0c;从而加速数据从源头到消费的过程。白鲸开源科技&#xff0c;作为DataOps领域的领先开源原生公司&#xf…

【大模型】GraphRAG技术原理

核心概念 GraphRAG 的核心在于用大模型构建知识图谱知识图谱聚类社区化RAG RAG就是输入&#xff08;问题知识&#xff09;到大模型 1-大模型自动从海量数据中构建知识图谱&#xff08;提取合并实体关系&#xff09; 2-聚类算法从知识图谱中聚类社区并生成社区摘要 3-输入问题…

揭秘区块链隐私黑科技:零知识证明如何改变未来

文章目录 1. 引言&#xff1a;什么是零知识证明&#xff1f;2. 零知识证明的核心概念与三大属性2.1 完备性&#xff08;Completeness&#xff09;2.2 可靠性&#xff08;Soundness&#xff09;2.3 零知识性&#xff08;Zero-Knowledge&#xff09; 3. 零知识证明的工作原理4. 零…

王佩丰24节Excel学习笔记——第十二讲:match + index

【以 Excel2010 系列学习&#xff0c;用 Office LTSC 专业增强版 2021 实践】 【本章小技巧】 vlookup与match&#xff0c;index 相结合使用match,index 结合&#xff0c;快速取得引用的值扩展功能&#xff0c;使用match/index函数&#xff0c;结合照相机工具获取照片 一、回顾…

探秘C语言:从诞生到广泛应用的编程世界

引言 在编程的广袤天地里&#xff0c;C 语言宛如一颗璀璨的恒星&#xff0c;持久而耀眼地散发着光芒。自诞生以来&#xff0c;它就以独特的魅力和强大的功能&#xff0c;深深扎根于软件开发的各个层面。无论是构建复杂的操作系统&#xff0c;还是操控微小的嵌入式设备&#xff…

【Python】pandas库---数据分析

大学毕业那年&#xff0c;你成了社会底层群众里&#xff0c;受教育程度最高的一批人。 前言 这是我自己学习Python的第四篇博客总结。后期我会继续把Python学习笔记开源至博客上。 上一期笔记有关Python的NumPy数据分析&#xff0c;没看过的同学可以去看看&#xff1a;【Pyt…

常见异构程序设计语言

目录 一、OpenMP 二、MPI 三、CUDA/HIP 四、OpenACC 五、Athread 六、OpenCL 七、oneAPI 20世纪80年代&#xff0c;异构计算技术就已经诞生了。异构就是CPU、DSP、GPU、ASIC、协处理器、FPGA等各种计算单元、使用不同的类型指令集、不同的体系架构的计算单元&#xff0c…

番外篇 Git 的原理与使用

PS&#xff1a;本篇是个长篇&#xff0c;但是阅读完&#xff0c;可以基本了解 Git 在实际开发中的绝大部分常用操作。 前言&#xff1a;什么是Git 我们在日常工作 / 学习时&#xff0c;对于某些文档 / 代码&#xff0c;可能会存在多个版本需要维护&#xff0c;但是随着版本的…

音频开发中常见的知识体系

在 Linux 系统中&#xff0c;/dev/snd 目录包含与声音设备相关的文件。每个文件代表系统中的一部分音频硬件或音频控制接口。以下是你列出的文件及其含义&#xff1a; 一.基本术语 样本长度(sample)&#xff1a;样本是记录音频数据最基本的单位&#xff0c;计算机对每个通道采…

我的工作会被AI替代吗?

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

‌HBase是什么,‌HBase介绍

‌官方网站&#xff1a;Apache HBase – Apache HBase Home HBase是一个分布式的、面向列的NoSQL数据库&#xff0c;主要用于存储和处理海量数据。‌它起源于Google的​​​​​​​BigTable论文&#xff0c;是Apache Hadoop项目的子项目。HBase设计用于高可靠性、高性能和可伸…

【C 语言指针篇】指针的灵动舞步与内存的神秘疆域:于 C 编程世界中领略指针艺术的奇幻华章

文章目录 【C 语言篇】指针的灵动舞步与内存的神秘疆域&#xff1a;于 C 编程世界中领略指针艺术的奇幻华章前言一 、指针的介绍与使用1. 指针的介绍1.1指针表示1.2指针变量1.3空指针 2. 使用指针2.1交换两个变量的值2.2计算输出最小值和最大值 二、野指针的介绍与使用1. 野指针…

网络视频监控平台/安防监控/视频综合管理Liveweb视频汇聚平台解决方案

一、当前现状分析 当前视频资源面临以下问题&#xff1a; 1&#xff09;不同单位在视频平台建设中以所属领域为单位&#xff0c;设备品牌众多&#xff0c;存在的标准不一&#xff0c;各系统之间也没有统一标准&#xff1b; 2&#xff09;各单位视频平台建设分散、统筹性差&am…

【从零开始入门unity游戏开发之——C#篇08】逻辑运算符、位运算符

文章目录 一、逻辑运算符1、**&&&#xff08;逻辑与&#xff09;**语法&#xff1a;示例&#xff1a; 2、**||&#xff08;逻辑或&#xff09;**语法&#xff1a;示例&#xff1a; 3、**!&#xff08;逻辑非&#xff09;**语法&#xff1a;示例&#xff1a; 4、**^&…