Springboot 接入 WebSocket 实战

news2024/10/25 3:24:55

Springboot 接入 WebSocket 实战

前言:
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。

简单理解:
1,常见开发过程中我们知道 Http协议,客户端请求一次,服务器响应一次,推送数据,不能主动的推送数据,每次请求都要做一个连接,非常消耗性能。

2,websocket 建立一次链接,可以主动向客户端推送数据。

需求说明:
1,项目需要做一个知识助手,远程调用三方接口,那边是websocket 实时推送数据,类似gpt
2,后端需要连接三方服务,调用接口返回数据给前端,做渲染

在这里插入图片描述

功能实现

1,依赖

 		<dependency>
            <groupId>javax.websocket</groupId>
            <artifactId>javax.websocket-api</artifactId>
            <version>1.1</version>
        </dependency>

       <dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp</artifactId>
        </dependency>

2,代码接口实现

controller:

    @GetMapping("/callxxxxModel")
    public String callxxxxModel(@RequestParam("paramOne") String paramOne) {
       return webSocketxxxClientService.callxxxxModel(paramOne);
    }

service:

    /**
     * 
     * @param paramOne
     *            参数1
     */
    String callxxxxModel(String paramOne);

serviceImpl:

@Slf4j
@Service("webSocketxxxClientService")
public class WebSocketxxxClientServiceImpl implements WebSocketxxxClientService{



    @Override
    public String callxxxxModel(String paramOne, Integer executeType) {
        String uri = "ws://10.xx.xx.13:123/sss/xxx/aa/xxx_v2";
        String xappid = "lsjdfljsdxxx09980dsfsd";
        String xappkey = "xxsfdsf12123123";
        long timestamp = System.currentTimeMillis();
        String seqid = "";

        log.info("timestamp=" + timestamp);
        log.info("seqid=" + seqid);

        WebSocketClientRemote client = new WebSocketClientRemote(uri, xappid, xappkey);

        // Prepare message
        Map<String, Object> message = new HashMap<>();
        message.put("uid", xappid);
        message.put("timestamp", timestamp);
        message.put("seqid", seqid);
        message.put("stream", "true");
        // 会话识别码,切换话题可能需要更换
        message.put("session_id", seqid);
        message.put("prov", "xxsdfsdf23424332");
        message.put("param1", paramOne);
        message.put("param2", "xvsdfds23423423xxxxx");

        String jsonMessage = JSON.toJSONString(message);
        client.sendMessage(jsonMessage);
        String responseMessage = client.getResponseMessage();
        client.close();
        return responseMessage;
    }
package com.xx.xx.xx.web;

import com.xx.xx.common.result.ResultCodeEnum;
import com.xx.xx.xxx.exception.CloudException;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import okio.ByteString;

import javax.websocket.ClientEndpoint;
import java.util.concurrent.CountDownLatch;

/**
 * @author nobuyboday
 */
@Slf4j
@ClientEndpoint
public class WebSocketClientRemote {

    private final OkHttpClient client;
    private final WebSocket webSocket;
    // public final CountDownLatch latch = new CountDownLatch(50);
	
	// 记录websocket 返回的信息
    public String responseMessage = "";

