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

📅 发布时间:2026/7/7 10:35:04 👁️ 浏览次数:
Spring Boot中使用Server-Sent Events (SSE) 实现实时数据推送教程
一、简介Server-Sent Events (SSE) 是HTML5引入的一种轻量级的服务器向浏览器客户端单向推送实时数据的技术。在Spring Boot框架中我们可以很容易地集成并利用SSE来实现实时通信。二、依赖添加在Spring Boot项目中无需额外引入特定的依赖因为Spring Web MVC模块已经内置了对SSE的支持。辅助Maven!-- 集成beetl -- dependency groupIdcom.ibeetl/groupId artifactIdbeetl-framework-starter/artifactId version1.2.30.RELEASE/version /dependency !-- 集成hutool工具类简便操作 -- dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.3.10/version /dependency三、编写核心SSE ClientSlf4j Component public class SseClient { private static final MapString, 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); } } }创建SSE 端点创建一个SseEmitter用uid进行标识uid可以是用户标识符也可以是业务标识符。可以理解为通信信道标识。通过端点发送事件可以定时或在事件发生时调用sseEmitter.send()方法来发送事件。关闭端点连接四、编写ControllerController 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, noi,IdUtil.fastUUID()); } return ok; } /** * 关闭连接 */ CrossOrigin GetMapping(/closeSse) public void closeConnect(String uid ){ sseClient.closeSse(uid); } }1打开页面默认页面传递端点标识。2连接端点/createSse页面需要使用3通过ajax/sendMsg触发后端业务(循环十条数据发往页面)向页面发送消息。4主动关闭连接(/closeSse)五、前端接收与处理HTML JavaScript在前端页面使用EventSource API订阅SSE endpointHtml!DOCTYPE html html langen head meta charsetUTF-8 titleTitle/title /head body div idcon/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实现实时数据推送既简单又实用特别适合实时更新频率不高、实时性要求不严苛的场景。同时在高并发场景下需要注意资源管理和优化策略的选择。