spring boot 项目整合 websocket

news2025/1/24 8:31:36

1.业务背景

        负责的项目有一个搜索功能,搜索的范围几乎是全表扫,且数据源类型贼多。目前对搜索的数据量量级未知,但肯定不会太少,不仅需要搜索还得点击下载文件。

 

        关于搜索这块类型 众多,未了避免有个别极大数据源影响整个搜索效率,我采用多线程异步搜索,将搜索到每个数据源数据使用 websocket 响应给前端。

2.遇到的问题

        1 .想自定义接收前端消息的类型,因为接收的消息类型都是string 类型,所以一看肯定不符合我的需求。(唉,怪我没多问)

          思路: 其实接收是string一点不影响。直接上json,转对象就行。

        2. socket 什么时候关闭 

          思路:

                    1.心跳包检测,心跳达到次数断开socket。(前后端互发心跳)

                    2. 因为多线程,后端开启线程监听线程有没有执行完的队列还有没有还没执行的任务,没有开始计时,达到时间关闭socket,若计时期间有任务重置计时。(后端监听)

3.相关资料

一文搞懂四种 WebSocket 使用方式_@enablewebsocket_Java架构狮的博客-CSDN博客

4.代码实现

        1.注解写法

/**
 * 开启WebSocket支持
 * Created by huiyunfei on 2019/5/31.
 */
@Configuration
@EnableWebSocket
public class WebSocketConfig implements ServletContextInitializer {


    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter();
        return serverEndpointExporter;
    }


    /**
     * 启动加载
     *
     * @param servletContext
     */
    @Override
    public void onStartup(ServletContext servletContext) {
        servletContext.addListener(WebAppRootListener.class);

        // 接收base64的字符串,等于50M  解决上传内容过大问题
        servletContext.setInitParameter("org.apache.tomcat.websocket.textBufferSize", "52428800");
        servletContext.setInitParameter("org.apache.tomcat.websocket.binaryBufferSize", "52428800");
    }


}
 @OnOpen
    public void onOpen(Session session) {
        System.out.println("与前端建立了WebSocket连接");
        this.session = session;
        webSocketSet.add(this);     //加入set中
//        addOnlineCount();           //在线数加1
//        log.info("有新窗口开始监听:"+sid+",当前在线人数为" + getOnlineCount());
        this.sid=sid;

        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            log.error("websocket IO异常");
        }
    }


    @OnMessage
    public void handleMessage(Session session, String message) throws IOException {
        session.getBasicRemote().sendText("Reversed: " + new StringBuilder(message).reverse());

    }



    @OnClose
    public void onClose(Session session) {
        System.out.println("与前端断开了WebSocket连接");
    }

    @OnError
    public void onError(Throwable throwable) {
        throwable.printStackTrace();
    }

       注意:谁说是注解开发,切记并不是发送http请求,下面是错误实例

        上面我不是提到想自定义接收参数,然后我一直以为加个注解就行。接收类型别动。

         不然就像苦逼的我程序都启动不了,排错半天时间。

    @OnMessage
    public void onMessage(Session session, FullSearchParam param) {
        System.out.println("接收到前端发送的消息:" + param.getSearchContext());
        try {
//            fullSearch(param, session);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (EncodeException e) {
            throw new RuntimeException(e);
        }
    }

        2.实现接口

package com.trinity.web.controller.search.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;


/**
 * 开启WebSocket支持
 * Created by huiyunfei on 2019/5/31.
 */
@Configuration
@EnableWebSocket
public class SpringSocketConfig implements WebSocketConfigurer {

    @Autowired
    private SpringSocketHandle springSocketHandle;

    @Autowired
    private SpringAbstractWebSocketHandler springAbstractWebSocketHandler;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(springSocketHandle, "/spring-ws").setAllowedOrigins("*")
                .addHandler(springAbstractWebSocketHandler, "/spring-ws1").setAllowedOrigins("*");
    }



}

              这种方式接收消息需要判断,因为 WebSocketMessage 是接口,spring 提供了三个实现类,分别是文本 字节 ping,目前后两种还不知道怎么使用。所以这种方式需要区判断前端传输的数据类型分别处理。

@Component
public class SpringSocketHandle implements WebSocketHandler {

    /**
     * 连接成功后调用。
     * @param session
     * @throws Exception
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("SpringSocketHandle, 收到新的连接: " + session.getId());
    }

    /**
     * 处理发送来的消息
     *
     * @param session
     * @param message
     * @throws Exception
     */
    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        String msg = "SpringSocketHandle, 连接:" + session.getId() +  ",已收到消息。";
        System.out.println(msg);
//        this.handleMessage(session, );
        session.sendMessage(new TextMessage(msg));
    }

    /**
     * WS 连接出错时调用
     *
     * @param session
     * @param exception
     * @throws Exception
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("WS 连接发生错误");
    }

    /**
     *  连接关闭后调用
     *
     * @param session
     * @param closeStatus
     * @throws Exception
     */

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        System.out.println("WS 关闭连接");
    }

    /**
     * 支持分片消息
     *
     * @return
     */
    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

        这种方式就更加简单不需要我们自己去判断

