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

简单的springboot使用sse功能

什么是sse?

1、SSE 是Server-Sent Events(服务器发送事件)

2、SSE是一种允许服务器主动向客户端推送实时更新的技术。

3、它基于HTTP协议,并使用了其长连接特性,在客户端与服务器之间建立一条持久化的连接。 通过这条连接,服务器可以实时地向客户端发送事件流,而客户端可以监听这些事件并作出相应的处理。

4、SSE是单向通信机制,即只能由服务器向客户端推送数据,客户端不能通过SSE向服务器发送数据。

5、SSE在现代浏览器和移动设备上得到了广泛的支持,是实现实时Web应用的一种有效方式。

使用流程(经测试,此方式不会丢失消息,靠谱能用!

1、引入springboot的web基本依赖,这里不细说

2、controller中

 /*** 订阅sse消息** @return*/@CrossOrigin@RequestMapping(path = "/subscribe/{userId}")public SseEmitter subscribe(@PathVariable String userId) {// 设置超时时间,0表示不过期。默认30秒,超过时间未完成会抛出异常:AsyncRequestTimeoutExceptionreturn SSEServer.connect(userId);}

3、SSEServer类

package com.orison.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;/*** @ClassName SSEServer* @Description TODO* @Author xiaoli* @Date 2022-10-26 18:00* @Version 1.0**/
@Slf4j
public class SSEServer {/*** 当前连接数*/private static AtomicInteger count = new AtomicInteger(0);private static Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>();public static SseEmitter connect(String userId){//设置超时时间,0表示不过期,默认是30秒,超过时间未完成会抛出异常SseEmitter sseEmitter = new SseEmitter(0L);//注册回调sseEmitter.onCompletion(completionCallBack(userId));sseEmitter.onError(errorCallBack(userId));sseEmitter.onTimeout(timeOutCallBack(userId));sseEmitterMap.put(userId,sseEmitter);//数量+1count.getAndIncrement();log.info("create new sse connect ,current user:{}",userId);return sseEmitter;}/*** 给指定用户发消息*/public static void sendMessage(String userId, String message){if(sseEmitterMap.containsKey(userId)){try{sseEmitterMap.get(userId).send(message);}catch (IOException e){log.error("user id:{}, send message error:{}",userId,e.getMessage());log.error("Exception:",e);}}}/*** 想多人发送消息,组播*/public static void groupSendMessage(String groupId, String message){if(sseEmitterMap!=null&&!sseEmitterMap.isEmpty()){sseEmitterMap.forEach((k,v) -> {try{if(k.startsWith(groupId)){v.send(message, MediaType.APPLICATION_JSON);}}catch (IOException e){log.error("user id:{}, send message error:{}",groupId,message);removeUser(k);}});}}public static void batchSendMessage(String message) {sseEmitterMap.forEach((k,v)->{try{v.send(message,MediaType.APPLICATION_JSON);}catch (IOException e){log.error("user id:{}, send message error:{}",k,e.getMessage());removeUser(k);}});}/*** 群发消息*/public static void batchSendMessage(String message, Set<String> userIds){userIds.forEach(userId->sendMessage(userId,message));}public static void removeUser(String userId){sseEmitterMap.remove(userId);//数量-1count.getAndDecrement();log.info("remove user id:{}",userId);}public static List<String> getIds(){return new ArrayList<>(sseEmitterMap.keySet());}public static int getUserCount(){return count.intValue();}private static Runnable completionCallBack(String userId) {return () -> {log.info("结束连接,{}",userId);removeUser(userId);};}private static Runnable timeOutCallBack(String userId){return ()->{log.info("连接超时,{}",userId);removeUser(userId);};}private static Consumer<Throwable> errorCallBack(String userId){return throwable -> {log.error("连接异常,{}",userId);removeUser(userId);};}
}

 

4、前端

<script>function createEventSource() {const eventSource = new EventSource('http://localhost:13330/device/cameraDevice/subscribe/'+getRandomString(5));eventSource.onmessage = function(event) {console.log("sse连接中");if (event.data){console.log(event);//这里就是请求streamEvents接口返回的值,此时就可以通过Ajax展示出来了}};eventSource.onerror = function(event) {console.error("sse连接失败,每5秒尝试重新连接");// 关闭当前 EventSource 实例eventSource.close();// 尝试在 5 秒后重新连接(可以根据需要调整重连间隔)setTimeout(createEventSource, 5000);};return eventSource;}// 初始化 EventSource 连接createEventSource();function getRandomString(len) {const _charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';let min = 0, max = _charStr.length - 1, _str = '';//判断是否指定长度,否则默认长度为15len = len || 15;//循环生成字符串for (var i = 0, index; i < len; i++) {index = RandomIndex(min, max, i);_str += _charStr[index];}return _str;}/*** 随机生成索引* @param min 最小值* @param max 最大值* @param i 当前获取位置*/function RandomIndex(min, max, i) {const _charStr = 'abacdefghjklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789';let index = Math.floor(Math.random() * (max - min + 1) + min),numStart = _charStr.length - 10;//如果字符串第一位是数字,则递归重新获取if (i == 0 && index >= numStart) {index = RandomIndex(min, max, i);}//返回最终索引值return index;}</script>

相关文章:

简单的springboot使用sse功能

什么是sse? 1、SSE 是Server-Sent Events&#xff08;服务器发送事件&#xff09; 2、SSE是一种允许服务器主动向客户端推送实时更新的技术。 3、它基于HTTP协议&#xff0c;并使用了其长连接特性&#xff0c;在客户端与服务器之间建立一条持久化的连接。 通过这条连接&am…...

【服务器问题】xshell 登录远程服务器卡住( 而 vscode 直接登录不上)

打开 xshell ssh 登录远程服务器&#xff1a;卡在下面这里&#xff0c;迟迟不继续 当 SSH 连接卡在 Connection established. 之后&#xff0c;但没有显示远程终端提示符时&#xff0c;这通常意味着连接已经成功建立&#xff0c;说明不是网络连接和服务器连接问题&#xff0c;…...

AI×5G 市场前瞻及应用现状

本文为《5GAI时代&#xff1a;生活方式和市场的裂变》一书读后总结及研究。 本书的上架建议是“经营”&#xff0c;内容也更偏向于市场分析。书出版于2021年&#xff0c;现在是2024年&#xff0c;可以收集整理一些例子&#xff0c;看看书里的前瞻性5GAI应用预测&#xff0c;到…...

利用 Redis 与 Lua 脚本解决秒杀系统中的高并发与库存超卖问题

1. 前言 1.1 秒杀系统中的库存超卖问题 在电商平台上&#xff0c;秒杀活动是吸引用户参与并提升销量的一种常见方式。秒杀通常会以极低的价格限量出售某些商品&#xff0c;目的是制造紧迫感&#xff0c;吸引大量用户参与。然而&#xff0c;这种活动的特殊性也带来了许多技术挑…...

【MySQL】创建数据库、用户和密码

创建数据库、用户和密码参考sql语句 drop database if exists demoshop; drop user if exists demoshop%; -- 支持emoji&#xff1a;需要mysql数据库参数&#xff1a; character_set_serverutf8mb4 create database demoshop default character set utf8mb4 collate utf8mb4_un…...

leetcode hot100【Leetcode 72.编辑距离】java实现

Leetcode 72.编辑距离 题目描述 给定两个单词 word1 和 word2&#xff0c;返回将 word1 转换为 word2 所使用的最少操作数。 你可以对一个单词执行以下三种操作之一&#xff1a; 插入一个字符删除一个字符替换一个字符 示例 1: 输入: word1 "horse", word2 &…...

腾讯阅文集团Java后端开发面试题及参考答案

Java 的基本数据类型有哪些?Byte 的数值范围是多少? Java 的基本数据类型共有 8 种,可分为 4 类: 整数类型:包括 byte、short、int 和 long。byte 占 1 个字节,其数值范围是 - 128 到 127,用于表示较小范围的整数,节省内存空间,在处理一些底层的字节流数据或对内存要求…...

protobuf实现Hbase数据压缩

目录 前置HBase数据压缩效果获取数据(反序列化) 前置 安装说明 使用说明 HBaseDDL和DML操作 HBase数据压缩 问题 在上文的datain中原文 每次写入数据会写入4个单元格的内容&#xff0c;现在希望能对其进行筛减&#xff0c;合并成1格&#xff0c;减少存储空间&#xff08;序列…...

论文阅读之方法: Single-cell transcriptomics of 20 mouse organs creates a Tabula Muris

The Tabula Muris Consortium., Overall coordination., Logistical coordination. et al. Single-cell transcriptomics of 20 mouse organs creates a Tabula Muris. Nature 562, 367–372 (2018). 论文地址&#xff1a;https://doi.org/10.1038/s41586-018-0590-4 代码地址…...

PHP语法学习(第三天)

老规矩&#xff0c;先回顾一下昨天学习的内容 PHP语法学习(第二天) 主要学习了PHP变量、变量的作用域、以及参数作用域。 今天由Tom来打开新的篇章 文章目录 echo 和 print 区别PHP echo 语句实例 PHP print 语句实例 PHP 数组创建数组利用array() 函数 数组的类型索引数组关联…...

PostgreSQL添加PostGIS扩展和存储坐标

一、安装 1、PostGIS安装&#xff1a;Getting Started | PostGIS 2、安装好后&#xff0c;执行下面sql CREATE EXTENSION postgis;SELECT PostGIS_Full_Version(); 二、使用 PostGIS文档&#xff1a;PostGIS 简介 — Introduction to PostGIS 建表&#xff1a; CREATE TAB…...

Flink四大基石之State(状态) 的使用详解

目录 一、有状态计算与无状态计算 &#xff08;一&#xff09;概念差异 &#xff08;二&#xff09;应用场景 二、有状态计算中的状态分类 &#xff08;一&#xff09;托管状态&#xff08;Managed State&#xff09;与原生状态&#xff08;Raw State&#xff09; 两者的…...

Linux中dos2unix详解

dos2unix 是一个用于将文本文件从DOS/Windows格式转换为Unix/Linux格式的工具。在不同的操作系统中&#xff0c;文本文件中的换行符表示方式是不一样的。具体来说&#xff1a; 在DOS和Windows系统中&#xff0c;换行由两个字符组成&#xff1a;回车&#xff08;Carriage Retur…...

MySQL MVCC 介绍

MVCC&#xff08;Multi-Version Concurrency Control&#xff09;是一种并发控制机制&#xff0c;用于在多个并发事务同时读写数据库时保持数据的一致性和隔离性。MVCC通过在每个数据行上维护多个版本的数据来实现。当一个事务要对数据库中的数据进行修改时&#xff0c;MVCC不会…...

Linux篇之日志管理工具Logrotate介绍并结合crontab使用

1. Logrotate介绍 logrotate 是一个用于管理和轮换日志文件的工具,通常用于 Unix 和 Linux 系统。它可以自动化日志文件的轮换、压缩、删除和邮寄等操作,确保日志文件不会无限制地增长,占用过多的磁盘空间。 2. 主要功能 轮换:定期将日志文件移动到备份目录,并生成新的…...

Vulnhub靶场 Matrix-Breakout: 2 Morpheus 练习

目录 0x00 准备0x01 主机信息收集0x02 站点信息收集0x03 漏洞查找与利用1. 文件上传2. 提权 0x04 总结 0x00 准备 下载连接&#xff1a;https://download.vulnhub.com/matrix-breakout/matrix-breakout-2-morpheus.ova 介绍&#xff1a; This is the second in the Matrix-Br…...

秒杀项目 超卖问题 详解

秒杀项目中的超卖问题详解 秒杀场景是一种高并发场景&#xff0c;用户在短时间内大量涌入抢购有限的商品。超卖问题指的是由于系统设计不合理&#xff0c;导致实际售出的商品数量超过库存数量。 1. 为什么会出现超卖问题&#xff1f; 超卖问题通常由以下原因引发&#xff1a;…...

Linux系统编程之进程控制

概述 在Linux系统中&#xff0c;创建一个新的进程后&#xff0c;如何对该进程进行有效的控制&#xff0c;是一项非常重要的操作。控制进程状态的操作主要包括&#xff1a;进程的执行、进程的等待、进程的终止等。下面&#xff0c;我们将逐个进行介绍。 进程的执行 创建进程后&a…...

集合的相关性质与定义

集合 集合 集合描述了一组对象的集合&#xff0c;而映射描述了集合之间的对应关系。 集合 集合是由一组无序的&#xff0c;互不相同的对象组成的整体&#xff0c;集合中的对象称为元素或成员。集合可以用大括号{}表示,元素之间用逗号进行分隔。 定义&#xff1a; 集合 A …...

pytest自定义命令行参数

实际使用场景&#xff1a;pytest运行用例的时候&#xff0c;启动mitmdump进程试试抓包&#xff0c;pytest命令行启动的时候&#xff0c;传入mitmdump需要的参数&#xff08;1&#xff09;抓包生成的文件地址 &#xff08;2&#xff09;mitm的proxy设置 # 在pytest的固定文件中…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】

1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件&#xff08;System Property Definition File&#xff09;&#xff0c;用于声明和管理 Bluetooth 模块相…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程&#xff1a;首先由HR先筛选一部分简历后&#xff0c;在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如&#xff1a;Boss直聘&#xff08;招聘方平台&#xff09; 直接按照条件进行筛选 例如&#xff1a…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

C++.OpenGL (14/64)多光源(Multiple Lights)

多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...