Springboot 集成WebSocket作为客户端,含重连接功能,开箱即用

  • 使用演示
 public static void main(String[] args) throws Exception{//初始化socket客户端BaseWebSocketClient socketClient = BaseWebSocketClient.init("传入链接");//发送消息socketClient.sendMessage("填写需要发送的消息", (receive) -> {//这里编写接收消息的代码});}

只需要init后调用sendMessage方法即可,做到开箱即用。内部封装了失败重连接、断线重连接等功能。

基于Springboot工程

  • 引入websocket依赖
	<!--websocket--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
  • 开箱即用的工具类
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
import java.io.IOException;
import java.net.URI;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;/*** 封装简易websocket客户端的类,带重连机制*/
@ClientEndpoint
@Slf4j
public class BaseWebSocketClient {/*** 接收消息的函数,发送消息的时候传入*/private Consumer<String> receiveConsumer;/*** 连接socket的url,init的时候传入*/private String url;/*** 当前socket会话对象,init执行后生成*/private Session session;/*** 重连延迟2.5秒执行(连接需要时间,重连的时候延迟执行)*/private final Long reconnectTime = 2500L;/*** 重连次数*/private AtomicInteger retryReconnectCount = new AtomicInteger(0);/*** 发送消息重试次数*/private AtomicInteger reconnectSendCount = new AtomicInteger(0);/*** 发送消息最大重试次数*/private final int maxReconnectSendCount = 10;/*** 初始化,初始化完才能正常使用** @param url websocket连接的地址*/public static BaseWebSocketClient init(String url) throws Exception {BaseWebSocketClient client = new BaseWebSocketClient();URI uri = new URI(url);WebSocketContainer container = ContainerProvider.getWebSocketContainer();container.connectToServer(client, uri);client.setUrl(url);return client;}/*** 发送消息** @param message         消息* @param receiveConsumer 接收消息的函数*/public void sendMessage(String message, Consumer<String> receiveConsumer) {if (session == null) {throw new RuntimeException("socket还未初始化");}this.setReceiveConsumer(receiveConsumer);try {if (session.isOpen()) {//如果是open状态就能够发送消息session.getBasicRemote().sendText(message);reconnectSendCount = new AtomicInteger(0);} else {//进行重连this.reconnect();//重连2s后重新发送消息new Timer().schedule((new TimerTask() {@Overridepublic void run() {//为了防止重试次数过多,这里做一下限制,一直连接不成功的就不发消息了if (reconnectSendCount.getAndIncrement() >= maxReconnectSendCount) {return;}//再次重试发送消息sendMessage(message, receiveConsumer);}}), reconnectTime + reconnectTime);}} catch (Exception e) {log.error("socket发送消息失败,url:{}", url, e);}}/*** 手动关闭连接,当不使用的时候手动关闭,减少连接资源的损耗*/public void close() throws IOException {session.close(new CloseReason(CloseReason.CloseCodes.NORMAL_CLOSURE, "正常关闭"));}@OnOpenpublic void onOpen(Session session) {this.session = session;}/*** 接收消息,接收消息的响应动作由使用者在send的时候自行传入** @param message 消息内容*/@OnMessagepublic void onMessage(String message) {receiveConsumer.accept(unicodeDecode(message));}/*** 关闭时的操作,分为正常关闭和异常关闭,这里异常关闭的做重连操作*/@OnClosepublic void onClose(CloseReason closeStatus) throws Exception {if (closeStatus == null || closeStatus.getCloseCode() != CloseReason.CloseCodes.NORMAL_CLOSURE) {log.info("socket连接异常关闭url:{},closeStatus:{}", closeStatus, url);//重连reconnect();} else {log.info("socket连接关闭:{}", url);}}@OnErrorpublic void onError(Throwable throwable) throws Exception {log.error("socket连接异常,url:{}", url, throwable);//重连reconnect();}/*** 重连机制*/private void reconnect() throws Exception {if (session == null || session.isOpen()) {return;}//schedule里的this不是当前client对象Object that = this;new Timer().schedule(new TimerTask() {public void run() {//如果是打开的就不执行重连if (session.isOpen()) {return;}log.info("当前socket重连次数:{},url:{}", retryReconnectCount.getAndIncrement(), url);try {URI uri = new URI(url);WebSocketContainer container = ContainerProvider.getWebSocketContainer();container.connectToServer(that, uri);retryReconnectCount = new AtomicInteger(0);log.info("重连成功");} catch (Exception e) {log.error("socket重连失败,url:{}", url, e);}}}, reconnectTime);}private void setReceiveConsumer(Consumer<String> receiveConsumer) {this.receiveConsumer = receiveConsumer;}private void setUrl(String url) {this.url = url;}/*** unicode转中文*/public static String unicodeDecode(String string) {if (StringUtils.isBlank(string)) {return string;}Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");Matcher matcher = pattern.matcher(string);char ch;while (matcher.find()) {ch = (char) Integer.parseInt(matcher.group(2), 16);string = string.replace(matcher.group(1), String.valueOf(ch));}return string;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/144606.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

常识判断 --- 科技常识

目录 力与热 光和声 航空成就 垃圾分类 百科知识 血型 二十四节气歌 春雨惊春清谷天 夏满忙夏暑相连 秋处露秋寒霜降 冬雪雪冬小大寒 力与热 光和声 航空成就 垃圾分类 百科知识 血型

【Ambari】银河麒麟V10 ARM64架构_安装Ambari2.7.6HDP3.3.1问题总结

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的帮助&#x1f338;文…

NFT Insider#109:The Sandbox推出了首个足球小将 NFT 作品集,YGG Web3 游戏峰会即将开启!

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto联合出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#…

API 设计/开发/测试工具:Apifox与怎么通过拦截器

目录 一、测试接口如何创建&#xff1f; 二、如何添加body和header&#xff1f; 三、如果项目设置的有拦截器&#xff1f; 四、拦截器概念&#xff1a; 4.1使用拦截器概念 4.2 先写一个配置类WebMvcConfig.java 4.3 AuthInitInterceptor拦截器中实现 一、测试接口如何创建…

数据结构:简单记录顺序表、链表、栈、队列

初学者很容易认为顺序表、链表、栈、队列是四种并列的数据结构&#xff0c;其实仔细想想并不是。 注意区分&#xff1a; 顺序表和链表是指数据的存储结构&#xff0c;是线性表的一种&#xff0c;顺序表一般指的就是数组&#xff0c;数据存储的逻辑顺序和物理顺序都是连续的&a…

【图像处理】SIFT角点特征提取原理

一、说明 提起在OpenCV中的特征点提取&#xff0c;可以列出Harris&#xff0c;可以使用SIFT算法或SURF算法来检测图像中的角特征点。本篇围绕sift的特征点提取&#xff0c;只是管中窥豹&#xff0c;而更多的特征点算法有&#xff1a; Harris & Stephens / Shi–Tomasi 角点…

支付宝电脑网站支付,异步通知

一&#xff1a;异步通知是支付宝回调商户的服务器&#xff0c;所以这个地址需要通过外网访问&#xff0c;在真实项目中都会有对应的服务器&#xff0c;但是在测试中只有使用内网穿透工具 推荐使用NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 配置好内网穿透之后不要忘记…

CIP或者EtherNET/IP中的PATH是什么含义?

目录 SegmentPATH举例 最近在学习EtherNET/IP&#xff0c;PATH不太明白&#xff0c;翻了翻规范&#xff0c;在这里记个笔记。下面的叙述可能是中英混合&#xff0c;有一些是规范中的原文我直接搬过来的。我翻译的不准确。 Segment PATH是CIP Segment中的一个分类。要了解PATH…

PHP8的继承和多态-PHP8知识详解

我们在前面的时候讲过《面向对象编程的特点》时&#xff0c;面向对象编程具有3大特点&#xff1a;封装性、继承性和多态性。 继承和多态的根本作用就是完成代码的重用。下面就来讲解php8的继承和多态。 1继承 子类可以继承父类的所有成员变量和成员方法&#xff0c;包括构造方…

数据集笔记: Porto

数据来源&#xff1a;Taxi Trajectory Data_数据集-阿里云天池 (aliyun.com) 1 数据介绍 葡萄牙波尔图市运行的所有442辆出租车的全年轨迹&#xff08;从2013年7月1日至2014年6月30日&#xff09; 2 读取数据 import pandas as pdtrapd.read_csv(C:/Users/16000/Download…

【EasyExcel】excel表格的导入和导出

【EasyExcel】excel表格的导入和导出 【一】EasyExcel简介【二】EasyExcel使用【1】EasyExcel相关依赖【2】写Excel&#xff08;1&#xff09;最简单的写(方式一)&#xff08;2&#xff09;最简单的写(方式二)&#xff08;3&#xff09;排除模型中的属性字段&#xff08;4&…

Springboot对MVC、tomcat扩展配置

Springboot在web层的开发基本都是采用Springmvc框架技术&#xff0c;但是Springmvc中的某些配置在boot是没有的&#xff0c;我们就应该根据自己的需求进行对mvc扩展配置 Springboot1.x版本如何配置 通过注解Configuration一个类&#xff0c;继承webmvcconfigureradapter&#…

Bootstrap的弹性盒子布局学习笔记

Bootstrap的弹性盒子布局学习笔记 目录 01-综述02-利用类d-flex与类d-inline-flex将容器定义为弹性盒子03-对弹性容器的的元素在水平方向上进行排列顺序设置03-对弹性容器的的元素在垂直方向上进行排列顺序设置04-弹性盒子内所有元素在主轴方向上的对齐方式05-1-弹性盒子内各行…

C#生成自定义海报

安装包 SixLabors.ImageSharp.Drawing 2.0 需要的字体&#xff1a;宋体和微软雅黑 商用的需要授权如果商业使用可以使用方正书宋、方正黑体&#xff0c;他们可以免费商用 方正官网 代码 using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Draw…

redis-设置从节点

节点结构 节点配置文件 主节点 不变 6380节点 port 6380 slaveof 127.0.0.1 63796381节点 port 6381 slaveof 127.0.0.1 6380启动 指定配置文件的方式启动 D:\jiqun\redis\Redis-6380>redis-server.exe redis.windows.conf启动时&#xff0c;会触发同步数据命令 主节点…

安装ipfs-swarm-key-gen

安装ipfs-swarm-key-gen Linux安装go解释器安装ipfs-swarm-key-gen Linux安装go解释器 https://blog.csdn.net/omaidb/article/details/133180749 安装ipfs-swarm-key-gen # 编译ipfs-swarm-key-gen二进制文件 go get -u github.com/Kubuxu/go-ipfs-swarm-key-gen/ipfs-swarm…

insightface实战:画出嘴巴和眼睛的mask

今天的目标是将人脸的嘴巴和眼睛区域抠出来&#xff0c;使用insightface简单实现出来&#xff0c;为了方便批量使用多进程跑数据&#xff0c;使用多进程的方式&#xff0c;下面是代码&#xff1a; import os import cv2 from multiprocessing import Pool import numpy as n…

Visual Studio 2019 C# winform CefSharp 中播放视频及全屏播放

VS C# winform CefSharp 浏览器控件&#xff0c;默认不支持视频播放&#xff0c;好在有大佬魔改了dll&#xff0c;支持流媒体视频播放。虽然找了很久&#xff0c;好歹还是找到了一个版本100.0.230的dll&#xff08;资源放在文末&#xff09; 首先创建一个项目 第二、引入CefSha…

排序:归并(Merge)排序算法分析

1.归并操作 归并:把两个或多个已经有序的序列合并成一个。 2路归并&#xff1a;二合一k路归并&#xff1a;k合一结论:m路归并&#xff0c;每选出一个元素需要对比关键字m-1次。 2.算法思想 核心操作:把数组内的两个有序序列归并为一个。 例如&#xff1a; 3.代码实现 将…

什么是大数据可视化

在互联网高速发展的当今&#xff0c;5G的兴起加速了数据传输的速度&#xff1b;与此同时&#xff0c;智能物联网如智慧家电、可穿戴设备等产品的火热&#xff0c;进一步扩充了数据获取的渠道。不仅仅在网页上、手机和电脑应用上以秒计产生海量数据&#xff0c;智能设备同时也在…