Springboot集成WebSocket客户端,发送消息并监测心跳

  • jar包(主要jar包)
		<dependency><groupId>org.java-websocket</groupId><artifactId>Java-WebSocket</artifactId><version>1.5.7</version></dependency>
  • 服务类

import cn.hutool.json.JSONUtil;
import cn.hutool.json.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;/*** WebSocket client*  * @author Mr丶s* @date 2024/9/3 22:06* @description*/
@Slf4j
public class MyWebSocketClient extends WebSocketClient {// 用于存储接收到的客户端响应的 CompletableFuture 对象private CompletableFuture<JSONObject> responseFuture;// 心跳检测的调度程序private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);/*** 构造函数,初始化 WebSocket 客户端连接 URI** @param serverUri WebSocket 服务器的 URI* @throws URISyntaxException 如果 URI 格式不正确*/public MyWebSocketClient(URI serverUri) throws URISyntaxException {super(serverUri);}/*** 当与服务器建立连接时调用此方法** @param handshakedata 握手数据*/@Overridepublic void onOpen(ServerHandshake handshakedata) {log.info("Connected to server");startHeartbeat();}/*** 当收到服务器的消息时调用此方法** @param message 服务器发送的消息*/@Overridepublic void onMessage(String message) {// 使用 Hutool 将消息解析为 JSON 对象JSONObject jsonResponse = JSONUtil.parseObj(message);log.info("Received JSON response: " + jsonResponse.toStringPretty());// 如果 responseFuture 存在,则将 JSON 响应设置为其结果if (responseFuture != null) {responseFuture.complete(jsonResponse);}}/*** 当连接关闭时调用此方法** @param code   关闭的状态码* @param reason 关闭的原因* @param remote 是否是远程关闭*/@Overridepublic void onClose(int code, String reason, boolean remote) {log.info("Connection closed with exit code " + code + " additional info: " + reason);stopHeartbeat();}/*** 当发生错误时调用此方法** @param ex 发生的异常*/@Overridepublic void onError(Exception ex) {System.err.println("An error occurred: " + ex.getMessage());// 如果发生错误并且 responseFuture 存在,则将异常设置为 responseFuture 的结果if (responseFuture != null) {responseFuture.completeExceptionally(ex);}}/*** 发送 JSON 格式的数据到服务器** @param jsonData 要发送的 JSON 数据(Hutool 的 JSONObject 对象)*/public void sendJsonMessage(JSONObject jsonData) {// 发送 JSON 数据到 WebSocket 服务器this.send(jsonData.toString());log.info("Sent JSON data: " + jsonData.toStringPretty());}/*** 检查 WebSocket 连接是否已建立** @return 如果连接已建立,则返回 true;否则返回 false*/public boolean isConnected() {return this.isOpen();}/*** 发送 JSON 数据并异步获取服务器响应** @param jsonData 要发送的 JSON 数据(Hutool 的 JSONObject 对象)* @return 包含服务器响应的 CompletableFuture 对象*/public CompletableFuture<JSONObject> sendMessageAndGetResponse(JSONObject jsonData) {// 初始化 CompletableFuture 对象,用于存储未来的响应responseFuture = new CompletableFuture<>();// 发送 JSON 消息sendJsonMessage(jsonData);// 返回 CompletableFuture 对象,客户端可以等待此 future 的完成return responseFuture;}/*** 启动心跳检测,定时发送心跳消息*/private void startHeartbeat() {scheduler.scheduleAtFixedRate(() -> {if (isConnected()) {// 发送心跳消息sendJsonMessage(JSONUtil.createObj().set("type", "heartbeat"));log.info("Heartbeat sent");} else {log.info("Disconnected, attempting to reconnect");reconnect();}}, 0, 30, TimeUnit.SECONDS); // 每 30 秒发送一次心跳}/*** 停止心跳检测*/private void stopHeartbeat() {scheduler.shutdownNow();}/*** 尝试重新连接 WebSocket 服务器*/@Overridepublic void reconnect() {try {this.reconnectBlocking();log.info("Reconnected to server");} catch (InterruptedException e) {e.printStackTrace();}}
}
  • 服务调用

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import cn.hutool.json.JSONObject;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;/*** WebSocket 服务类** @author Mr丶s* @date 2024/8/18 下午9:23* @description*/
@Slf4j
@Service
public class WebSocketClientService {private MyWebSocketClient myWebSocketClient;/*** 初始化 WebSocket 客户端并建立连接* 此方法在服务启动时调用,确保 WebSocket 客户端可以与服务器进行通信。*/@PostConstructpublic void init() {try {// WebSocket 服务器 URIURI uri = new URI("ws://58.57.65.22:2315");// URI uri = new URI("ws://192.168.1.106:5523");// 创建 WebSocket 客户端实例myWebSocketClient = new MyWebSocketClient(uri);// 尝试建立连接connectIfNotConnected();} catch (URISyntaxException e) {e.printStackTrace();}}/*** 如果 WebSocket 未连接,则建立连接* 确保 WebSocket 连接是打开的,如果连接未打开,则尝试建立连接。*/private void connectIfNotConnected() {try {if (!myWebSocketClient.isConnected()) {// 阻塞式连接,直到连接成功myWebSocketClient.connectBlocking();log.info("WebSocket client connected");} else {log.info("WebSocket client already connected");}} catch (InterruptedException e) {e.printStackTrace();}}/*** 发送 JSON 数据到 WebSocket 服务器并获取响应** @param jsonData 要发送的 JSON 数据(Hutool 的 JSONObject 对象)* @return 服务器返回的 JSON 数据(Hutool 的 JSONObject 对象)*/public JSONObject sendJsonData(JSONObject jsonData) {connectIfNotConnected(); // 确保已建立连接// 发送消息并异步等待服务器的响应CompletableFuture<JSONObject> responseFuture = myWebSocketClient.sendMessageAndGetResponse(jsonData);try {// 阻塞直到获得响应,并返回响应数据return responseFuture.get();} catch (InterruptedException | ExecutionException e) {e.printStackTrace();return null;}}/*** 关闭 WebSocket 连接*/@PreDestroypublic void close() {try {myWebSocketClient.closeBlocking();log.info("WebSocket client connection closed");} catch (InterruptedException e) {e.printStackTrace();}}
}

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

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

相关文章

「Python程序设计」条件控制:if-elif-else语句

我们在进行程序设计的过程中&#xff0c;基本上遵循的过程是&#xff0c;找出变量和常量&#xff0c;通过python编程语言&#xff0c;设置变量和常量&#xff0c;以及考虑是否需要赋予初始值。 设计变量和常量&#xff0c;其实就是为了模拟和计算我们的现实世界中&#xff0c;…

学习笔记--Docker

安装 1.卸载旧版 首先如果系统中已经存在旧的Docker&#xff0c;则先卸载&#xff1a; yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine 2.配置Docker的yum库 首先要安…

深入理解 JavaScript DOM 操作

一、DOM 操作分类 &#xff08;一&#xff09;元素查找 根据 ID 值查找&#xff1a;getElementById()&#xff0c;返回符合条件的第一个对象。 var aa document.getElementById("aa");console.log(aa);根据类名查找&#xff1a;getElementsByClassName()&#xff…

IntelliJ IDEA 自定义字体大小

常用编程软件自定义字体大全首页 文章目录 前言具体操作1. 打开设置对话框2. 设置编辑器字体3. 设置编译软件整体字体 前言 IntelliJ IDEA 自定义字体大小&#xff0c;统一设置为 JetBrains Mono 具体操作 【File】>【Settings...】>【Editor】>【Font】 统一设置…

C++:list篇

前言: 观看C的list前需要对链表有一些了解&#xff0c;如C语言的链表结构。本片仅介绍list容器中常用的接口函数概念以及使用。 list的概念&#xff1a; 简而言之&#xff0c;C的list是一个双向带哨兵位的链表容器模板 list的构造&#xff1a; 1.list():默认构造 2.li…

spring之异常和测试相关注解

原文地址 ControllerAdvice和ExceptionHandler 通常组合使用&#xff0c;用于处理全局异常&#xff0c;示例代码如下&#xff1a; ControllerAdvice Configuration Slf4j public class GlobalExceptionConfig {private static final Integer GLOBAL_ERROR_CODE 500;Excepti…

认识git和git的基本使用,本地仓库,远程仓库和克隆远程仓库

本地仓库 #安装git https://git-scm.com/download/win #git是什么&#xff1f;有什么用&#xff1f; git相当于一个版本控制系统&#xff0c;版本控制是一种记录一个或若干文件内容变化&#xff0c;以便将来查阅特定版本修订情况的系统。 作用: 记录&#xff08;项目&#…

[Qt5] 使用QtConcurrent::run在异步线程中执行耗时函数

&#x1f4e2;博客主页&#xff1a;https://loewen.blog.csdn.net&#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;本文由 丶布布原创&#xff0c;首发于 CSDN&#xff0c;转载注明出处&#x1f649;&#x1f4e2;现…

Java-树形图工具类TreeUtil

TreeUtil 工具类,包括列表转树形结构、遍历、查找和删除节点等功能。 import java.util.*;public class TreeUtil {/*** 将列表转换为树形结构。** @param target 扁平化的节点列表* @param getId 获取节点ID的函数* @param getParentId 获取节点父ID的函数* @…

物联网(IoT)支持的小型水处理厂实时硬件在环(HIL)仿真

这篇论文的标题是《Real-Time Hardware-In-The-Loop Simulation of IoT-Enabled Mini Water Treatment Plant》&#xff0c;作者是 Mohamad Taib Miskon 等人&#xff0c;发表在 2024 年 IEEE 自动控制与智能系统国际会议&#xff08;I2CACIS&#xff09;上。以下是该论文的主要…

【Agent】Agent Q: Advanced Reasoning and Learning for Autonomous AI Agents

1、问题背景 传统的训练Agent方法是在静态数据集上进行监督预训练&#xff0c;这种方式对于要求Agent能够自主的在动态环境中可进行复杂决策的能力存在不足。例如&#xff0c;要求Agent在web导航等动态设置中执行复杂决策。 现有的方式是用高质量数据进行微调来增强Agent在动…

学习日志29

论文阅读&#xff1a;IBM Q Experience as a versatile experimental testbed for simulating open quantum systems 引言部分&#xff1a; 引言部分首先介绍了开放量子系统的理论研究的重要性&#xff0c;这些理论描述了量子系统与其环境相互作用的动力学。这种理论对于理解量…

C++复习day01

这篇博客主要复习C语言的数组和指针 1.指针数组和数组指针 问&#xff1a;指针数组和数组指针&#xff0c;哪一个是指针&#xff0c;哪一个是数组&#xff1f; 我们来类比一下&#xff0c;整型数组是存放整型的数组&#xff0c;那么指针数组就是一个存放指针的数组&#xff0…

经验笔记:进程、线程与协程的理解与应用

经验笔记&#xff1a;进程、线程与协程的理解与应用 1. 引言 在软件开发中&#xff0c;特别是在涉及并发编程的场景下&#xff0c;进程、线程和协程是非常重要的概念。理解它们各自的定义、特点以及彼此之间的联系对于有效地设计和实现高效的应用程序至关重要。 2. 定义与特…

vector 常见函数

目录 一.vector 构造函数 二 . Iterators 迭代器&#xff08;random access iterator&#xff09; 三.Capacity: 空间 3.1 resize 3.2 reserve 四.Element access: 元素访问 方式 4.1 operator[] 类似于数组的 [] 4.2 front 和back 五.Modifiers: 六.vector 的 二…

【工业AI】寻优算法的思考

遗传算法GA 本质上来讲&#xff0c;就是找随机点x&#xff0c;通过公式或者回归模型构成的映射函数获得y。 区别于其他搜索寻优算法之处在于&#xff1a;遗传算法的一轮一轮迭代中&#xff0c;新的随机点x的生成&#xff0c;是靠交叉变异01而来的。 初始的DNA_size不管设置为多…

vue3+ts文件流导出xlsx表格需要token

封装方法post请求 import { ElLoading } from element-plus; import axios from axios; export const exportFilePost (params: any) > {const loadingInstance ElLoading.service({background: rgba(255, 255, 255, 0),});axios.post(params.url, params.data, {headers…

redis内存数据库的专业术语雪崩、击穿、穿透的名词解释

redis作为一个内存数据库&#xff0c;其作用主要体现在可以提供高速的访问处理。 redis在内存层面工作&#xff0c;一个字&#xff0c;快。 这也是redis区别于其他类型数据库的一个主要特点。 与之配合使用的是后端持久化存储数据库&#xff0c;比如结构化的数据库mysql mysql的…

18、Gemini-Pentest-v2

难度 中 目标 root权限 一个flag 靶机启动环境为VMware kali 192.168.152.56 靶机 192.168.152.63 信息收集 web测试 访问80端口 上面介绍了一下这个系统是一个内部系统&#xff0c;让员工查看他们的个人资料还可以导出为PDF 页面还有一个链接是UserList可以访问但是页面什…

ES数据写入过程

1. 写入请求 当一个写入请求&#xff08;如 Index、Update 或 Delete 请求&#xff09;通过REST API发送到Elasticsearch时&#xff0c;通常包含一个文档的内容&#xff0c;以及该文档的索引和ID。 2. 请求路由 协调节点&#xff1a;首先&#xff0c;请求会到达一个协调节点…