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

Spring Boot中使用Server-Sent Events (SSE) 实现实时数据推送教程

一、简介

Server-Sent Events (SSE) 是HTML5引入的一种轻量级的服务器向浏览器客户端单向推送实时数据的技术。在Spring Boot框架中,我们可以很容易地集成并利用SSE来实现实时通信。

二、依赖添加

在Spring Boot项目中,无需额外引入特定的依赖,因为Spring Web MVC模块已经内置了对SSE的支持。

辅助Maven

<!-- 集成beetl --> <dependency> <groupId>com.ibeetl</groupId> <artifactId>beetl-framework-starter</artifactId> <version>1.2.30.RELEASE</version> </dependency> <!-- 集成hutool工具类简便操作 --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.3.10</version> </dependency>

三、编写核心SSE Client

@Slf4j @Component public class SseClient { private static final Map<String, SseEmitter> sseEmitterMap = new ConcurrentHashMap<>(); /** * 创建连接 */ public SseEmitter createSse(String uid) { //默认30秒超时,设置为0L则永不超时 SseEmitter sseEmitter = new SseEmitter(0l); //完成后回调 sseEmitter.onCompletion(() -> { log.info("[{}]结束连接...................", uid); sseEmitterMap.remove(uid); }); //超时回调 sseEmitter.onTimeout(() -> { log.info("[{}]连接超时...................", uid); }); //异常回调 sseEmitter.onError( throwable -> { try { log.info("[{}]连接异常,{}", uid, throwable.toString()); sseEmitter.send(SseEmitter.event() .id(uid) .name("发生异常!") .data("发生异常请重试!") .reconnectTime(3000)); sseEmitterMap.put(uid, sseEmitter); } catch (IOException e) { e.printStackTrace(); } } ); try { sseEmitter.send(SseEmitter.event().reconnectTime(5000)); } catch (IOException e) { e.printStackTrace(); } sseEmitterMap.put(uid, sseEmitter); log.info("[{}]创建sse连接成功!", uid); return sseEmitter; } /** * 给指定用户发送消息 * */ public boolean sendMessage(String uid,String messageId, String message) { if (StrUtil.isBlank(message)) { log.info("参数异常,msg为null", uid); return false; } SseEmitter sseEmitter = sseEmitterMap.get(uid); if (sseEmitter == null) { log.info("消息推送失败uid:[{}],没有创建连接,请重试。", uid); return false; } try { sseEmitter.send(SseEmitter.event().id(messageId).reconnectTime(1*60*1000L).data(message)); log.info("用户{},消息id:{},推送成功:{}", uid,messageId, message); return true; }catch (Exception e) { sseEmitterMap.remove(uid); log.info("用户{},消息id:{},推送异常:{}", uid,messageId, e.getMessage()); sseEmitter.complete(); return false; } } /** * 断开 * @param uid */ public void closeSse(String uid){ if (sseEmitterMap.containsKey(uid)) { SseEmitter sseEmitter = sseEmitterMap.get(uid); sseEmitter.complete(); sseEmitterMap.remove(uid); }else { log.info("用户{} 连接已关闭",uid); } } }
  1. 创建SSE 端点

    创建一个SseEmitter,用uid进行标识,uid可以是用户标识符,也可以是业务标识符。可以理解为通信信道标识。

  2. 通过端点发送事件

    可以定时或在事件发生时调用sseEmitter.send()方法来发送事件。

  3. 关闭端点连接

四、编写Controller

@Controller public class IndexAction { @Autowired private SseClient sseClient; @GetMapping("/") public String index(ModelMap model) { String uid = IdUtil.fastUUID(); model.put("uid",uid); return "index"; } @CrossOrigin @GetMapping("/createSse") public SseEmitter createConnect(String uid) { return sseClient.createSse(uid); } @CrossOrigin @GetMapping("/sendMsg") @ResponseBody public String sseChat(String uid) { for (int i = 0; i < 10; i++) { sseClient.sendMessage(uid, "no"+i,IdUtil.fastUUID()); } return "ok"; } /** * 关闭连接 */ @CrossOrigin @GetMapping("/closeSse") public void closeConnect(String uid ){ sseClient.closeSse(uid); } }

1,打开页面默认页面,传递端点标识。

2,连接端点(/createSse),页面需要使用

3,通过ajax(/sendMsg),触发后端业务(循环十条数据发往页面),向页面发送消息。

4,主动关闭连接(/closeSse)

五、前端接收与处理

  1. HTML & JavaScript

    在前端页面,使用EventSource API订阅SSE endpoint:

