SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)
SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)
文章目录
- SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)
- @[TOC]
- 前言
- 一、websocket服务端依赖引入
- 二、websocket服务代码实现
- 1.WebSocketConfig配置
- 2.WebSocketServer服务实现
- 3.ChatClient4Chat连接工具实现
- 3.WebSocketClient连接第三方客户端实现
- 总结
文章目录
- SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)
- @[TOC]
- 前言
- 一、websocket服务端依赖引入
- 二、websocket服务代码实现
- 1.WebSocketConfig配置
- 2.WebSocketServer服务实现
- 3.ChatClient4Chat连接工具实现
- 3.WebSocketClient连接第三方客户端实现
- 总结
章节
第一章链接: SpringBoot集成websocket(1)|(websocket客户端实现)
第二章链接: SpringBoot集成websocket(2)|(websocket服务端实现以及websocket中转实现)
前言
本节主要介绍的是springboot实现websocket的客户端服务端,以及客户端与服务端的数据互传。以下为伪代码,业务逻辑删除导致不能直接拷贝运行,大家可以参考其中的思路实现。
一、websocket服务端依赖引入
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId></dependency>
二、websocket服务代码实现
1.WebSocketConfig配置
springboot接入websocket需要启用对应的配置
@Configuration
@EnableWebSocket
public class WebSocketConfig {@Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}
2.WebSocketServer服务实现
springboot提供对外的websocket接口实现
@Component
@Data
@Slf4j
@ServerEndpoint(value = "/v1/chat")
public class DocChatServer {public final static String CHAT_ERR_MSG_FORMAT = "{\"header\":{\"code\":10001,\"message\":\"参数格式不对\",\"sId\":\"%s\",\"status\":2}}";@Autowiredprivate void setOriginMessageSender() {// 初始化注入bean 隐藏掉了}@OnOpenpublic void OnOpen(Session session) {log.debug("chat websocket open ");}@OnClosepublic void OnClose() {log.debug("chat websocket close ");}@OnMessagepublic void OnMessage(Session session, String message) {SearchDocParamVo param = null;log.debug("ApiRequest = {}", message);// 参数校验try {JSONObject jsonObject = JSONObject.parseObject(message);// todo 参数校验} catch (Exception e) {String errMsg = String.format(CHAT_ERR_MSG_FORMAT, session.getId());log.error("chat请求参数格式不会:{},异常:{}", errMsg, e);send(session, errMsg);return;}// todo 业务处理List<ChatRecord.Source> sources = Lists.newArrayList();;String prompt = "";// 谈话接口queryChat(session, param, prompt, sources);}/*** 执行谈话** @param session* @param param* @param prompt* @param sources*/private void queryChat(Session session, SearchDocParamVo param, String prompt, List<ChatRecord.Source> sources) {// todo 业务处理 。。。// 消息发送try {boolean b = this.sendChatMessage(session, param, sources, texts);if (!b) {List<Text> textsTry = Lists.newArrayList();Text build1 = Text.builder().role("user").content("请更具自己的理解回答问题:" + param.getContent()).build();textsTry.add(build1);this.sendChatMessage(session, param, sources, textsTry);}} catch (Exception e) {log.error("发送消息异常:{}", e.getMessage());}}/*** 收到谈话响应数据处理** @param session* @param param* @param sources* @param texts* @return*/private boolean sendChatMessage(Session session, SearchDocParamVo param, List<ChatRecord.Source> sources, List<Text> texts) {ChatClient4Chat planetClient4Chat = new ChatClient4Chat(websocketConfigConst);try {planetClient4Chat.send(param, texts, new ApiResponseObserver() {public void onReceive(String message) {// 收到远程websocket服务响应的数据}public void onError(Throwable throwable) {log.error("收到错误:{}", throwable);}public void onCompleted() {log.error("收到结束");}});// 以下是业务逻辑 可忽略for (int i = 0; i < 100; i++) {if (planetClient4Chat.isHasCheck()) {log.debug("has check");return planetClient4Chat.isSuccess();} else {Thread.sleep(500);}}} catch (Exception e) {log.error("发送消息异常:{}", e.getMessage());}return true;}public void send(Session session, String msg) {synchronized (session) {if (!session.isOpen()) {log.error("客户端连接关闭,数据不发送:{}", msg);return;}try {session.getBasicRemote().sendText(msg);} catch (IOException ex) {log.error("传递消息给客户端异常:{}", ex.getMessage());}}}public int getStatus(String message) {int status = -1;try {//todo 业务逻辑return choices.getStatus();} catch (Exception e) {log.error("数据中提取status异常:{}", e);}return status;}@OnErrorpublic void onerror(Session session, Throwable throwable) {log.error("chat连接异常关闭:远程主机强迫关闭了一个现有的连接:{}", throwable);}}
3.ChatClient4Chat连接工具实现
springboot提供对中间衔接工具了,连接第三饭websocket接口
实现代码如下
@Slf4j
@Getter
@Setter
public class ChatClient4Chat {private static WebsocketConfigConst websocketConfigConst;private StringBuilder stringBuilder;private boolean hasCheck;private boolean success;private Queue<String> queue;private ChatChatServer sparkChatServer;ChatClient4Chat(WebsocketConfigConst websocketConfigConst) {this.websocketConfigConst = websocketConfigConst;this.stringBuilder = new StringBuilder();this.hasCheck = false;this.success = true;this.queue = new LinkedList<String>();}/*** 执行聊天** @param param*/public void send(SearchDocParamVo param, List<Text> texts, ApiResponseObserver apiResponseObserver) {// 获取连接ChatChatServer chatServer = (ChatChatServer ) getWebSocketClient(apiResponseObserver);if (chatServer != null && chatServer.isOpen()) {this.sparkChatServer = chatServer;// 消息发送try {chatServer.send(SparkHand.initParam(param, texts, websocketConfigConst.type, websocketConfigConst.appid, websocketConfigConst.token));} catch (Exception e) {log.error("发送消息异常:{}", e.getMessage());}} else {log.error("接口连接未打开");}}public void close() {// 获取连接if (sparkChatServer != null && sparkChatServer.isOpen()) {sparkChatServer.close();} else {log.error("接口连接未打开,关闭异常");}}private void waitConnect() {try {Thread.sleep(50);} catch (InterruptedException e) {log.error("等待连接异常");}}private WebSocketClient getWebSocketClient(ApiResponseObserver apiResponseObserver) {WebSocketClient client = new SparkChatServer(websocketConfigConst.chaturl, apiResponseObserver);client.connect();waitConnect();return client;}
}
ApiResponseObserver 是一个定义的接口,规范一些方法
public interface ApiResponseObserver extends ResponseObservable<String> {
}public interface ResponseObservable<T> {void onReceive(T response);void onError(Throwable throwable);void onCompleted();
}
3.WebSocketClient连接第三方客户端实现
springboot提供对第三方websocket连接的客户端
实现代码如下
@Slf4j
public class SparkChatServer extends WebSocketClient {private ApiResponseObserver apiResponseObserver;public SparkChatServer(URI serverUri, ApiResponseObserver apiResponseObserver) {super(serverUri);this.apiResponseObserver = apiResponseObserver;}@Overridepublic void onOpen(ServerHandshake serverHandshake) {log.debug("chat 服务连接成功");}@Overridepublic void onMessage(String message) {log.debug("收到chat数据{}", message);apiResponseObserver.onReceive(message);}@Overridepublic void onClose(int i, String s, boolean b) {log.debug("退出chat连接");}@Overridepublic void onError(Exception e) {log.error("chat连接出现异常:{}", e);}
}
总结
本文主要介绍websocket客户端、服务端的实现,同时通过连接工具中转websocket请求参数,捉到实时同步,以及数据收集。代码为伪代码,删除了实际使用当中的业务逻辑,介绍的是实现实录,大家可以参考。
第一章链接: SpringBoot集成websocket(1)|(websocket客户端实现)
第二章链接: SpringBoot集成websocket(2)|(websocket服务端实现以及websocket中转实现)
相关文章:
SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)
SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传) 文章目录 SpringBoot集成websocket(3)|(websocket调用websocket采用回调方式实现数据互传)[TOC] 前…...

基于Doris实时数据开发的一些注意事项
300万字!全网最全大数据学习面试社区等你来! 最近Doris的发展大家是有目共睹的。例如冷热分离等新特性的持续增加。使得Doris在易用和成本上都有大幅提升。 基于Doris的一些存储实时数仓在越来越多的场景中开始有一些实践。大家也看到了这种方案频繁出现…...

竞赛项目 深度学习疲劳驾驶检测 opencv python
文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 🔥 优…...

20.4 HTML 表单
1. form表单 <form>标签: 用于创建一个表单, 通过表单, 用户可以向网站提交数据. 表单可以包含文本输入字段, 复选框, 单选按钮, 下拉列表, 提交按钮等等. 当用户提交表单时, 表单数据会发送到服务器进行处理.action属性: 应指向一个能够处理表单数据的服务器端脚本或UR…...

Linux——基础IO(1)
目录 0. 文件先前理解 1. C文件接口 1.1 写文件 1.2 读文件 1.3 输出信息到显示器 1.4 总结 and stdin & stdout & stderr 2. 系统调用文件I/O 2.1 系统接口使用示例 2.2 接口介绍 2.3 open函数返回值 3. 文件描述符fd及重定向 3.1 0 & 1 & 2 3.2…...

MFC第二十七天 通过动态链表实现游戏角色动态增加、WM_ERASEBKGND背景刷新的原理、RegisterClass注册窗口与框架程序开发
文章目录 通过动态链表实现游戏角色动态增加CMemoryDC.hCFlashDlg.hCFlashDlg.cpp WM_ERASEBKGND背景刷新的原理RegisterClass注册窗口与框架程序开发CFrameRegister 通过动态链表实现游戏角色动态增加 CMemoryDC.h #pragma once#include "resource.h"/*内存DC类简介…...
Debezium系列之:基于内容路由实现把数据库表中的数据按照数据类型分发到不同的topic
Debezium系列之:基于内容路由实现把数据库表中的数据按照数据类型分发到不同的topic 一、需求背景二、创建表三、插入、更新、删除数据四、核心参数和实现技术五、查看分发的Topic六、消费Topic数据七、总结和延展一、需求背景 一张表中存有各个超市门店的订单信息,例如超市门…...
苹果账号被禁用怎么办?
苹果账号被禁用怎么办? 转载:苹果账号被禁用怎么办? 当我们使用苹果手机登录App Store时,有时会遇到账号被禁用的提示。总结下来, 账号被禁用的原因可能有以下几种: 禁用的原因 1.在不同的设备上登录Ap…...
文章一:快速上手Git - 从零到一:Git版本控制入门指南
开始本篇文章之前先推荐一个好用的学习工具,AIRIght,借助于AI助手工具,学习事半功倍。欢迎访问:http://airight.fun/。 概述 在软件开发和团队协作中,版本控制是一项至关重要的技术。Git作为现代开发者最喜爱的版本控…...

【用unity实现100个游戏之6】制作一个战旗自走棋类游戏(附源码)
文章目录 前言导入素材开始1. 设置瓦片间隙2. 放置全图瓦片3. 美化瓦片地图4. 添加树木障碍物5. 设定不同的排序图层6. 瓦片交互6. 瓦片交互优化6. 瓦片是否允许角色7. 添加角色8. 新增游戏管理脚本9. 角色移动范围逻辑10. 角色移动范围可视化11. 角色移动12. 重置瓦片颜色12. …...

W5100S-EVB-PICO 做TCP Server进行回环测试(六)
前言 上一章我们用W5100S-EVB-PICO开发板做TCP 客户端连接服务器进行数据回环测试,那么本章将用开发板做TCP服务器来进行数据回环测试。 TCP是什么?什么是TCP Server?能干什么? TCP (Transmission Control Protocol) 是一种面向连…...

dinput8.dll导致游戏打不开的解决方法,快速修复dinput8.dll文件
当你尝试启动某个游戏时,如果遇到dinput8.dll文件缺失或损坏的错误提示,可能会导致游戏无法正常运行。dinput8.dll是DirectInput API的一部分,它提供了游戏手柄、键盘和鼠标等输入设备的支持。本文将详细介绍dinput8.dll的作用、导致游戏无法…...
NAS相关
Debian11 更换软件源 备份 #备份软件源列表 cp /etc/apt/sources.list /etc/apt/sources.list.bak编辑sources.list nano /etc/apt/sources.list替换文件内容 deb http://mirrors.163.com/debian/ bullseye main non-free contrib deb http://mirrors.163.com/debian/ bull…...
26.Netty源码之ThreadLocal
highlight: arduino-light JDK ThreadLocal 如果你需要变量在多线程之间隔离,或者在同线程内的类和方法中共享,那么 ThreadLocal 大显身手的时候就到了。ThreadLocal 可以理解为线程本地变量,它是 Java 并发编程中非常重要的一个类。 ThreadL…...

Mysql SUBSTRING_INDEX - 按分隔符截取字符串
作用: 按分隔符截取字符串 语法: SUBSTRING_INDEX(str, delimiter, count) 属性: 参数说明str必需的。一个字符串。delimiter必需的。分隔符定义,是大小写敏感,且是多字节安全的count必须的。大于0或者小于0的数值…...

封装Ellipsis组件,亲测使用各种场景
自己封装了Ellipsis组件 基于reacttaro,以下是实现代码,分为JSX和CSS文件 JSX代码如下: import { FC, Fragment, JSX, useState } from react; import { Image, StandardProps, Text, View } from tarojs/components;import iconDropDown fr…...

Kendo UI for jQuery,一个现代的jQuery UI组件!
Kendo UI for jQuery是什么? Kendo UI for jQuery是完整的jQuery UI组件库,可快速构建出色的高性能响应式Web应用程序。Kendo UI for jQuery提供在短时间内构建现代Web应用程序所需要的工具,从多个UI组件中选择,并轻松地将它们组…...

C++初阶语法——类和对象
前言:C语言中的结构体,在C有着更高位替代者——类。而类的实例化叫做对象。 本篇文章不定期更新扩展后续内容。 目录 一.面向过程和面向对象初步认识二.类1.C中的结构体2.类的定义类的两种定义方式 3.类的访问限定符及封装访问限定符说明 4.类的实例化对…...

linux学习(进程创建)[8]
创建进程 myproc.c #include <stdio.h> #include <unistd.h>int main() {printf("我是父进程\n");pid_t id fork();if(id < 0){printf("创建子进程失败\n");return 1;}else if(id 0){while(1){printf("我是子进程: pid…...

Linux基础与应用开发系列九:各类系统函数
open_close函数 OPEN函数 头文件: #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> 函数原型: 当文件存在时 int open(const char* pathname,int flags) 当文件不存在时 int open (const char* pathname,int f…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...

听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...