Spring封装的原生WebSocket使用,带组的实现
前言
为了和
TIO来进行对比websocket的简易程度,我这篇就是写一下Spring原生的webSocket的正常操作拿来对比就可以说说优劣性
正文
首先还是导入原生依赖,这里不需要写版本号
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
1.加入消息处理器
package com.xssq.handle;import com.xssq.service.ApiService; import com.xssq.utils.WsSessionManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.socket.CloseStatus; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler;import java.time.LocalDateTime;/** * web套接字处理程序 * * @author xssq * @version 1.0.0 * @date 2023/10/05 * @wisdom 你可以不会,但你不能不知道 */ @Component public class WebSocketHandler extends TextWebSocketHandler {@Autowiredprivate ApiService apiService;/*** 连接建立后* socket 建立成功事件** @param session 会话*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) {Object token = session.getAttributes().get("token");if (token != null) {// 用户连接成功,放入在线用户缓存WsSessionManager.add(token.toString(), session);} else {throw new RuntimeException("用户登录已经失效!");}}/*** 处理文本消息* 接收消息事件** @param session 会话* @param message 信息* @throws Exception 例外*/@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {apiService.apiGet();// 获得客户端传来的消息String payload = message.getPayload();Object token = session.getAttributes().get("token");System.out.println("server 接收到 " + token + " 发送的 " + payload);session.sendMessage(new TextMessage("server 发送给 " + token + " 消息 " + payload + " " + LocalDateTime.now()));}/*** 连接关闭后* socket 断开连接时** @param session 会话* @param status 状态*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) {Object token = session.getAttributes().get("token");if (token != null) {// 用户退出,移除缓存WsSessionManager.remove(token.toString());}} }
2.加入握手拦截器
package com.xssq.Interceptor;import cn.hutool.core.util.CharsetUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.http.HttpUtil; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.HandshakeInterceptor;import java.util.Map;/** * web套接字拦截器 * * @author xssq * @version 1.0.0 * @date 2023/10/05 * @wisdom 你可以不会,但你不能不知道 */ @Component public class WebSocketInterceptor implements HandshakeInterceptor {/*** 握手之前** @param request 请求* @param response 响应* @param wsHandler ws处理程序* @param attributes 属性* @return boolean* @throws Exception 例外*/@Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {System.out.println("握手开始");// 获得请求参数Map<String, String> paramMap = HttpUtil.decodeParamMap(request.getURI().getQuery(), CharsetUtil.CHARSET_UTF_8);String token = paramMap.get("token");if (StrUtil.isNotBlank(token)) {// 放入属性域attributes.put("token", token);System.out.println("用户 token " + token + " 握手成功!");return true;}System.out.println("用户登录已失效");return false;}/*** 握手后** @param request 请求* @param response 响应* @param wsHandler ws处理程序* @param exception 例外*/@Overridepublic void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {System.out.println("握手完成");} }
3.握手拦截器创建完成后,再创建一个用户的会话管理
package com.xssq.utils;import org.springframework.web.socket.WebSocketSession;import java.io.IOException; import java.util.concurrent.ConcurrentHashMap;/** * ws会话管理器 * * @author xssq * @version 1.0.0 * @date 2023/10/05 * @wisdom 你可以不会,但你不能不知道 */ public class WsSessionManager {/*** 保存连接 session 的地方*/public static ConcurrentHashMap<String, WebSocketSession> SESSION_POOL = new ConcurrentHashMap<>();/*** 添加 session** @param key*/public static void add(String key, WebSocketSession session) {// 添加 sessionSESSION_POOL.put(key, session);}/*** 删除 session,会返回删除的 session** @param key* @return*/public static WebSocketSession remove(String key) {// 删除 sessionreturn SESSION_POOL.remove(key);}/*** 删除并同步关闭连接** @param key*/public static void removeAndClose(String key) {WebSocketSession session = remove(key);if (session != null) {try {// 关闭连接session.close();} catch (IOException e) {// todo: 关闭出现异常处理e.printStackTrace();}}}/*** 获得 session** @param key* @return*/public static WebSocketSession get(String key) {// 获得 sessionreturn SESSION_POOL.get(key);} }
4.创建组连接池管理
package com.xssq.utils;import cn.hutool.core.util.IdUtil; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession;import java.io.IOException; import java.util.concurrent.ConcurrentHashMap;/** * 组ws会话管理器 * * @author xssq * @version 1.0.0 * @date 2023/10/07 * @wisdom 你可以不会,但你不能不知道 */ public class GroupWsSessionManager {/*** 组会话池*/public static ConcurrentHashMap<String, ConcurrentHashMap<String, WebSocketSession>> GROUP_SESSION_POOL = new ConcurrentHashMap<>();/*** 创建组** @param key 钥匙* @param session 会话* @return {@link String}*/public static String create(String key, WebSocketSession session) {/*创建组号*/String idStr = IdUtil.getSnowflakeNextIdStr();/*创建组*/ConcurrentHashMap<String, WebSocketSession> group = new ConcurrentHashMap<>();/*添加用户*/group.put(key, session);/*放入组池*/GROUP_SESSION_POOL.put(idStr, group);/*返回组号*/return idStr;}/*** 用户添加进组** @param groupId 组id* @param key 钥匙* @param session 会话* @return {@link String}*/public static void add(String groupId, String key, WebSocketSession session) {/*创建组号*/ConcurrentHashMap<String, WebSocketSession> group = GROUP_SESSION_POOL.get(groupId);/*用户添加进组*/group.put(key, session);}/*** 解散 组,会返回组号并且通知每一位组员已解散** @param groupId 组id* @return {@link String}*/public static String remove(String groupId) {/*获取要解散的组*/ConcurrentHashMap<String, WebSocketSession> group = GROUP_SESSION_POOL.get(groupId);/*通知组员已经解散*/group.forEach((s, webSocketSession) -> {try {webSocketSession.sendMessage(new TextMessage("群已解散"));} catch (IOException e) {throw new RuntimeException(e);}});/*解散组*/GROUP_SESSION_POOL.remove(groupId);/*返回组号*/return groupId;}/*** 用户退组** @param groupId 组id* @param key 钥匙*/public static void exit(String groupId, String key) {/*获取要退出的组*/ConcurrentHashMap<String, WebSocketSession> group = GROUP_SESSION_POOL.get(groupId);/*用户退出组*/group.remove(key);/*告知组内成员,用户退组*/group.forEach((s, webSocketSession) -> {try {webSocketSession.sendMessage(new TextMessage("用户" + key + "已经退出组"));} catch (IOException e) {throw new RuntimeException(e);}});} }
5.做完上面的还得再加一个webSocket的服务配置启动类
package com.xssq.config;import com.xssq.Interceptor.WebSocketInterceptor; import com.xssq.handle.WebSocketHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.config.annotation.WebSocketConfigurer; import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;/** * web套接字配置 * * @author xssq * @version 1.0.0 * @date 2023/10/05 * @wisdom 你可以不会,但你不能不知道 */ @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer {/*** web套接字处理程序*/@Autowiredprivate WebSocketHandler webSocketHandler;/*** web套接字拦截器*/@Autowiredprivate WebSocketInterceptor webSocketInterceptor;/*** 注册webSocket字处理程序** @param registry 登记处*/@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(webSocketHandler, "/xssq").addInterceptors(webSocketInterceptor).setAllowedOrigins("*");}}
6.简单说明
在第五步中
.addHandler(webSocketHandler, "/xssq")的第二个参数就是你需要连接的路由我这样写的话,连接路径就变成了ws://*******/xssq
后记
做完上面这些,你就会发现配置起来不仅麻烦而且性能还不如TIO简单还有就是没有心跳包,还得自己去配置心跳包,断线机制也得自己来,我现在写的这些都没有用数据库进行保存,如果结合数据库的话就会更加清晰明了用户和组的关系,不过好处也是明显的,就是定制化很强.
但是这些配置的组和管理器在TIO里面都不需要配置了,她都已经实现并且封装好了,我的这个也可以自己去写一个模板到用的时候进行拉取代码也是比较方便的哈
如果我的博客帮助到了您,您可以到我的博客
https://blog.csdn.net/weixin_57228276或者微信公众号搜索幸识SQ,在那里可以找到我,里面也有更多的优秀文章
相关文章:
Spring封装的原生WebSocket使用,带组的实现
前言 为了和TIO来进行对比websocket的简易程度,我这篇就是写一下Spring原生的webSocket的正常操作 拿来对比就可以说说优劣性 正文 首先还是导入原生依赖,这里不需要写版本号 <dependency><groupId>org.springframework.boot</groupId><artifactId>spr…...
Linux高性能服务器编程 学习笔记 第十一章 定时器
网络程序需要处理定时事件,如定期检测一个客户连接的活动状态。服务器进程通常管理着众多定时事件,有效地组织这些定时事件,使其在预期的时间被触发且不影响服务器的主要逻辑,对于服务器的性能有至关重要的影响。为此,…...
jenkins拉取git代码 code 128解决方案
jenkins拉取git代码 code 128解决方案 处理方案: 先检查一下自己的账号正常是否有权限(如账号正常有权限请看第二步)找到Jenkins工作目录,重命名caches文件夹(或直接删除caches内的所有内容) # 进入到jenkins目录(注意…...
【Linux】 ls命令使用
ls(英文全拼: list directory contents)命令用于显示指定工作目录下之内容(列出目前工作目录所含的文件及子目录)。 ls命令 -Linux手册页 著者 由Richard M.Stallman和David MacKenzie撰写。 语法 ls [-alrtAFR] [name...] ls命…...
【CVE-2023-35843】NocoDB 任意文件读取漏洞
一、漏洞描述 NocoDB 是 Airtable 的开源替代方案,可以“一键”将 MySQL、PostgreSQL、SQL Server、SQLite 和 MariaDB 转换为智能电子表格。此软件存在任意文件读取漏洞。 二、影响范围 NocoDB<0.106.1 三、网络空间搜索引擎搜索 fofa查询 icon_hash"-…...
在 ubuntu 22.04 上配置界面服务器 vnc
xrdp服务器的安装 步骤 1.安装服务器 $ sudo apt install tightvncserver // 命令过后并没有启动服务器 // 这个包没有 systemd 脚本,其不被 systemd 管理!!!查看配置 $ cat ~/.vnc/xstartup #!/bin/shxrdb "$HOME/.Xresources" xsetroot -solid grey #x-termina…...
强化学习------Sarsa算法
简介 SARSA(State-Action-Reward-State-Action)是一个学习马尔可夫决策过程策略的算法,通常应用于机器学习和强化学习学习领域中。它由Rummery 和 Niranjan在技术论文“Modified Connectionist Q-Learning(MCQL)” 中…...
[HNCTF 2022 WEEK2]easy_unser - 反序列化+wakeup绕过+目录绕过
题目代码: <?php include f14g.php;error_reporting(0);highlight_file(__FILE__);class body{private $want,$todonothing "i cant get you want,But you can tell me before I wake up and change my mind";public function __construct($want){…...
FastThreadLocal 快在哪里 ?
FastThreadLocal 快在哪里 ? 引言FastThreadLocalset如何获取当前线程私有的InternalThreadLocalMap ?如何知道当前线程使用到了哪些FastThreadLocal实例 ? get垃圾回收 小结 引言 FastThreadLocal 是 Netty 中造的一个轮子,那么为什么放着…...
ggkegg | 用这个神包玩转kegg数据库吧!~(一)
1写在前面 好久没更了,实在是太忙了,值班真的是根本不不睡觉啊,一忙一整天,忙到怀疑人生。😭 最近看到比较🔥的就是ggkegg包,感觉使用起来还是有一定难度的。🫠 和大家分享一下使用教…...
【小黑送书—第三期】>>《深入浅出SSD》
近年来国家大力支持半导体行业,鼓励自主创新,中国SSD技术和产业良性发展,产业链在不断完善,与国际厂商的差距逐渐缩小。但从行业发展趋势来看,SSD相关技术仍有大幅进步的空间,SSD相关技术也确实在不断前进。…...
linux虚拟机查看防火墙状态
linux虚拟机查看防火墙状态 在Linux虚拟机中,你可以通过以下几种方法查看防火墙状态: 查看iptables防火墙状态 对于使用iptables防火墙的Linux系统,可以使用以下命令查看防火墙状态: sudo iptables -L -v -n查看firewalld防火墙…...
Docker 安装 MongoDB
一、什么是MongoDB MongoDB 是一个基于分布式文件存储的数据库。是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。 二、MongoDB的安装 这里使用docker来安装MongoD 1.docker 拉取mysql镜像 docker pu…...
c++解压压缩包文件
功能实现需要依赖相关头文件和库文件,我这里的是64位的。需要的可以在这下载:https://download.csdn.net/download/bangtanhui/88403596 参考代码如下: #include <zip.h> #pragma comment(lib,"libzip.lib")//解压压缩包 /…...
MySql学习笔记:MySql性能优化
本文是自己的学习笔记,主要参考以下资料 - 大话设计模式,程杰著,清华大学出版社出版 - 马士兵教育 1、MySql调优金字塔2、MySql调优2.1、查询性能2.1.1、慢查询2.1.1.1、总结 1、MySql调优金字塔 Mysql 调优时设计三个层面,分别是…...
机器学习(四十八):粒子群优化(PSO)-提升机器学习模型准确率的秘密武器
文章目录 PSO算法简介为什么使用PSO优化机器学习参数?PSO与其他启发式算法的比较如何使用PSO优化机器学习模型?模块安装和测试例子PSO优化决策树总结PSO算法简介 粒子群优化算法(Particle Swarm Optimization,PSO)是一种模拟鸟群觅食行为的启发式算法。在PSO算法中,每个…...
MySQL - mysql服务基本操作以及基本SQL语句与函数
文章目录 操作mysql客户端与 mysql 服务之间的小九九了解 mysql 基本 SQL 语句语法书写规范SQL分类DDL库表查增 mysql数据类型数值类型字符类型日期类型 示例修改(表操作) DML添加数据删除数据修改数据 DQL查询多个字段条件查询聚合函数分组查询排序查询…...
[图论]哈尔滨工业大学(哈工大 HIT)学习笔记16-22
视频来源:2.7.1 补图_哔哩哔哩_bilibili 目录 1. 补图 1.1. 补图 2. 双图 2.1. 双图定理 3. 图兰定理/托兰定理 4. 极图理论 5. 欧拉图 5.1. 欧拉迹 5.2. 欧拉闭迹 5.3. 欧拉图 5.4. 欧拉定理 5.5. 伪图 1. 补图 1.1. 补图 (1)…...
使用关键字abstract 声明抽象类-PHP8知识详解
抽象类只能作为父类使用,因为抽象类不能被实例化。抽象类使用关键字abstract 声明,具体的使用语法格式如下: abstract class 抽象类名称{ //抽象类的成员变量列表 abstract function 成员方法1(参数); //抽象类的成员方法 abstract functi…...
Java中使用正则表达式
正则表达式 正则表达式(Regular Expression)是一种用于匹配、查找和替换文本的强大工具。它由一系列字符和特殊字符组成,可以用来描述字符串的模式。在编程和文本处理中,正则表达式常被用于验证输入、提取信息、搜索和替换文本等…...
【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制
在数字化浪潮席卷全球的今天,数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具,在大规模数据获取中发挥着关键作用。然而,传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时,常出现数据质…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...
深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
