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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/154897.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何保障亚马逊多账户的安全,防止关联?

在亚马逊平台上拥有多个账户可以扩大销售渠道&#xff0c;但同时也需要注意账户的安全&#xff0c;以防止被关联。本文将介绍一些重要的措施&#xff0c;帮助您保护亚马逊多账户的安全&#xff0c;预防账号关联。 一、亚马逊关联是什么&#xff1f; 在亚马逊平台上&#xff0…

单节点服务架构

单节点的服务架构&#xff1a; LNMP l:lilnux系统 n:nginx静态页面&#xff0c;转发动态请求 m:mysql数据库&#xff0c;后端服务器&#xff0c;保存用户和密码信息&#xff0c;以及论坛的信息 p:PHP&#xff0c;处理动态请求&#xff0c;动态请求转发数据库&#xff0c;然…

3PC(三阶段提交)

三阶段提交 3PC&#xff08;Three-Phase Commit&#xff09;是一种分布式系统中用于实现事务一致性的协议&#xff0c;它是在2PC&#xff08;Two-Phase Commit&#xff09;的基础上发展而来&#xff0c;旨在解决2PC的一些缺点。与2PC的两个阶段&#xff08;准备和提交&#xf…

iptables的一次修复日志

iptables的一次修复日志 搭建配置wireguard后&#xff0c;使用内网连接设备十分方便&#xff0c;我采用的是星型连接&#xff0c;即每个节点都连接到中心节点&#xff0c;但是突然发生了重启wg后中心节点不转发流量的问题&#xff0c;即每个接入的节点只能与中心节点连接&…

M2 Mac Xcode编译报错 ‘***.framework/‘ for architecture arm64

In /Users/fly/Project/Pods/YYKit/Vendor/WebP.framework/WebP(anim_decode.o), building for iOS Simulator, but linking in object file built for iOS, file /Users/fly/Project/Pods/YYKit/Vendor/WebP.framework/WebP for architecture arm64 这是我当时编译模拟器时报…

Mars3d-vue最简项目模板集成使用Mars3d的UI控件样板

备注说明&#xff1a; 1.小白可看步骤一二&#xff0c;进阶小白可直接看步骤三 步骤一&#xff1a;新建文件夹<uitest>&#xff0c;在mars3d仓库拉一份最简项目模板&#xff1a; git clone mars3d-vue-template: Vue3.x 技术栈下的Mars3D项目模板 步骤二&#xff1a;运…

java: 无法访问org.mybatis.spring.annotation.MapperScan

java: 无法访问org.mybatis.spring.annotation.MapperScan错误的类文件: /E:/maven/repository/org/mybatis/mybatis-spring/3.0.1/mybatis-spring-3.0.1.jar!/org/mybatis/spring/annotation/MapperScan.class类文件具有错误的版本 61.0, 应为 52.0请删除该文件或确保该文件位…

本地部署 EmotiVoice易魔声 多音色提示控制TTS

本地部署 EmotiVoice易魔声 多音色提示控制TTS EmotiVoice易魔声 介绍ChatGLM3 Github 地址部署 EmotiVoice准备模型文件准备预训练模型推理 EmotiVoice易魔声 介绍 EmotiVoice是一个强大的开源TTS引擎&#xff0c;支持中英文双语&#xff0c;包含2000多种不同的音色&#xff…

网站为什么一定要安装SSL证书

随着互联网的普及和发展&#xff0c;网络安全问题日益凸显。在这个信息爆炸的时代&#xff0c;保护用户隐私和数据安全已经成为各大网站和企业的首要任务。而SSL证书作为一种网络安全技术&#xff0c;已经成为网站必备的安全工具。那么&#xff0c;为什么网站一定要安装SSL证书…

electron项目开机自启动

一、效果展示&#xff1a;界面控制是否需要开机自启动 二、代码实现&#xff1a; 1、在渲染进程login.html中&#xff0c;画好界面&#xff0c;默认勾选&#xff1b; <div class"intro">开机自启动 <input type"checkbox" id"checkbox&quo…

