SSE Emitter在Spring Boot和Vue中的简单使用

1、确保你的 pom.xml 包含 Spring Web 依赖

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2、创建 SSE 控制器

java 复制代码
package com.keran.wms.controller;

import cn.hutool.json.JSONObject;
import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.IOException;
import java.util.concurrent.*;

@RestController
@RequestMapping("/sse")
public class SseController {

    private final CopyOnWriteArrayList<SseEmitter> emitters = new CopyOnWriteArrayList<>();

    // 客户端连接端点
    @GetMapping(path = "/connect")
    public SseEmitter connect() {
        SseEmitter emitter = new SseEmitter(60_000L); // 超时时间60秒

        emitter.onCompletion(() -> emitters.remove(emitter));
        emitter.onTimeout(() -> emitters.remove(emitter));

        emitters.add(emitter);

        return emitter;
    }

    // 向所有客户端发送消息
    public void sendEventToAll(String data) {
        for (SseEmitter emitter : emitters) {
            try {
                emitter.send(SseEmitter.event()
                        .data(data)
                        .name("message")); // 事件名称
            } catch (IOException e) {
                emitter.complete();
                emitters.remove(emitter);
            }
        }
    }

    // 测试发送消息的端点
    @GetMapping("/send")
    public JSONObject sendMessage() {
        sendEventToAll("Server time: " + System.currentTimeMillis());
        return new JSONObject().set("status", "Message sent to all clients");
    }

    // 每20秒发送一次心跳
    @Scheduled(fixedRate = 20000)
    public void sendHeartbeat() {
        emitters.forEach(emitter -> {
            try {
                emitter.send(SseEmitter.event()
                        .data("heartbeat")
                        .reconnectTime(5000L)); // 建议的重连时间
            } catch (IOException e) {
                emitter.completeWithError(e);
                emitters.remove(emitter);
            }
        });
    }

}

3、前端Vue实现

html 复制代码
<template>
  <div>
    <h1>SSE Demo</h1>
    <div v-for="(message, index) in messages" :key="index">
      {{ message }}
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      messages: [],
      eventSource: null,
      reconnectDelay: 5000,
    };
  },
  mounted() {
    this.connectSSE();
  },
  beforeDestroy() {
    if (this.eventSource) {
      this.eventSource.close();
    }
  },
  methods: {
    connectSSE() {
      // 替换为你的Spring Boot后端地址
      this.eventSource = new EventSource('http://localhost:8080/sse/connect');
      
      // 通用消息处理器
      this.eventSource.onmessage = (event) => {
        this.messages.push(event.data);
      };
      
      // 特定事件处理器(对应后端.name()设置的事件名)
      this.eventSource.addEventListener('message', (event) => {
        this.messages.push(event.data);
      });
      
      // 错误处理
      this.eventSource.onerror = (error) => {
        this.eventSource.close();
        if (this.reconnectAttempts < this.maxReconnectAttempts) {
            setTimeout(() => {
            this.reconnectAttempts++;
            this.connectSSE();
        }, this.reconnectDelay);
      }
      };
    }
  }
};
</script>

4、访问 http://localhost:6065/sse/send测试

5、测试成功

相关推荐
coderSong25684 小时前
Java高级 |【实验八】springboot 使用Websocket
java·spring boot·后端·websocket
Mr_Air_Boy5 小时前
SpringBoot使用dynamic配置多数据源时使用@Transactional事务在非primary的数据源上遇到的问题
java·spring boot·后端
coding随想6 小时前
JavaScript ES6 解构:优雅提取数据的艺术
前端·javascript·es6
小小小小宇6 小时前
一个小小的柯里化函数
前端
灵感__idea6 小时前
JavaScript高级程序设计(第5版):无处不在的集合
前端·javascript·程序员
小小小小宇6 小时前
前端双Token机制无感刷新
前端
小小小小宇6 小时前
重提React闭包陷阱
前端
小小小小宇7 小时前
前端XSS和CSRF以及CSP
前端
UFIT7 小时前
NoSQL之redis哨兵
java·前端·算法
超级土豆粉7 小时前
CSS3 的特性
前端·css·css3