    public WebSocketClientRemote(String uri, String xappid, String xappkey) {
        client = new OkHttpClient();

        Request request = new Request.Builder().url(uri)
                // 添加自定义头
                .addHeader("X-App-ID", "xxxfjslfjslj1231321xxxx3")
                // 添加自定义头
                .addHeader("X-App-Key", "0923jhdjflsdjflsdjljxxxxxxflsn").build();

        webSocket = client.newWebSocket(request, new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                log.info("已连接到服务器................");
            }

            @Override
            public void onMessage(WebSocket webSocket, String text) {
                // log.info("收到消息: " + text);
                responseMessage += text;
            }

            @Override
            public void onMessage(WebSocket webSocket, ByteString bytes) {
                log.info("收到字节消息: " + bytes.hex());
            }

            @Override
            public void onClosing(WebSocket webSocket, int code, String reason) {
                webSocket.close(1000, null);
                log.info("连接关闭: " + reason);
                // latch.countDown();
            }

            @Override
            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                log.info("连接失败: " + t.getMessage());
            }
        });
    }

    public void sendMessage(String message) {
        webSocket.send(message);
    }

    public void close() {
        webSocket.close(1000, "关闭连接");
    }

    public void await() throws InterruptedException {
        // latch.await();
    }

    public String getResponseMessage() {
        // 对方数据是以 <#END> 代表推送数据完毕,这个\\u003c#END\\u003e是<#END>编码问题 不用管
        boolean isReturn = responseMessage.endsWith("<#END>") || responseMessage.endsWith("\\u003c#END\\u003e") || responseMessage.contains("#END")
                || responseMessage.contains("\\u003c#END\\u003e");
        if (isReturn) {
//            log.info("最终的responseMessage:================>>>:{}", responseMessage);
            return responseMessage.substring(0, responseMessage.length() - "<#END>".length());
        } else {
            // 循环等待
            try {
                Thread.sleep(3000);
            } catch (Exception e) {
                throw new CloudException(ResultCodeEnum.CALL_GROUP_DCOOS_TYCLOUD_KNOWLEDGE_ASSISTANT_FAIL.getCode(),
                        ResultCodeEnum.CALL_GROUP_DCOOS_TYCLOUD_KNOWLEDGE_ASSISTANT_FAIL.getMessage() + ":" + e);
            }
            return getResponseMessage();
        }
    }

}

遇到的问题:

1,websocket 没有返回值,需要加一个接口获取返回值
2,对方返回的数据 <#END> 结尾,在接收判断是否完毕后,字符集问题 不识别 <#END>
3,推送数据要保证全部推送完毕,要有个循环调用

喜欢我的文章记得点个在看,或者点赞,持续更新中ing…

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

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

相关文章

LED显示器闪烁故障原因及解决方法

随着电子显示屏在各行各业的广泛应用&#xff0c;LED显示器因其高亮度、节能和灵活的宣传功能&#xff0c;成为了宣传推广的重要工具。然而&#xff0c;LED显示器在使用过程中有时会出现闪烁的现象&#xff0c;这不仅影响了显示效果&#xff0c;还可能影响用户体验。针对这一问…

【layui】多文件上传组件实现

插件预览效果&#xff1a; 需要引入layui的脚本文件layui.js和样式文件layui.css html代码&#xff1a; <div class"layui-input-block"><div class"layui-upload-list"><table class"layui-table"><colgroup><col…

18936 手串

### 思路 1. **输入处理**&#xff1a;读取输入的n, m, c&#xff0c;以及每个串珠的颜色信息。 2. **颜色位置记录**&#xff1a;使用一个字典来记录每种颜色出现的位置。 3. **检查颜色分布**&#xff1a;遍历每种颜色&#xff0c;检查其在任意连续m个串珠中是否出现超过一次…

【Flask】Flask数据库

【Flask】Flask数据库 1.概述2.使用Flask-SQLAlchemy管理数据库3.定义模型4.关系5.数据库操作创建表插入行修改行删除行查询行 1.概述 大多数的数据库引擎都有对应的 Python 包&#xff0c;包括开源包和商业包。Flask 并不限制你使用何种类型的数据库包&#xff0c;因此可以根…

Java体系中的泛型

1. 泛型 一般的类和方法&#xff0c;只能够使用基本类型&#xff0c;要么是自定义的类&#xff0c;如果要编写可以应用于多种数据类型的代码&#xff0c;这种刻板的限制对代码的约束就会很大&#xff0c;那么如何实现可应用于多种数据类型的代码&#xff0c;而不局限于单一一种…

第5篇:DDOS病毒----应急响应之Linux实战篇

现象描述 某服务器网络资源异常,感染该木马病毒的服务器会占用网络带宽&#xff0c;甚至影响网络业务正常应用。 系统分析 针对日志服务器病毒事件排查情况&#xff1a; 在开机启动项/etc/rc.d/rc.local发现可疑的sh.sh脚本&#xff0c;进一步跟踪sh.sh脚本,这是一个检测病毒…

C++从入门到起飞之——AVL树 全方位剖析!

&#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1. AVL的概念 2. AVL树的实现 2.1 AVL树的结构 2.2 AVL树的插⼊ >AVL树插⼊⼀个值的⼤概过程 &…