    Html

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="con"></div> <script> let chat = document.getElementById("con"); if (window.EventSource) { //创建sse eventSource = new EventSource(`/createSse?uid=${uid}`); eventSource.onopen = function (event) { console.log('SSE链接成功'); } eventSource.onmessage = function (event) { if(event.data){ chat.innerHTML += event.data + '<br/>'; //console.log('后端返回的数据:', data.value); } } eventSource.onerror = (error) => { console.log('SSE链接失败'); }; } else { alert("你的浏览器不支持SSE"); } </script> </body> </html>

在这个例子中,前端每接收到一次SSE推送的事件,就会在id为"con"的元素中追加数据。

六、注意事项

  • 当客户端断开连接时,SseEmitter会抛出IOException,所以务必捕获并处理这种异常,通常情况下我们会调用emitter.complete()emitter.completeWithError()来关闭SseEmitter。
  • SSE连接是持久性的,长时间保持连接可能需要处理超时和重连问题。
  • 考虑到资源消耗,对于大量的并发客户端,可能需要采用连接池或者其他优化策略。

总结,Spring Boot中利用SSE实现实时数据推送既简单又实用,特别适合实时更新频率不高、实时性要求不严苛的场景。同时,在高并发场景下需要注意资源管理和优化策略的选择。

http://www.jsqmd.com/news/450474/

相关文章:

  • Java农产品电商平台源码(含完整文档)基于JSP+SSM框架的JavaWeb/JavaEE商城系统
  • Flutter 三方库 sqlite_crdt 的鸿蒙化适配指南 - 掌控分布式存储资产、精密 CRDT 治理实战、鸿蒙级同步专家
  • Flutter 三方库 steamworks 的鸿蒙化适配指南 - 掌控游戏引擎资产、Steam 集成实战、鸿蒙级精密分发专家
  • Flutter 三方库 concurrent_queue 的鸿蒙化适配指南 - 掌控高并发队列资产、精密任务治理实战、鸿蒙级吞吐专家
  • Flutter 三方库 drift_dev 的鸿蒙化适配指南 - 掌控数据库资产、精密 Drift 治理实战、鸿蒙级存储专家
  • Flutter 三方库 data_fixture_dart 的鸿蒙化适配指南 - 掌控数据资产、精密 Mock 治理实战、鸿蒙级质量专家
  • Flutter 三方库 dartemis 的鸿蒙化适配指南 - 掌控数据资产、精密 ECS 架构治理实战、鸿蒙级游戏专家
  • Spring Boot环境配置
  • 当学术彻底“放飞自我”,会发生什么?我分析了800篇奇葩论文
  • Spring Boot3.3.X整合Mybatis-Plus
  • Lua 的 UTF-8 模块
  • Matlab入门速成七十二:(一文识记所有代码)均值方差相关系数,分析数据的特征
  • Flutter 三方库 kdtree 的鸿蒙化适配指南 - 掌控空间搜索资产、精密算法治理实战、鸿蒙级算力专家
  • 洋州影院购票管理系统信息管理系统源码-SpringBoot后端+Vue前端+MySQL【可直接运行】
  • Spring Cloud Nacos配置管理
  • Flutter 三方库 dart_extensions_methods 的鸿蒙化适配指南 - 掌控语法扩展资产、精密工程治理实战、鸿蒙级开发专家
  • Linux下如何使用Git工具:从安装到实战的完整指南
  • Spring Cloud Alibaba 组件版本选择
  • SpringBoot+Vue 学院个人信息管理系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】
  • 基于Java+SSM+Flask疫情信息管理系统(源码+LW+调试文档+讲解等)/疫情数据管理系统/疫情信息统计软件/疫情信息管理工具/公共卫生信息管理系统/疫情监控平台/实时疫情信息系统
  • Spring Integration + MQTT
  • 使用OpenClaw,搭建私人QQ助理
  • Flutter 三方库 youtube_caption_scraper 的鸿蒙化适配指南 - 掌控多媒体字幕资产、精密 Scraper 治理实战、鸿蒙级内容专家
  • 企业级养老院管理系统管理系统源码|SpringBoot+Vue+MyBatis架构+MySQL数据库【完整版】
  • 前后端分离校车调度管理系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程
  • Flutter 三方库 nyxx_commands 的鸿蒙化适配指南 - 掌控指令资产、精密 Discord Bot 治理实战、鸿蒙级交互专家
  • Flutter 三方库 delete_un_used_assets 的鸿蒙化适配指南 - 掌控清理资产、精密冗余治理实战、鸿蒙级瘦身专家
  • R语言,linux及服务器远程配置
  • Spring cloud alibaba集成nacos 报错:[Nacos Config] config[dataId=xxx, group=DEFAULT_GROUP] is empty 解决
  • 流水潺潺:探寻Linux下C语言文件流的诗意实现