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;}
}相关文章:
Springboot 集成WebSocket作为客户端,含重连接功能,开箱即用
使用演示 public static void main(String[] args) throws Exception{//初始化socket客户端BaseWebSocketClient socketClient BaseWebSocketClient.init("传入链接");//发送消息socketClient.sendMessage("填写需要发送的消息", (receive) -> {//这里…...
java调整字符串
package 字符串练习;public class 调整字符串 {/* 如果调整成功则给提示,返回不成功也给提示调整 例如:abcde -> bcdea -> cdeab 就是把第一个值放到最后的位置上现在是给定两个字符串, 选定其中一个进行调整, (我们想一下,如果调整字符串的长度次,那不就是返回到原来的字…...
2023-9
内核向应用层发送netlink单播消息: nlmsg_unicast -> netlink_unicast -> netlink_sendskb -> __netlink_sendskb -> 把skb链入struct sock 的 sk_receive_queue 链表中,再调用sk->sk_data_ready(sk); -> sock_def_readable -> wak…...
软考高级+系统架构设计师教程+第二版新版+电子版pdf
注意!!! 系统架构设计师出新版教程啦,2022年11月出版。所以今年下半年是新版第一次考试,不要再复习老版教程了,内容改动挺大的。 【内容简介】系统架构设计师教程(第2版)作为全国计…...
【产品运营】如何提升B端产品竞争力(下)
“好产品不是能力内核,做好产品的流程才是” 一、建立需求池和需求反馈渠道 需求池管理是B端产品进化最重要的环节,它的重要性远超产品设计、开发等其他环节。 维护需求池有主动和被动两种。 主动维护是产品经理在参与售前、迭代、交付、售后、竞品分…...
uniapp 微信小程序使用echarts
本文目的:通过分包的方式,尽可能在微信小程序中使用最新的echarts。 当然你也可以直接使用现成的uchart或者市场里别人封好的echarts. 准备工作 下载echarts-for-weixin源码。 复制ec-canvas文件夹以及下属文件,在uniapp项目中与pages同级的地…...
【漏洞复现】企望制造 ERP命令执行
漏洞描述 由于企望制造 ERP comboxstore.action接口权限设置不当,默认的配置可执行任意SQL语句,利用xp_cmdshell函数可远程执行命令,未经认证的攻击者可通过该漏洞获取服务器权限。 免责声明 技术文章仅供参考,任何个人和组织…...
2023 “华为杯” 中国研究生数学建模竞赛(E题)深度剖析|数学建模完整代码+建模过程全解全析
问题一 血肿扩张风险相关因素探索建模 思路: 根据题目要求,首先需要判断每个患者是否发生了血肿扩张事件。根据定义,如果后续检查的血肿体积比首次检查增加≥6 mL或≥33%,则判断为发生了血肿扩张。 具体判断步骤: (1) 从表1中提取每个患者的入院首次影像检查…...
【腾讯云国际站】CDN内容分发网络特性介绍
为什么使用腾讯云国际站 CDN 内容分发网络? 当用户直接访问源站中的静态内容时,可能面临的体验问题: 客户离服务器越远,访问速度越慢。客户数量越多,网络带宽费用越高。跨境用户访问体验较差。 腾讯云国际站CDN 如何改…...
【工业机器人视觉】
工业机器人视觉 工业机器人的定位、抓取任务是工业生产线上一项重要的应用,一般通过预先示教的方式让机器人执行预定的指令动作。但是,一旦工件的状态发生改变时,机器人便无法完成工作任务。区别:就像人睁眼走直线和闭眼走直线。…...
跨域(浏览器)
跨域问题 是前端开发中常遇到的一个挑战。由于浏览器的同源策略限制,前端在发起异步请求时会受到限制,只能向相同源(域名、协议和端口号都相同)的服务器发送请求。当请求的目标服务器与当前页面的源不一致时,就会触发…...
Leetcode 2866. Beautiful Towers II
Leetcode 2866. Beautiful Towers II 1. 解题思路2. 代码实现 题目链接:2866. Beautiful Towers II 1. 解题思路 这一题其实思路上还是比较明显的,就是一个单调数组的问题,问题在于说如果具体去设计这个单调数组。 我们从题目出发&#x…...
电脑C盘爆红怎么办?(小白篇)
文章目录 前言:1、清理临时和系统文件2、更改电脑默认软件安装位置3、微信、QQ文件存储路径放在其它盘4、卸载一些不常用的软件彩蛋 前言: C盘作为电脑的系统盘,如果出现爆满或者剩余空间很小整个C盘变红,这样会导致电脑系统运行…...
Office Xml 2003转XLSX
一、使用到的依赖包 1、xelem-3.1.jar 下载地址:管网下载地址 2、poi-3.17.jar 下载地址:https://mvnrepository.com/artifact/org.apache.poi/poi 二、实现方法 1、Xml2003公式转XLSX公式算法 (1)Xml2003函数格式 SUM(R[-1…...
skyWalking搭建(一)
title: “SkyWalking搭建(一)” createTime: 2021-07-27T14:34:2108:00 updateTime: 2021-07-27T14:34:2108:00 draft: false author: “name” tags: [“skywalking”] categories: [“java”] description: “测试的” 基于 docker 部署 skywalking 并实现 SpringBoot 全链路…...
Golang开发--sync.WaitGroup
sync.WaitGroup 是 Go 语言标准库中的一个并发原语,用于等待一组并发操作的完成。它提供了一种简单的方式来跟踪一组 goroutine 的执行状态,并在所有 goroutine 完成后恢复执行。 下面是关于 sync.WaitGroup 的实现细节的详细解释: 创建 Wa…...
Linux命令教程:使用cat命令查看和处理文件
文章目录 教程:使用cat命令在Linux中查看和处理文件1. 引言2. cat命令的基本概述3. 查看文件内容4. 创建文件5. 文件重定向和管道6. 格式化和编辑文件7. 实际应用示例7.1 使用cat命令浏览日志文件7.2 利用cat命令合并多个配置文件7.3 使用cat命令将文件内容发送到其…...
Websocket集群解决方案以及实战(附图文源码)
最近在项目中在做一个消息推送的功能,比如客户下单之后通知给给对应的客户发送系统通知,这种消息推送需要使用到全双工的websocket推送消息。 所谓的全双工表示客户端和服务端都能向对方发送消息。不使用同样是全双工的http是因为http只能由客户端主动发…...
科技的成就(五十一)
397、初等数论的不可解问题 1936 年 4 月,邱奇证明判定性问题不可解。33 岁的邱奇发表论文《初等数论的不可解问题》,运用λ演算给出了判定性问题一个否定的答案。λ演算是一套从数学逻辑中发展起来的形式系统,采用变量绑定和替换,…...
Tomcat8 任意写文件PUT方法 (CVE-2017-12615)
Tomcat 任意写文件PUT方法 (CVE-2017-12615) 文章目录 Tomcat 任意写文件PUT方法 (CVE-2017-12615)1 在线漏洞解读:2 版本影响3 环境搭建4 漏洞复现4.1 访问4.2 POC攻击点4.2.1 直接发送以下数据包,然后shell将被写入Web根目录。4.2.2 访问是否通,可以访…...
改进二进制粒子群算法在配电网重构中的应用:基于IEEE33节点系统的功率损耗优化与动态重构程序
改进二进制粒子群算法配电网重构 可以动态生成配电网重构过程,目标函数为功率损耗,算例为IEEE33节点系统 程序简洁明了,注释详细配电网重构就像是给电力系统做一场"动态手术",通过调整开关状态让电流走最优路径。传统的…...
7分钟掌握WorkshopDL:打破平台壁垒的Steam创意工坊模组下载终极方案
7分钟掌握WorkshopDL:打破平台壁垒的Steam创意工坊模组下载终极方案 【免费下载链接】WorkshopDL WorkshopDL - The Best Steam Workshop Downloader 项目地址: https://gitcode.com/gh_mirrors/wo/WorkshopDL 你是否在Epic Games Store或GOG平台购买了游戏&…...
别再只测电压了!解锁杰理AC632蓝牙芯片ADC的隐藏玩法:电池检测与低功耗设计
杰理AC632蓝牙芯片ADC实战:电池检测与低功耗设计全解析 在蓝牙耳机、智能穿戴等电池供电设备的开发中,精准的电池电量监测和低功耗设计往往是决定产品成败的关键因素。杰理AC632作为一款广泛应用于消费电子领域的蓝牙芯片,其内置的ADC功能为开…...
AMD新平台装CentOS7.9总报Kernel Panic?别折腾了,试试Rocky Linux 9.2吧
AMD新平台安装CentOS7.9遭遇Kernel Panic?Rocky Linux 9.2的完美替代方案 最近几年,AMD的Zen3架构处理器凭借出色的性能和能效比,赢得了大量开发者和技术爱好者的青睐。然而,当这些用户尝试在Ryzen 5000系列平台上安装某些较旧的L…...
RTKLIB数据流引擎str2str:从源码到实战的流式数据处理架构剖析
1. RTKLIB数据流引擎str2str架构解析 str2str是RTKLIB中负责数据流处理的核心模块,它的设计理念类似于工厂里的流水线传送带。想象一下GNSS数据就像流水线上的零件,str2str的工作就是把这些零件从不同来源的传送带(输入流)接过来&…...
[资料整理]魔法师传奇 MagicMayhem
魔法师传奇 Magic&Mayhem魔法师传奇中文站网站魔法师传奇2023版介绍魔法师传奇中文站网站 网站地址:魔法师传奇中文站 http://zb.l4d.top:1983/magic 备用链接:http://zb.my.to:1983/magic 论坛地址:魔法师传奇中文论坛 http://zb.l4d.t…...
在快马平台实战演练claude代码技能教程中的完整项目开发流程
今天想和大家分享一个特别实用的学习路径——如何通过InsCode(快马)平台将Claude代码技能教程中的知识转化为真实可运行的项目。最近我跟着教程完整实现了一个博客内容管理系统,整个过程比想象中顺畅很多。 项目规划与功能拆解 Claude教程中提到的博客系统包含8个…...
数字化转型架构下的数据安全治理指南:以数据安全为核心的安全立体防御体系、数据安全体系、数据安全现状评估报告···(附相关资料)
微信公众号:木木自由,更多数据分析,经营分析、财务分析、商业分析、数据治理、数据要素、数据资产干货以及资料分享木木自由 数据分析领地Digital Technology Summit在数字经济深度发展的今天,数字化转型已成为企业生存与发展的…...
c语言完美演绎6-20
/* 范例:6-20 */#include<stdio.h> #include<conio.h>int main(){int a;printf("请输入你的分数0-100>");scanf("%d",&a);if((a>0) && (a<60))printf("你被当了");else if((a>60) && (a…...
实战演练:基于快马平台与方锐理念构建短视频智能配乐应用
最近在做一个短视频创作的小工具,发现给视频配乐真是个技术活。正好看到网易方锐的AI音乐技术挺火的,就想着能不能用它的理念做个智能配乐助手。在InsCode(快马)平台上试了试,没想到还真搞出了一个能跑起来的demo,分享下我的实现思…...