@Slf4j
@Component
public class SpringAbstractWebSocketHandler extends AbstractWebSocketHandler {

    /**
     * 业务service
     */
    @Autowired
    private IDampDatasourceInfoService dampDatasourceInfoService;
    @Autowired
    private IDampAssetInfoService dampAssetInfoService;
    @Autowired
    private SearchThreadPool searchThreadPool;
    @Autowired
    private TokenService tokenService;


    /**
     * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static int onlineCount = 0;

    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
     */
    private static CopyOnWriteArraySet<SearchSocketServer> webSocketSet = new CopyOnWriteArraySet<SearchSocketServer>();

    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;


    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        log.info("接收到搜索的消息,搜索内容为{}",message);
        List<String> authorization = session.getHandshakeHeaders().get("Authorization");
        FullSearchParam param = JSONObject.parseObject(message.getPayload(), FullSearchParam.class);
        fullSearch(param, session);
    }



    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {

    }

    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
    }

      5.总结

        尝试写不会的代码总是非常的认真,但也非常煎熬。

        然后接收消息时用到了 SecurityUtils 公共方法 从token 获取用户id,但是却出现获取失败。

        明天再看

public class SecurityUtils
{
    /**
     * 用户ID
     **/
    public static Long getUserId()
    {
        try
        {
            return getLoginUser().getUserId();
        }
        catch (Exception e)
        {
            throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
        }
    }
/**
     * 获取用户
     **/
    public static LoginUser getLoginUser()
    {
        try
        {
            return (LoginUser) getAuthentication().getPrincipal();
        }
        catch (Exception e)
        {
            throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
        }
    }
    /**
     * 获取Authentication
     */
    public static Authentication getAuthentication()
    {
        return SecurityContextHolder.getContext().getAuthentication();
    }

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

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

相关文章

阿里云X森马 AIGC T恤设计大赛;SD新手入门完全指南;揭秘LLM训练中的数学;LLM高质量阅读清单 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; 阿里云X森马 | AIGC T 恤设计大赛&#xff0c;函数计算玩转 Stable Diffusion 比赛官网&#xff1a;https://developer.aliyun.com/ad…

火山引擎云调度GTM“同城容灾”与“异地多活”实践

随着企业不断推进数字化进程&#xff0c;高并发业务和海量数据的挑战也随之而来。在现实生活中&#xff0c;除了地震、台风、挖光纤这种小概率事件&#xff0c;还有很多人为造成的高概率数据丢失事件&#xff0c;比如人为操作失误、硬件故障、网络攻击等等&#xff0c;故障容灾…

RISC-V中国峰会 | 256核服务器高调亮相,谁与争锋?

8月23日&#xff0c;第三届RISC-V中国峰会&#xff08;RISC-V Summit China 2023&#xff09;在北京香格里拉饭店正式开幕&#xff0c;来自世界各地的行业精英汇聚一堂&#xff0c;为RISC-V生态系统建言献策&#xff0c;凝心聚力&#xff01; 中国工程院院士倪光南、RISC-V国际…

C++多线程编程——thread线程创建与使用(2W字保姆级介绍)

目录 前言 线程创建 标准库thread&#xff08;同步线程的创建过程&#xff09; 启动线程&#xff1a;实例thread 线程执行单元&#xff08;可调用对象&#xff09; 线程等待 线程传参 线程id 成员方法获取线程id 命名空间获取线程id 让出线程资源 sleep_for() sle…

聊一聊微前端框架的选型和实现 | 业务平台

一、项目背景 目前&#xff0c;我们开发维护的项目主要有 6 个&#xff0c;但是分别对应 PC 和 H5 两个端&#xff1a; 如上图所示&#xff0c;我们 6个项目最开始是一个一个进行开发维护的&#xff0c;但是到后期&#xff0c;这几个项目之间有的部分会有业务逻辑不同&#xff…

docker高级(mysql主从复制)

数据库密码需要设置成自己的&#xff01;&#xff01;&#xff01; 1、创建容器master13307 #docker pulldocker run -p 13307:3306 --name mysql-master \ --privilegedtrue \ -v /mysql/mysql-master/log:/var/log/mysql \ -v /mysql/mysql-master/data:/var/lib/mysql \ -…

centos 下扩容根目录

大体情况&#xff1a; 在VM虚拟机上安装了移动云的BCLinux镜像&#xff0c;磁盘设定为8G&#xff0c;但是用过一段时间之后根目录下磁盘已满&#xff0c;无法创建文件夹等操作&#xff0c;因此在VM上进行了磁盘扩容&#xff0c;扩容之后需要在系统上自行挂载&#xff0c;使用m…

【VsCode】SSH远程连接Linux服务器开发,搭配cpolar内网穿透实现公网访问(1)

文章目录 前言1、安装OpenSSH2、vscode配置ssh3. 局域网测试连接远程服务器4. 公网远程连接4.1 ubuntu安装cpolar内网穿透4.2 创建隧道映射4.3 测试公网远程连接 5. 配置固定TCP端口地址5.1 保留一个固定TCP端口地址5.2 配置固定TCP端口地址5.3 测试固定公网地址远程 前言 远程…

【linux】基本指令(二)【man、echo、cat、cp】

目录 一、man指令二、echo指令三、cat指令二、cp指令一些常见快捷键 一、man指令 Linux的命令有很多参数&#xff0c;我们不可能全记住&#xff0c;可以通过查看联机手册获取帮助。访问Linux手册页的命令是 man 语法: man [选项] 命令 常用选项 1.-k 根据关键字搜索联机帮助 2…

面试题-React(六):React组件和生命周期

一、React组件 React组件简介&#xff1a; React组件是构建用户界面的基本单元。它们将界面拆分成独立、可重用的部分&#xff0c;使得代码更加模块化、可维护性更高。React组件可以是函数组件或类组件&#xff0c;它们接收输入的数据&#xff08;称为props&#xff09;并返回…

ORB-SLAM2算法11之地图点MapPoint

文章目录 0 引言1 MapPoint类1.1 构造函数1.2 成员函数1.2.1 AddObservation1.2.2 EraseObservation1.2.3 SetBadFlag1.2.4 Replace1.2.5 ComputeDistinctiveDescriptors1.2.6 UpdateNormalAndDepth1.2.7 PredictScale 2 MapPoint类用途 0 引言 ORB-SLAM2算法7详细了解了Syste…

Webstorm 入门级玩转uni-app 项目-微信小程序+移动端项目方案

1. Webstorm uni-app语法插件 &#xff1a; Uniapp Support Uniapp Support - IntelliJ IDEs Plugin | Marketplace 第一个是不收费&#xff0c;第二个收费 我选择了第二个Uniapp Support &#xff0c;有试用30天&#xff0c;安装重启webstorm之后&#xff0c;可以提高生产率…

排序链表-归并排序

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&#xff1a; 输…

vue 展开和收起

效果图 代码块 <div><span v-for"(item,index) in showHandleList" :key"item.index"><span>{{item.emailFrom}}</span></span><span v-if"this.list.length > 4" click"showAll !showAll">{…

Ceph入门到精通-大流量10GB/s LVS+OSPF 高性能架构

LVS 和 LVSkeepalived 这两种架构在平时听得多了&#xff0c;最近才接触到另外一个架构LVSOSPF。这个架构实际上是LVSKeepalived 的升级版本&#xff0c;我们所知道LVSKeepalived 架构是这样子的&#xff1a; 随着业务的扩展&#xff0c;我们可以对web服务器做水平扩展&#xf…

聚观早报 | 云鲸扫拖机器人J4体验;芯科科技第三代无线开发平台

【聚观365】8月24日消息 云鲸扫拖机器人J4体验 芯科科技推出第三代无线开发平台 英伟达与VMWare宣布扩大合作 万物新生&#xff08;爱回收&#xff09;2023年二季度财报 充电桩需求增长带动汽车后服务市场 云鲸扫拖机器人J4体验 家庭卫生清洁是每个人都无法回避的事情&am…

实训笔记8.24

实训笔记8.24 8.24笔记一、Sqoop数据迁移工具1.1 Sqoop的基本概念1.2 Sqoop的基本操作1.2.1 命令语法1.2.2 list-databases1.2.3 list-tables1.2.3 eval1.2.4 import1.2.5 export1.2.6 导入 二、Flume日志采集工具2.1 数据采集的问题2.2 数据采集一般使用的技术2.3 扩展&#x…

Tokenview再度升级:全新Web3开发者APIs数据服务体验!

Tokenview发布全新版本的区块链APIs和数据服务平台&#xff0c;为开发者打造更强大、更便捷的开发体验&#xff01; 此次升级&#xff0c;我们整合了开发者使用习惯以及Tokenview产品优势。我们深知对于开发者来说&#xff0c;时间是非常宝贵的&#xff0c;因此我们努力提供一…

联合注入步骤

使用场景&#xff1a; 有回显&#xff0c;可以看到某些字段的回显信息 像下面的有具体的回显信息 一、判断注入位点 在原始的id&#xff08;参数&#xff09;的输入后面添加额外的条件 如果and 11 有结果&#xff0c;and10没有结果输出&#xff0c; 就说明我们添加的额外条件…

sqlmap安装以及运用

目录 一、sqlmap简介 linux系统安装 windows系统安装 二.sqlmap确定目标 (1) sqlmap直连数据库 (2) sqlmap的URL探测 (3) Sqlmap文件读取目标 (4) Sqlmap Google批量扫注入 一、sqlmap简介 sqlmap是一个开源的渗透测试工具&#xff0c;它可以自动化检测sql注入漏洞利用…