当前位置: 首页 > news >正文

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高性能服务器编程 学习笔记 第十一章 定时器

网络程序需要处理定时事件&#xff0c;如定期检测一个客户连接的活动状态。服务器进程通常管理着众多定时事件&#xff0c;有效地组织这些定时事件&#xff0c;使其在预期的时间被触发且不影响服务器的主要逻辑&#xff0c;对于服务器的性能有至关重要的影响。为此&#xff0c;…...

jenkins拉取git代码 code 128解决方案

jenkins拉取git代码 code 128解决方案 处理方案&#xff1a; 先检查一下自己的账号正常是否有权限(如账号正常有权限请看第二步&#xff09;找到Jenkins工作目录&#xff0c;重命名caches文件夹(或直接删除caches内的所有内容) # 进入到jenkins目录&#xff08;注意&#xf…...

【Linux】 ls命令使用

ls&#xff08;英文全拼&#xff1a; list directory contents&#xff09;命令用于显示指定工作目录下之内容&#xff08;列出目前工作目录所含的文件及子目录)。 ls命令 -Linux手册页 著者 由Richard M.Stallman和David MacKenzie撰写。 语法 ls [-alrtAFR] [name...] ls命…...

【CVE-2023-35843】NocoDB 任意文件读取漏洞

一、漏洞描述 NocoDB 是 Airtable 的开源替代方案&#xff0c;可以“一键”将 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&#xff08;State-Action-Reward-State-Action&#xff09;是一个学习马尔可夫决策过程策略的算法&#xff0c;通常应用于机器学习和强化学习学习领域中。它由Rummery 和 Niranjan在技术论文“Modified Connectionist Q-Learning&#xff08;MCQL&#xff09;” 中…...

[HNCTF 2022 WEEK2]easy_unser - 反序列化+wakeup绕过+目录绕过

题目代码&#xff1a; <?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 快在哪里 &#xff1f; 引言FastThreadLocalset如何获取当前线程私有的InternalThreadLocalMap &#xff1f;如何知道当前线程使用到了哪些FastThreadLocal实例 ? get垃圾回收 小结 引言 FastThreadLocal 是 Netty 中造的一个轮子&#xff0c;那么为什么放着…...

ggkegg | 用这个神包玩转kegg数据库吧!~(一)

1写在前面 好久没更了&#xff0c;实在是太忙了&#xff0c;值班真的是根本不不睡觉啊&#xff0c;一忙一整天&#xff0c;忙到怀疑人生。&#x1f62d; 最近看到比较&#x1f525;的就是ggkegg包&#xff0c;感觉使用起来还是有一定难度的。&#x1fae0; 和大家分享一下使用教…...

【小黑送书—第三期】>>《深入浅出SSD》

近年来国家大力支持半导体行业&#xff0c;鼓励自主创新&#xff0c;中国SSD技术和产业良性发展&#xff0c;产业链在不断完善&#xff0c;与国际厂商的差距逐渐缩小。但从行业发展趋势来看&#xff0c;SSD相关技术仍有大幅进步的空间&#xff0c;SSD相关技术也确实在不断前进。…...

linux虚拟机查看防火墙状态

linux虚拟机查看防火墙状态 在Linux虚拟机中&#xff0c;你可以通过以下几种方法查看防火墙状态&#xff1a; 查看iptables防火墙状态 对于使用iptables防火墙的Linux系统&#xff0c;可以使用以下命令查看防火墙状态&#xff1a; sudo iptables -L -v -n查看firewalld防火墙…...

Docker 安装 MongoDB

一、什么是MongoDB MongoDB 是一个基于分布式文件存储的数据库。是一个介于关系数据库和非关系数据库之间的产品&#xff0c;是非关系数据库当中功能最丰富&#xff0c;最像关系数据库的。 二、MongoDB的安装 这里使用docker来安装MongoD 1.docker 拉取mysql镜像 docker pu…...

c++解压压缩包文件

功能实现需要依赖相关头文件和库文件&#xff0c;我这里的是64位的。需要的可以在这下载&#xff1a;https://download.csdn.net/download/bangtanhui/88403596 参考代码如下&#xff1a; #include <zip.h> #pragma comment(lib,"libzip.lib")//解压压缩包 /…...

MySql学习笔记:MySql性能优化