Rocky linux 修改ip地址, rocky服务器修改静态地址, rocky虚拟机修改ip

1. 更新yum yum update 2. 安装ifconfig yum install net-tools 3. 修改配置 vi /etc/NetworkManager/system-connections/ens33.nmconnection 将ipv4内容修改如下&#xff1a; # 自动改为手动 methodmanual # 网关为vm ware 查看网关地址 address你想改为的ip/24,网关 #dns不…

Qml 分组动画(二) 动画嵌套(自学笔记)

分组动画嵌套示例&#xff0c;直接看效果&#xff0c; 做一个踢足球的示例 下面两个Rectangle 制作渐变的天空和大地 下面这个Rectangle 用于放置足球图片&#xff0c; 由于足球图片直接从网上下载的 没有找到合适大小的图片 &#xff0c;所以用 一个矩形框作限制&#xff0c;…

闲谈Promise

预备知识 回调函数&#xff1a;当一个函数作为参数传入另一个函数中&#xff0c;并且它不会立刻执行&#xff0c;当满足一定条件之后&#xff0c;才会执行&#xff0c;这种函数称为回调函数。比如&#xff1a;定时器。异步任务&#xff1a;与之对应的概念是同步任务&#xff0…

【JVM】面试篇

1 什么是JVM&#xff1f; 1.1 定义 JVM 指的是Java虚拟机&#xff08; Java Virtual Machine &#xff09;。JVM 本质上是一个运行在计算机上的程序&#xff0c;他的职责是运行Java字节码文件&#xff0c;Java虚拟机上可以运行Java、Kotlin、Scala、Groovy等语言。 启动这个程…

电子电气架构---软件定义汽车的新兴生态系统

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的人和事&#xff0c;多看一眼都是你的不…

【含文档】基于Springboot+Vue的校园体育器材管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

C++ : STL容器之vector剖析

STL容器之vector剖析 一、构造函数与赋值&#xff08;一&#xff09;默认构造&#xff08;二&#xff09;拷贝构造&#xff08;三&#xff09;几个相同值构造&#xff08;四&#xff09;迭代器构造&#xff08;五&#xff09;initializer_list 构造&#xff08;六&#xff09;赋…

网络编程(19)——C++使用asio协程实现并发服务器

十九、day19 上一节学习了如果通过asio协程实现一个简单的并发服务器demo&#xff08;官方案例&#xff09;&#xff0c;今天学习如何通过asio协程搭建一个比较完整的并发服务器。 主要实现了AsioIOServicePool线程池、逻辑层LogicSystem、粘包处理、接收协程、发送队列、网络…

C语言入门:打开编程世界的大门

一.C语言是什么 在我们生活中&#xff0c;我们在交流时候使用的就是语言&#xff0c;在这个世界上有许多的国家、民族&#xff0c;自然也有很多语言如&#xff1a;汉语、英语、法语等等&#xff0c;这种人与人交流使用的语言我们称为自然语言。然而计算机并不能理解我们的语言…

github下载文件的两种方式(非git形式)

1.以下面的图为例 &#xff0c;可以直接点击右上方的绿色Code按键&#xff0c;在弹出的列表中选择Download Zip选项&#xff0c;即可下载。 2.如果下载的是单独的某一个文件&#xff0c;则可以按照下图的格式点击下图所示的那个下载的图标即可。

【Linux系统编程】第三十一弹---深入理解静态库:从零开始制作与高效使用的完全指南

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、静态库 1.1、怎么做静态库 1.2、怎么使用静态库 1、静态库 1.1、怎么做静态库 在Linux环境下&#xff0c;通常使用GCC&am…

【2024最新】基于springboot+vue的实验室管理系统lw+ppt

作者&#xff1a;计算机搬砖家 开发技术&#xff1a;SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;Java精选实战项…

PAT甲级-1034 Head of a Gang

题目 题目大意 一个犯罪团伙满足条件&#xff1a;人数 > 2&#xff1b;团伙内的总通话时长 > k。团伙首领就是该团伙中通话时长最多的。先给定一组通话&#xff0c;格式为 A B time&#xff0c;要求输出犯罪团伙的数目&#xff0c;并输出每个团伙的首领名字和该团伙的人…