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

springboot -sse -flux 服务器推送消息

先说BUG处理,遇到提示异步问题 Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported>" to servlet and filter declarations in web.xml.

springboot在@WebFilter注解处,加入urlPatterns = { "/*" },asyncSupported = true

springmvc在web.xml处理

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"version="3.0"><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>ASYNC</dispatcher>
</filter-mapping>
  • demo1,服务器间隔一定时间推送内容
  1.     接口方法
@GetMapping(path = "/sse/{userId}",produces = MediaType.TEXT_EVENT_STREAM_VALUE )public Flux<ServerSentEvent<String>> sse(@PathVariable String userId) {// 每两秒推送一次return Flux.interval(Duration.ofSeconds(2)).map(seq->Tuples.of(seq, LocalDateTime.now())).log()//序号和时间.map(data-> ServerSentEvent.<String>builder().id(userId).data(data.getT1().toString()).build());//推送内容}

2.前端代码

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"/><title>服务器推送事件</title>
</head>
<body>
<div>    <div id="data"></div>    <div id="result"></div><br/>
</div>
<script th:inline="javascript" >
//服务器推送事件
if (typeof (EventSource) !== "undefined") { var source1 = new EventSource("http://localhost:9000/api/admin/test/sse/1");//当抓取到消息时source1.onmessage = function (evt) {document.getElementById("data").innerHTML = document.getElementById("data").innerHTML+"股票行情:" + evt.data;};
} else {//注意:ie浏览器不支持document.getElementById("result").innerHTML = "抱歉,你的浏览器不支持 server-sent 事件...";  var xhr;var xhr2;if (window.XMLHttpRequest){//IE7+, Firefox, Chrome, Opera, Safari浏览器支持该方法xhr=new XMLHttpRequest();xhr2=new XMLHttpRequest();}else{//IE6, IE5 浏览器不支持,使用ActiveXObject方法代替xhr=new ActiveXObject("Microsoft.XMLHTTP");xhr2=new ActiveXObject("Microsoft.XMLHTTP");}console.log(xhr);console.log(xhr2);xhr.open('GET', '/sse/countDown');xhr.send(null);//发送请求xhr.onreadystatechange = function() {console.log("s响应状态:" + xhr.readyState);//2是空响应,3是响应一部分,4是响应完成if (xhr.readyState > 2) {//这儿可以使用response(对应json)与responseText(对应text)var newData = xhr.response.substr(xhr.seenBytes);newData = newData.replace(/\n/g, "#");newData = newData.substring(0, newData.length - 1);var data = newData.split("#");console.log("获取到的数据:" + data);document.getElementById("result").innerHTML = data;//长度重新赋值,下次截取时需要使用xhr.seenBytes = xhr.response.length;}}xhr2.open('GET', '/sse/retrieve');xhr2.send(null);//发送请求xhr2.onreadystatechange = function() {console.log("s响应状态:" + xhr2.readyState);//0: 请求未初始化,2 请求已接收,3 请求处理中,4  请求已完成,且响应已就绪if (xhr2.readyState > 2) {//这儿可以使用response(对应json)与responseText(对应text)var newData1 = xhr2.response.substr(xhr2.seenBytes);newData1 = newData1.replace(/\n/g, "#");newData1 = newData1.substring(0, newData1.length - 1);var data1 = newData1.split("#");console.log("获取到的数据:" + data1);document.getElementById("data").innerHTML = data1;//长度重新赋值,下次截取时需要使用xhr2.seenBytes = xhr2.response.length;}}
}
</script>
</body>
</html>
  • demo2 订阅服务器消息,服务器send推送消息完成后,关闭sse.close

1.接口方法以及工具类

@GetMapping(path = "/sse/sub",produces = MediaType.TEXT_EVENT_STREAM_VALUE )
public SseEmitter subscribe(@RequestParam String questionId,HttpServletResponse response) {// 简单异步发消息 ====//questionId 订阅id,id对应了sse对象new Thread(() -> {try {Thread.sleep(1000);for (int i = 0; i < 10; i++) {Thread.sleep(500);SSEUtils.pubMsg(questionId, questionId + " - kingtao come " + i);}} catch (Exception e) {e.printStackTrace();} finally {// 消息发送完关闭订阅SSEUtils.closeSub(questionId);}}).start();// =================return SSEUtils.addSub(questionId);}

工具类

import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;public class SSEUtils {// timeoutprivate static Long DEFAULT_TIME_OUT = 2*60*1000L;// 订阅表private static Map<String, SseEmitter> subscribeMap = new ConcurrentHashMap<>();/** 添加订阅 */public static SseEmitter addSub(String questionId) {if (null == questionId || "".equals(questionId)) {return null;}SseEmitter emitter = subscribeMap.get(questionId);if (null == emitter) {emitter = new SseEmitter(DEFAULT_TIME_OUT);subscribeMap.put(questionId, emitter);}return emitter;}/** 发消息 */public static void pubMsg(String questionId, String msg) {SseEmitter emitter = subscribeMap.get(questionId);if (null != emitter) {try {// 更规范的消息结构看源码emitter.send(SseEmitter.event().data(msg));} catch (Exception e) {// e.printStackTrace();}}}/*** 关闭订阅 * @param questionId*/public static void closeSub(String questionId) {SseEmitter emitter = subscribeMap.get(questionId);if (null != emitter) {try {emitter.complete();subscribeMap.remove(questionId);} catch (Exception e) {e.printStackTrace();}}}
}

2.前端代码

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>sse</title>
</head>
<body>
<div><label>问题id</label><input type="text" id="questionId"><button onclick="subscribe()">订阅</button><hr><label>F12-console控制台查看消息</label>
</div><script>function subscribe() {let questionId = document.getElementById('questionId').value;let url = 'http://localhost:9000/api/admin/test/sse/sub?questionId=' + questionId;let eventSource = new EventSource(url);eventSource.onmessage = function (e) {console.log(e.data);};eventSource.onopen = function (e) {console.log(e,1);// todo};eventSource.onerror = function (e) {// todoconsole.log(e,2);eventSource.close()};}
</script>
</body>
</html>

相关文章:

springboot -sse -flux 服务器推送消息

先说BUG处理&#xff0c;遇到提示异步问题 Async support must be enabled on a servlet and for all filters involved in async request processing. This is done in Java code using the Servlet API or by adding "<async-supported>true</async-supported&…...

js进阶笔记之原型,原型链

目录 1、原型对象 constructor 属性 对象原型 2、原型链 3、instanceof 4、原型继承 1、原型对象 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候再一个一个的依次调用就可以了。 面向对象是把事务分解成为…...

【DevOps】Git 图文详解(四):Git 使用入门

本系列包含&#xff1a; Git 图文详解&#xff08;一&#xff09;&#xff1a;简介及基础概念Git 图文详解&#xff08;二&#xff09;&#xff1a;Git 安装及配置Git 图文详解&#xff08;三&#xff09;&#xff1a;常用的 Git GUIGit 图文详解&#xff08;四&#xff09;&a…...

Jquery ajax 同步阻塞引起的UI线程阻塞的坑(loading图片显示不出来 )

Jquery ajax 同步阻塞引起的UI线程阻塞的坑&#xff08;loading图片显示不出来&#xff0c;layer.load延迟&#xff09;jax重新获取数据刷新页面功能&#xff0c;因为ajax属于耗时操作&#xff0c;想在获取数据且加载页面时显示加载遮罩层&#xff0c;结果发现了ajax的好多坑。…...

读书笔记——《黑猩猩的政治》

前言 弗朗斯德瓦尔&#xff08;Frans de Waal)的代表作《黑猩猩政治》成书于1982年&#xff0c;是它的首部书籍作品&#xff0c;也是美国国会新任议员的被推荐读物。之前看的他另一部作品的《万智有灵》是2016年的作品&#xff0c;时间跨度居然这么大。《万智有灵》介绍了许多…...

此处不允许使用特性namespace

1.DOCTYPE 后面改成 mapper 2.PUBLIC一行中的Config改为Mapper 3.将下一行config变为小写的mapper <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.or…...

随笔记录-springmvc_ResourceHandlerRegistry+ResourceHttpRequestHandler

环境&#xff1a;springboot-2.7.5 配置文件配置静态资源映射 springboot配置静态资源映射方式是通过 WebMvcAutoConfiguration 实现的 spring: # resources: # # 自springboot 2.5.5之后&#xff0c;该属性已经被废弃&#xff0c;使用spring.web.resources.static-locat…...

Redis面试内容,Redis过期策略,Redis持久化方式,缓存穿透、缓存击穿和缓存雪崩,以及解决办法

文章目录 一、redis什么是RedisRedis使用场景1、缓存2、数据共享[分布式](https://so.csdn.net/so/search?q分布式&spm1001.2101.3001.7020)3、分布式锁4、全局ID5、计数器6、限流7、位统计 Redis有5中数据类型&#xff1a; SSHLZRedis中一个key的值每天12点过期&#xff…...

爱上C语言:scanf、gets以及getchar输入字符串你真的懂了吗

&#x1f680; 作者&#xff1a;阿辉不一般 &#x1f680; 你说呢&#xff1a;不服输的你&#xff0c;他们拿什么赢 &#x1f680; 专栏&#xff1a;爱上C语言 &#x1f680;作图工具&#xff1a;draw.io(免费开源的作图网站) 如果觉得文章对你有帮助的话&#xff0c;还请点赞…...

ubuntu Setforeground 前台应用切换

场景分析 有这样一个系统&#xff0c;一个服务主进程用于接收指令&#xff0c;其它服务是独立的gui 程序&#xff0c;服务进程根据命令将对应的gui 程序切换到前台。 windows 平台有Setforeground 这个api&#xff0c;可以根据进程ID&#xff0c;将某个应用的窗口切换到前台。…...

【Java 进阶篇】从Java对象到JSON:Jackson的魔法之旅

在现代的软件开发中&#xff0c;处理数据的能力是至关重要的。而当我们谈及数据格式时&#xff0c;JSON&#xff08;JavaScript Object Notation&#xff09;通常是首选。为了在Java中轻松地将对象转换为JSON&#xff0c;我们需要一种强大而灵活的工具。这时&#xff0c;Jackso…...

HarmonyOS ArkTS语言,运行Hello World(二)

一、认识DevEco Studio界面 进入IDE后&#xff0c;我们首先了解一下基础的界面。整个IDE的界面大致上可以分为四个部分&#xff0c;分别是代码编辑区、通知栏、工程目录区以及预览区。 代码编辑区 1、中间的是代码编辑区&#xff0c;你可以在这里修改你的代码&#xff0c;以…...

四、文件包含漏洞

一、文件包含漏洞 解释&#xff1a;文件包含漏洞是一种注入型漏洞&#xff0c;其本质就是输入一段用户能够控制的脚本或者代码&#xff0c;并让服务端执行&#xff1b;其还能够使得服务器上的源代码被读取&#xff0c;在PHP里面我们把可重复使用的函数写入到单个文件中&#x…...

Java中基于SSM框架的数据保存方法与日期处理

​ 一、详解 在SSM框架中&#xff0c;保存数据通常涉及到服务层和数据访问层。服务层处理业务逻辑&#xff0c;而数据访问层负责与数据库进行交互。 二、代码 Override public void save(Student student) { Date date new Date(); SimpleDateFormat format new Sim…...

编译器核心技术概览

编译技术是一门庞大的学科&#xff0c;我们无法对其做完善的讲解。但不同用途的编译器或编译技术的难度可能相差很大&#xff0c;对知识的掌握要求也会相差很多。如果你要实现诸如 C、JavaScript 这类通用用途语言&#xff08;general purpose language&#xff09;&#xff0c…...

本地训练,开箱可用,Bert-VITS2 V2.0.2版本本地基于现有数据集训练(原神刻晴)

按照固有思维方式&#xff0c;深度学习的训练环节应该在云端&#xff0c;毕竟本地硬件条件有限。但事实上&#xff0c;在语音识别和自然语言处理层面&#xff0c;即使相对较少的数据量也可以训练出高性能的模型&#xff0c;对于预算有限的同学们来说&#xff0c;也没必要花冤枉…...

守护进程的理解

什么是守护进程 daemon False # 是否以守护进程方式运行&#xff0c;True守护&#xff0c;False 非守护 在这段代码中&#xff0c;daemon 变量的值决定了进程是否以守护进程方式运行。如果 daemon 的值为 True&#xff0c;则表示进程将以守护进程方式运行&#xff0c;否则为…...

VMware虚拟机的安装教程

安装VMware虚拟机的步骤如下&#xff1a; 首先&#xff0c;你需要从VMware官方网站&#xff08;https://www.vmware.com&#xff09;下载VMware虚拟机软件安装程序。 一旦下载完成&#xff0c;双击运行安装程序。 在安装程序启动后&#xff0c;你将看到一个欢迎界面。点击"…...

Linux环境搭建(tomcat,jdk,mysql下载)

是否具备环境&#xff08;前端node&#xff0c;后端环境jdk&#xff09;安装jdk,配置环境变量 JDK下载 - 编程宝库 (codebaoku.com) 进入opt目录 把下好的安装包拖到我们的工具中 把解压包解压 解压完成&#xff0c;可以删除解压包 复制解压文件的目录&#xff0c;配置环境变量…...

80万条中文ChatGPT多轮对话数据集

80万条中文ChatGPT多轮对话数据集 代码代码地址代码解析 代码 import json import numpy as np from tqdm import tqdm import redef find_chinese_text(text):pattern re.compile(r[^\u4e00-\u9fff])return pattern.sub(, text)with open("E:/data_sets/multiturn_chat…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

XCTF-web-easyupload

试了试php&#xff0c;php7&#xff0c;pht&#xff0c;phtml等&#xff0c;都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接&#xff0c;得到flag...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装&#xff08;Encapsulation&#xff09; 定义&#xff1a;将数据&#xff08;属性&#xff09;和操作数据的方法绑定在一起&#xff0c;通过访问控制符&#xff08;private、protected、public&#xff09;隐藏内部实现细节。示例&#xff1a; public …...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

SpringCloudGateway 自定义局部过滤器

场景&#xff1a; 将所有请求转化为同一路径请求&#xff08;方便穿网配置&#xff09;在请求头内标识原来路径&#xff0c;然后在将请求分发给不同服务 AllToOneGatewayFilterFactory import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; impor…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...