C++纯虚函数和抽象类 制作饮品案例(涉及知识点:继承,多态,实例化继承抽象类的子类,多文件实现项目)

一.纯虚函数的由来 在多态中&#xff0c;通常父类中虚函数的实现是毫无意义的&#xff0c;主要都是调用子类重写的内容。例如&#xff1a; #include<iostream>using namespace std;class AbstractCalculator { public:int m_Num1;int m_Num2;virtual int getResult(){r…

PHP手动为第三方类添加composer自动加载

有时候我们要使用的第三方的类库&#xff08;SDK&#xff09;没用用composer封装好&#xff0c;无法用composer进行安装&#xff0c;怎么办呢&#xff1f;&#xff1f;&#xff1f; 步骤如下&#xff1a; 第一步、下载需要的SDK文件包&#xff0c;把它放在vendor目录下 第二步…

SSM高考志愿辅助推荐系统-计算机毕业设计附源码21279

目 录 摘要 1 绪论 1.1 研究背景 1.2研究意义 1.3论文结构与章节安排 2 高考志愿辅助推荐系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性分析 2.2.2 非功能性分析 2.3 系统用例分析 2…

竞赛选题 身份证识别系统 - 图像识别 深度学习

文章目录 0 前言1 实现方法1.1 原理1.1.1 字符定位1.1.2 字符识别1.1.3 深度学习算法介绍1.1.4 模型选择 2 算法流程3 部分关键代码 4 效果展示5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计 图像识别 深度学习 身份证识别…

java面试-zookeeper

1、什么是zap协议 ZAB 协议总共包含以下两部分内容&#xff1a; ZAB 协议通过两阶段提交的方式来确保分布式系统的一致性。这两阶段分别是&#xff1a;准备阶段和提交阶段。在准备阶段&#xff0c;一个节点&#xff08;称为 Leader&#xff09;向其他节点&#xff08;称为 Fol…

K8S精进之路-控制器Deployment-(1)

在K8S中&#xff0c;最小运行单位为POD,它是一个逻辑概念&#xff0c;其实是一组共享了某些资源的容器组。POD是能运行多个容器的&#xff0c;Pod 里的所有容器&#xff0c;共享的是同一个 Network Namespace&#xff0c;并且可以声明共享同一个 Volume。在POD中能够hold住网络…

Python数据分析实战-爬取以某个关键词搜索的最新的500条新闻的标题和链接(附源码和实现效果)

实现功能 通过百度引擎&#xff0c;爬取以“开源之夏”为搜索关键词最新的500条新闻的标题和链接 实现代码 1.安装所需的库&#xff1a;你需要安装requests和beautifulsoup4库。可以使用以下命令通过pip安装&#xff1a; pip install requests beautifulsoup42.发起搜索请求…

linux启动redis时报错

2.WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128 意思大概是 tcp 连接数设置为 128 太小了 解决方案&#xff1a; ①修改配置文件 vim /etc/sysctl.conf &#xff08;1&#xff09;…

【AT模式连接ONENET】ONENET可视化平台的使用

02 ONENET可视化平台的使用 ATCWMODE1 设置模式 ATCWDHCP1,1 启动DHCP功能 ①ATCWJAP"ssid","password" ATCWJAP“123456789”&#xff0c;“wang020118” ②ATMQTTUSERCFG0,1,"设备名字","设备ID","你的鉴权信息""…

Hotspot启动原理(二)

关于Hotspot虚拟机的启动原理和过程。Hotspot虚拟机是Java虚拟机的一种实现&#xff0c;它在JVM领域中具有广泛的应用。在Hotspot虚拟机的启动过程中&#xff0c;会经历一系列的步骤&#xff0c;包括初始化、类加载、字节码解释执行、JIT编译、垃圾回收等环节。具体来说&#x…