当前位置: 首页 > news >正文

spring boot 项目整合 websocket

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 {@Beanpublic ServerEndpointExporter serverEndpointExporter() {ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter();return serverEndpointExporter;}/*** 启动加载** @param servletContext*/@Overridepublic 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");}}
 @OnOpenpublic 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异常");}}@OnMessagepublic void handleMessage(Session session, String message) throws IOException {session.getBasicRemote().sendText("Reversed: " + new StringBuilder(message).reverse());}@OnClosepublic void onClose(Session session) {System.out.println("与前端断开了WebSocket连接");}@OnErrorpublic void onError(Throwable throwable) {throwable.printStackTrace();}

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

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

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

    @OnMessagepublic 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 {@Autowiredprivate SpringSocketHandle springSocketHandle;@Autowiredprivate SpringAbstractWebSocketHandler springAbstractWebSocketHandler;@Overridepublic 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*/@Overridepublic void afterConnectionEstablished(WebSocketSession session) throws Exception {System.out.println("SpringSocketHandle, 收到新的连接: " + session.getId());}/*** 处理发送来的消息** @param session* @param message* @throws Exception*/@Overridepublic 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*/@Overridepublic void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {System.out.println("WS 连接发生错误");}/***  连接关闭后调用** @param session* @param closeStatus* @throws Exception*/@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {System.out.println("WS 关闭连接");}/*** 支持分片消息** @return*/@Overridepublic boolean supportsPartialMessages() {return false;}

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

@Slf4j
@Component
public class SpringAbstractWebSocketHandler extends AbstractWebSocketHandler {/*** 业务service*/@Autowiredprivate IDampDatasourceInfoService dampDatasourceInfoService;@Autowiredprivate IDampAssetInfoService dampAssetInfoService;@Autowiredprivate SearchThreadPool searchThreadPool;@Autowiredprivate 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();}

相关文章:

spring boot 项目整合 websocket

1.业务背景 负责的项目有一个搜索功能&#xff0c;搜索的范围几乎是全表扫&#xff0c;且数据源类型贼多。目前对搜索的数据量量级未知&#xff0c;但肯定不会太少&#xff0c;不仅需要搜索还得点击下载文件。 关于搜索这块类型 众多&#xff0c;未了避免有个别极大数据源影响整…...

统计学补充概念-17-线性决策边界

概念 线性决策边界是一个用于分类问题的线性超平面&#xff0c;可以将不同类别的样本分开。在二维空间中&#xff0c;线性决策边界是一条直线&#xff0c;将两个不同类别的样本分隔开来。对于更高维的数据&#xff0c;决策边界可能是一个超平面。 线性决策边界的一般形式可以表…...

指针变量、指针常量与常量指针的区别

指针变量、指针常量与常量指针 一、指针变量 定义&#xff1a;指针变量是指存放地址的变量&#xff0c;其值是地址。 一般格式&#xff1a;基类型 指针变量名;&#xff08;int p&#xff09; 关键点&#xff1a; 1、int * 表示一种指针类型(此处指int 类型)&#xff0c;p(变量…...

mq与mqtt的关系

文章目录 mqtt 与 mq的区别mqtt 与 mq的详细区别传统消息队列RocketMQ和微消息队列MQTT对比&#xff1a;MQ与RPC的区别 mqtt 与 mq的区别 mqtt&#xff1a;一种通信协议&#xff0c;规范 MQ&#xff1a;一种通信通道&#xff08;方式&#xff09;&#xff0c;也叫消息队列 MQ…...

代码大全阅读随笔 (二)

软件设计 设计就是把需求分析和编码调试连在一起的活动。 设计不是在谁的头脑中直接跳出来了&#xff0c;他是不断的设计评估&#xff0c;非正式讨论&#xff0c;写实验代码以及修改实验代码中演化和完善。 作为软件开发人员&#xff0c;我们不应该试着在同一时间把整个程序都塞…...

vue 项目的屏幕自适应方案

方案一&#xff1a;使用 scale-box 组件 属性&#xff1a; width 宽度 默认 1920height 高度 默认 1080bgc 背景颜色 默认 "transparent"delay自适应缩放防抖延迟时间&#xff08;ms&#xff09; 默认 100 vue2版本&#xff1a;vue2大屏适配缩放组件&#xff08;vu…...

23软件测试高频率面试题汇总

一、 你们的测试流程是怎么样的&#xff1f; 答&#xff1a;1.项目开始阶段&#xff0c;BA&#xff08;需求分析师&#xff09;从用户方收集需求并将需求转化为规格说明书&#xff0c;接 下来在项目组领导会组织需求评审。 2.需求评审通过后&#xff0c;BA 会组织项目经理…...

PHP8的匿名函数-PHP8知识详解

php 8引入了匿名函数&#xff08;Anonymous Functions&#xff09;&#xff0c;它是一种创建短生命周期的函数&#xff0c;不需要命名&#xff0c;并且可以在其作用域内直接使用。以下是在PHP 8中使用匿名函数的知识要点&#xff1a; 1、创建匿名函数&#xff0c;语法格式如下&…...

Redis—Redis介绍(是什么/为什么快/为什么做MySQL缓存等)

一、Redis是什么 Redis 是一种基于内存的数据库&#xff0c;对数据的读写操作都是在内存中完成&#xff0c;因此读写速度非常快&#xff0c;常用于缓存&#xff0c;消息队列、分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务场景&#xff0c;比如 String(字符串)、…...

C语言链表梳理-2

链表头使用结构体&#xff1a;struct Class 链表中的每一项使用结构体&#xff1a;struct Student#include <stdio.h>struct Student {char * StudentName;int StudentAge;int StudentSex;struct Student * NextStudent; };struct Class {char *ClassName;struct Stude…...

【深度学习】实验03 特征处理

文章目录 特征处理标准化归一化正则化 特征处理 标准化 # 导入标准化库 from sklearn.preprocessing import StandardScalerfrom matplotlib import gridspec import numpy as np import matplotlib.pyplot as plt import warnings warnings.filterwarnings("ignore&quo…...

基于Dpabi的功能连接

1.预处理 这里预处理用Gretna软件进行&#xff0c;共分为以下几步&#xff1a; &#xff08;1&#xff09;DICOM转NIfTI格式 (2)去除前10个时间点(Remove first 10 times points)&#xff1a;由于机器刚启动、被试刚躺进去也还需适应环境&#xff0c;导致刚开始扫描的数据很…...

在React项目是如何捕获错误的?

文章目录 react中的错误介绍解决方案后言 react中的错误介绍 错误在我们日常编写代码是非常常见的 举个例子&#xff0c;在react项目中去编写组件内JavaScript代码错误会导致 React 的内部状态被破坏&#xff0c;导致整个应用崩溃&#xff0c;这是不应该出现的现象 作为一个框架…...

基于内存池的 简单高效的数据库 SDK简介

基于内存池的 简单高效的数据库 SDK简介 下载地址&#xff1a; https://gitee.com/tankaishuai/powerful_sdks/tree/master/shm_alloc_db_heap shm_alloc_db_heap 是一个基于内存池实现的简单高效的文件型数据存储引擎&#xff0c;利用它可以轻松地像访问内存块一样读、写、增…...

python实例方法,类方法和静态方法区别

为python中的装饰器 实例方法 实例方法时直接定义在类中的函数&#xff0c;不需要任何修饰。只能通过类的实例化对象来调用。不能通过类名来调用。 类方法 类方法&#xff0c;是类中使用classmethod修饰的函数。类方法在定义的时候需要有表示类对象的参数(一般命名为cls&#…...

Pyecharts教程(四):使用pyecharts绘制3D折线图

Pyecharts教程(四):使用pyecharts绘制3D折线图 作者:安静到无声 个人主页 目录 Pyecharts教程(四):使用pyecharts绘制3D折线图准备工作数据准备绘制3D折线图推荐专栏在这篇文章中,我们将学习如何使用pyecharts库来绘制一个3D折线图。pyecharts是一个用于生成Echarts图表的…...

【stable-diffusion使用扩展+插件和模型资源(下)】

插件模型魔法图片等资源&#xff1a;https://tianfeng.space/1240.html 书接上文&#xff1a;&#xff08;上&#xff09; 插件推荐 1.lobe theme lobe theme是一款主题插件&#xff0c;直接可以在扩展安装 界面进行了重新布局&#xff0c;做了一些优化&#xff0c;有兴趣的…...

一文了解SpringBoot中的Aop

目录 1.什么是Aop 2.相关概念 3.相关注解 4.为什么要用Aop 5.Aop使用案例 1.什么是Aop AOP&#xff1a;Aspect Oriented Programming&#xff0c;面向切面&#xff0c;是Spring三大思想之一&#xff0c;另外两个是 IOC-控制反转 DI-依赖注入 (Autowired、Qualifier、Re…...

android系统启动流程之zygote如何创建SystemServer进程

SystemServer:是独立的进程&#xff0c;主要工作是管理服务的&#xff0c;它将启动大约90种服务Services. 它主要承担的职责是为APP的运行提供各种服务&#xff0c;像AMS,WMS这些服务并不是一个独立的进程&#xff0c; 它们其实都是SystemServer进程中需要管理的的众多服务之一…...

【awd系列】Bugku S3 AWD排位赛-9 pwn类型

文章目录 二进制下载检查分析运行二进制ida分析解题思路exp 二进制下载 下载地址&#xff1a;传送门 检查分析 [rootningan 3rd]# file pwn pwn: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for …...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

无人机侦测与反制技术的进展与应用

国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机&#xff08;无人驾驶飞行器&#xff0c;UAV&#xff09;技术的快速发展&#xff0c;其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统&#xff0c;无人机的“黑飞”&…...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...

Scrapy-Redis分布式爬虫架构的可扩展性与容错性增强:基于微服务与容器化的解决方案

在大数据时代&#xff0c;海量数据的采集与处理成为企业和研究机构获取信息的关键环节。Scrapy-Redis作为一种经典的分布式爬虫架构&#xff0c;在处理大规模数据抓取任务时展现出强大的能力。然而&#xff0c;随着业务规模的不断扩大和数据抓取需求的日益复杂&#xff0c;传统…...