当前位置: 首页 > 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…...

基于图像梯度的瞳孔中心定位:eyeLike开源项目的技术实现解析

基于图像梯度的瞳孔中心定位&#xff1a;eyeLike开源项目的技术实现解析 【免费下载链接】eyeLike A webcam based pupil tracking implementation. 项目地址: https://gitcode.com/gh_mirrors/ey/eyeLike 在计算机视觉领域&#xff0c;如何仅使用普通网络摄像头实现精准…...

《Java 创建线程有哪些方式?一篇给你讲明白》

正文一、开头先说人话兄弟们&#xff0c;Java 里说“创建线程”&#xff0c;听起来像一件事&#xff0c;实际上像点烧烤套餐&#xff1a;有的是单点有的是叫老板帮你烤有的是点完还能等结果有的是直接包年办会员看起来都能“开个线程”&#xff0c;但姿势不一样&#xff0c;后劲…...

计算机组成原理知识问答系统:基于LiuJuan20260223Zimage的实现

计算机组成原理知识问答系统&#xff1a;基于LiuJuan20260223Zimage的实现 最近在尝试一些AI应用时&#xff0c;我发现了一个挺有意思的镜像&#xff0c;叫LiuJuan20260223Zimage。它不是一个通用的大模型&#xff0c;而是专门针对计算机组成原理这个领域做了深度优化。简单来…...

3分钟快速完成B站m4s转MP4:免费跨平台解决方案

3分钟快速完成B站m4s转MP4&#xff1a;免费跨平台解决方案 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否遇到过B站缓存视频无法在其他设…...

公共字段自动填充:告别重复的手动 setCreateTime

一、为什么需要自动填充&#xff1f;几乎每个业务系统里面&#xff0c;数据库都有几个“公共字段”。比较典型的就是&#xff1a;create_time / createTime&#xff1a;创建时间 update_time / updateTime&#xff1a;更新时间 create_user / createUser&#xff1a;创建人 upd…...

告别预编译包:手把手教你为你的Qt项目定制编译Windows静态库(Qt5.15/6.5 + CMake实战)

从零构建Qt静态库&#xff1a;为商业项目打造极致精简的Windows部署方案 当你的Qt应用程序需要交付给客户时&#xff0c;几十MB的DLL依赖文件往往成为部署的噩梦。想象一下&#xff0c;一个简单的工具软件因为QtCore、QtGui等动态库的拖累&#xff0c;安装包膨胀到上百MB——这…...

丹青识画系统快速部署指南:小白友好,轻松玩转AI影像艺术鉴赏

丹青识画系统快速部署指南&#xff1a;小白友好&#xff0c;轻松玩转AI影像艺术鉴赏 1. 认识丹青识画系统 你有没有遇到过这样的情况&#xff1f;看到一张触动心弦的照片&#xff0c;却找不到合适的文字来描述它的意境。传统的AI图像识别只能告诉你"这是一座山"、&…...

从SSC生成的代码到实际跑通:我的STM32F103 EtherCAT从站移植与调试全记录

从SSC生成代码到实际运行的STM32F103 EtherCAT从站开发实战指南 1. 引言&#xff1a;EtherCAT从站开发的挑战与机遇 在工业自动化领域&#xff0c;EtherCAT凭借其卓越的实时性能和灵活的拓扑结构&#xff0c;已成为主流工业以太网协议之一。对于嵌入式开发者而言&#xff0c;实…...

LabVIEW里用Python节点处理复杂数据?三种方法帮你搞定(含NumPy数组转换)

LabVIEW与Python深度集成&#xff1a;复杂数据结构高效处理指南 在工业自动化和测试测量领域&#xff0c;LabVIEW以其图形化编程优势长期占据重要地位&#xff0c;而Python则凭借丰富的数据科学库成为算法开发的首选。当两者相遇&#xff0c;如何突破基础数据类型限制&#xff…...

从硬件拓扑到软件调度:深入理解NUMA如何影响你的K8s和Docker容器性能

从硬件拓扑到软件调度&#xff1a;深入理解NUMA如何影响你的K8s和Docker容器性能 在云原生技术栈中&#xff0c;性能调优往往聚焦于CPU配额和内存限制&#xff0c;却忽略了硬件架构对容器表现的深层影响。当我们在Kubernetes集群中部署高吞吐量应用时&#xff0c;经常会遇到一个…...