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.业务背景 负责的项目有一个搜索功能,搜索的范围几乎是全表扫,且数据源类型贼多。目前对搜索的数据量量级未知,但肯定不会太少,不仅需要搜索还得点击下载文件。 关于搜索这块类型 众多,未了避免有个别极大数据源影响整…...
统计学补充概念-17-线性决策边界
概念 线性决策边界是一个用于分类问题的线性超平面,可以将不同类别的样本分开。在二维空间中,线性决策边界是一条直线,将两个不同类别的样本分隔开来。对于更高维的数据,决策边界可能是一个超平面。 线性决策边界的一般形式可以表…...
指针变量、指针常量与常量指针的区别
指针变量、指针常量与常量指针 一、指针变量 定义:指针变量是指存放地址的变量,其值是地址。 一般格式:基类型 指针变量名;(int p) 关键点: 1、int * 表示一种指针类型(此处指int 类型),p(变量…...
mq与mqtt的关系
文章目录 mqtt 与 mq的区别mqtt 与 mq的详细区别传统消息队列RocketMQ和微消息队列MQTT对比:MQ与RPC的区别 mqtt 与 mq的区别 mqtt:一种通信协议,规范 MQ:一种通信通道(方式),也叫消息队列 MQ…...
代码大全阅读随笔 (二)
软件设计 设计就是把需求分析和编码调试连在一起的活动。 设计不是在谁的头脑中直接跳出来了,他是不断的设计评估,非正式讨论,写实验代码以及修改实验代码中演化和完善。 作为软件开发人员,我们不应该试着在同一时间把整个程序都塞…...
vue 项目的屏幕自适应方案
方案一:使用 scale-box 组件 属性: width 宽度 默认 1920height 高度 默认 1080bgc 背景颜色 默认 "transparent"delay自适应缩放防抖延迟时间(ms) 默认 100 vue2版本:vue2大屏适配缩放组件(vu…...
23软件测试高频率面试题汇总
一、 你们的测试流程是怎么样的? 答:1.项目开始阶段,BA(需求分析师)从用户方收集需求并将需求转化为规格说明书,接 下来在项目组领导会组织需求评审。 2.需求评审通过后,BA 会组织项目经理…...
PHP8的匿名函数-PHP8知识详解
php 8引入了匿名函数(Anonymous Functions),它是一种创建短生命周期的函数,不需要命名,并且可以在其作用域内直接使用。以下是在PHP 8中使用匿名函数的知识要点: 1、创建匿名函数,语法格式如下&…...
Redis—Redis介绍(是什么/为什么快/为什么做MySQL缓存等)
一、Redis是什么 Redis 是一种基于内存的数据库,对数据的读写操作都是在内存中完成,因此读写速度非常快,常用于缓存,消息队列、分布式锁等场景。 Redis 提供了多种数据类型来支持不同的业务场景,比如 String(字符串)、…...
C语言链表梳理-2
链表头使用结构体:struct Class 链表中的每一项使用结构体: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软件进行,共分为以下几步: (1)DICOM转NIfTI格式 (2)去除前10个时间点(Remove first 10 times points):由于机器刚启动、被试刚躺进去也还需适应环境,导致刚开始扫描的数据很…...
在React项目是如何捕获错误的?
文章目录 react中的错误介绍解决方案后言 react中的错误介绍 错误在我们日常编写代码是非常常见的 举个例子,在react项目中去编写组件内JavaScript代码错误会导致 React 的内部状态被破坏,导致整个应用崩溃,这是不应该出现的现象 作为一个框架…...
基于内存池的 简单高效的数据库 SDK简介
基于内存池的 简单高效的数据库 SDK简介 下载地址: https://gitee.com/tankaishuai/powerful_sdks/tree/master/shm_alloc_db_heap shm_alloc_db_heap 是一个基于内存池实现的简单高效的文件型数据存储引擎,利用它可以轻松地像访问内存块一样读、写、增…...
python实例方法,类方法和静态方法区别
为python中的装饰器 实例方法 实例方法时直接定义在类中的函数,不需要任何修饰。只能通过类的实例化对象来调用。不能通过类名来调用。 类方法 类方法,是类中使用classmethod修饰的函数。类方法在定义的时候需要有表示类对象的参数(一般命名为cls&#…...
Pyecharts教程(四):使用pyecharts绘制3D折线图
Pyecharts教程(四):使用pyecharts绘制3D折线图 作者:安静到无声 个人主页 目录 Pyecharts教程(四):使用pyecharts绘制3D折线图准备工作数据准备绘制3D折线图推荐专栏在这篇文章中,我们将学习如何使用pyecharts库来绘制一个3D折线图。pyecharts是一个用于生成Echarts图表的…...
【stable-diffusion使用扩展+插件和模型资源(下)】
插件模型魔法图片等资源:https://tianfeng.space/1240.html 书接上文:(上) 插件推荐 1.lobe theme lobe theme是一款主题插件,直接可以在扩展安装 界面进行了重新布局,做了一些优化,有兴趣的…...
一文了解SpringBoot中的Aop
目录 1.什么是Aop 2.相关概念 3.相关注解 4.为什么要用Aop 5.Aop使用案例 1.什么是Aop AOP:Aspect Oriented Programming,面向切面,是Spring三大思想之一,另外两个是 IOC-控制反转 DI-依赖注入 (Autowired、Qualifier、Re…...
android系统启动流程之zygote如何创建SystemServer进程
SystemServer:是独立的进程,主要工作是管理服务的,它将启动大约90种服务Services. 它主要承担的职责是为APP的运行提供各种服务,像AMS,WMS这些服务并不是一个独立的进程, 它们其实都是SystemServer进程中需要管理的的众多服务之一…...
【awd系列】Bugku S3 AWD排位赛-9 pwn类型
文章目录 二进制下载检查分析运行二进制ida分析解题思路exp 二进制下载 下载地址:传送门 检查分析 [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 …...
使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...
学校招生小程序源码介绍
基于ThinkPHPFastAdminUniApp开发的学校招生小程序源码,专为学校招生场景量身打造,功能实用且操作便捷。 从技术架构来看,ThinkPHP提供稳定可靠的后台服务,FastAdmin加速开发流程,UniApp则保障小程序在多端有良好的兼…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