本文是自己的学习笔记&#xff0c;主要参考以下资料 - 大话设计模式&#xff0c;程杰著&#xff0c;清华大学出版社出版 - 马士兵教育 1、MySql调优金字塔2、MySql调优2.1、查询性能2.1.1、慢查询2.1.1.1、总结 1、MySql调优金字塔 Mysql 调优时设计三个层面&#xff0c;分别是…...

机器学习(四十八):粒子群优化(PSO)-提升机器学习模型准确率的秘密武器

文章目录 PSO算法简介为什么使用PSO优化机器学习参数?PSO与其他启发式算法的比较如何使用PSO优化机器学习模型?模块安装和测试例子PSO优化决策树总结PSO算法简介 粒子群优化算法(Particle Swarm Optimization,PSO)是一种模拟鸟群觅食行为的启发式算法。在PSO算法中,每个…...

MySQL - mysql服务基本操作以及基本SQL语句与函数

文章目录 操作mysql客户端与 mysql 服务之间的小九九了解 mysql 基本 SQL 语句语法书写规范SQL分类DDL库表查增 mysql数据类型数值类型字符类型日期类型 示例修改&#xff08;表操作&#xff09; DML添加数据删除数据修改数据 DQL查询多个字段条件查询聚合函数分组查询排序查询…...

[图论]哈尔滨工业大学(哈工大 HIT)学习笔记16-22

视频来源&#xff1a;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. 补图 &#xff08;1&#xff09;…...

使用关键字abstract 声明抽象类-PHP8知识详解

抽象类只能作为父类使用&#xff0c;因为抽象类不能被实例化。抽象类使用关键字abstract 声明&#xff0c;具体的使用语法格式如下&#xff1a; abstract class 抽象类名称{ //抽象类的成员变量列表 abstract function 成员方法1(参数); //抽象类的成员方法 abstract functi…...

Java中使用正则表达式

正则表达式 正则表达式&#xff08;Regular Expression&#xff09;是一种用于匹配、查找和替换文本的强大工具。它由一系列字符和特殊字符组成&#xff0c;可以用来描述字符串的模式。在编程和文本处理中&#xff0c;正则表达式常被用于验证输入、提取信息、搜索和替换文本等…...

Python之字符串分割替换移除

Python之字符串分割替换移除 分割 split(sepNone, maxsplit-1) -> list of strings 从左至右sep 指定分割字符串&#xff0c;缺省的情况下空白字符串作为分隔符maxsplit 指定分割的次数&#xff0c;-1 表示遍历整个字符串立即返回列表 rsplit(sepNone, maxsplit-1) -> …...

ubuntu增加内存

文章目录 1、硬盘操作步骤第二步:点击【扩展】(必须关闭ubuntu电源才能修改)第三步:修改【最大磁盘容量大小】1、硬盘操作步骤 最近发现Ubuntu空间不足,怎么去扩容呢? 第一步:点击【硬盘】 第二步:点击【扩展】(必须关闭ubuntu电源才能修改) 第三步:修改【最大磁…...

黑客都是土豪吗?真实情况是什么?

黑客的利益链条真的这么大这么好么,连最外围的都可以靠信息不对称赚普通人大学毕业上班族想都不敢想的金钱数目,黑客们是不是基本都是土豪 网络技术可以称为黑客程度的技术是不是真的很吃香&#xff1f;如果大部分大学生的智力资源都用在学习网络技术&#xff0c;会不会出现僧…...

企业想过等保,其中2FA双因素认证手段必不可少

随着信息技术的飞速发展&#xff0c;网络安全问题日益凸显。等保2.0时代的到来&#xff0c;意味着企业和组织需要更加严格地保护自身的信息安全。而在这个过程中&#xff0c;双因素认证的重要性逐渐得到广泛认可。本文将探讨 2FA 双因素认证的重要性。 在了解 2FA 双因素认证的…...

Combination Lock

题目描述 新学期开学&#xff0c;您又回到了学校。您需要记住如何操作储物柜上的组合锁。一个组合锁的常见设计如图 1 所示。组合锁有一个圆形刻度表盘&#xff0c;在表盘上&#xff0c;有 40 个编号为从 0 至 39 的刻度&#xff0c;正上方有一个刻度指针。一个组合由这些数字…...

SpringBoot解决LocalDateTime返回数据为数组问题

现象&#xff1a; 在SpringBoot项目中&#xff0c;接口返回的数据出现LocalDateTime对象被转换成了数组 原因分析&#xff1a; 默认序列化情况下会使用SerializationFeature.WRITE_DATES_AS_TIMESTAMPS。使用这个解析时就会打印出数组。 解决方法&#xff1a; 在配置类中…...

【数字人】2、MODA | 基于人脸关键点的语音驱动单张图数字人生成(ICCV2023)

文章目录 一、背景二、方法2.1 问题描述和数据预处理2.2 Mapping-Once network with Dual Attentions2.3 Facial Composer Network2.4 使用 TPE 来合成人像图片 三、效果3.1 训练细节3.2 数据3.3 测评指标3.4 结果比较 四、代码4.1 数据前处理4.2 训练4.3 推理 论文&#xff1a…...

群狼调研(长沙物业第三方评优)开展房地产市场调查内容设计

湖南房地产市场近年来表现出多元化的发展趋势。为了在竞争激烈的市场中获得更好的发展&#xff0c;房地产企业需要密切关注市场变化&#xff0c;合理规划开发项目&#xff0c;同时提高产品质量和服务水平&#xff0c;以满足消费者的需求和期望。群狼调研(长沙神秘顾客调查)在房…...

计算机网络-计算机网络体系结构-物理层

目录 一、通信基础 通信方式 传输方式 码元 传输率 *二 准则 2.1奈氏准则(奈奎斯特定理) 2.2香农定理 三、信号的编码和调制 *数字数据->数字信号 数字数据->模拟信号 模拟数据->数字信号 模拟数据->模拟信号 *四、数据交换方式 电路交换 报文交换…...

微信小程序wxs标签 在wxml文件中编写JavaScript逻辑

PC端开发 可以在界面中编写JavaScript脚本 vue/react这些框架更是形成了一种常态 因为模板引擎和jsx语法本身就都是在js中的 我们小程序中其实也有类似的奇妙写法 不过先声明 这东西不是很强大 我们可以先写一个案例代码 wxml代码参考 <view><wxs module"wordSt…...

东莞企业建站收费产品推广/泉州关键词快速排名

我肯定会为每种请求类型添加一个新类.是的,您可能需要编写大量代码,但它会更安全.关键(对我来说)是谁会写这段代码&#xff1f;让我们把这个答案读到最后(或直接跳转到最后建议的选项).在这些例子中,我将使用Dictionary< string,string>对于通用对象,但您可能/应该使用适…...

sae+wordpress/手机端搜索引擎排名

数据结构与算法 二分查找 一、简述 记--二分查找的C语言简单实现。 例子打包&#xff1a;外链:https://wwi.lanzouq.com/b0ca7a38b 密码:ckk5 二、二分查找 释义 假设有一个有序表A&#xff0c;元素个数为n&#xff0c;要查找元素为K 1&#xff09;将A表分成左右两个子表A…...

商务网站建设实训/小学培训机构

现在市面上免费的项目管理工具多如牛毛&#xff0c;然而在工作中一旦用错了工具&#xff0c;就不是免费不免费的事了&#xff0c;如果对项目整体进度造成影响&#xff0c;就得不偿失了。本着让项目管理者省钱又省力的目标&#xff0c;我们今天来测评一下那些热门的项目管理工具…...

网站建设网页设计培训班/搜索引擎优化关键词的处理

欢迎关注”生信修炼手册”!mutagene是一个肿瘤突变频谱数据库&#xff0c;从ICGA, TCGA等肿瘤项目中收集整理蛋白编码基因上的体细胞突变数据&#xff0c;分析识别对应的突变频谱&#xff0c;对应的文章发表在Nucleic Acids Research,链接如下https://academic.oup.com/nar/art…...

php动态网站开发论文/什么是百度竞价推广

转自&#xff1a;https://blog.csdn.net/paincupid/article/details/49924299 经常会接触到VO&#xff0c;DO&#xff0c;DTO的概念&#xff0c;本文从领域建模中的实体划分和项目中的实际应用情况两个角度&#xff0c;对这几个概念进行简析。 得出的主要结论是&#xff1a;在项…...

长春seo经理/百度seo优化网站

最近看完了《黑客与画家》这本书&#xff0c;作者是保罗格雷厄姆&#xff0c;硅谷的创业之父。作者还创立了风投公司YC&#xff0c;资助了很多有想法有能力的年轻人。 书本的很多内容我觉得是自己的阅历不够确实不能够理解&#xff0c;而且作者使用lisp语言我也从来没有接触过&…...