SSE(Server-Sent Events)

SSE(Server-Sent Events)

1. 自定义定时器实现SSE?

1.前端页面

2.后端
2.1 Controller

java 复制代码
@RestController
@RequestMapping("sse/test")
public class SseController {

    @Autowired
    private SseEmitterServiceBli sseEmitterServiceBli;

    /**
     * 创建新连接
     */
    @GetMapping("/connectBli")
    public Object createSession(){
        return sseEmitterServiceBli.createSession();
    }

    /**
     * 断开连接
     */
    @GetMapping("/closeBli")
    public void closeSession(@RequestParam String clientId){
        sseEmitterServiceBli.closeSession(clientId);
    }
}

2.2 Service

java 复制代码
@Service
public class SseEmitterServiceBli {

    private static final Logger log = LoggerFactory.getLogger(SseEmitterServiceBli.class);
    // 存储活跃的 SSE 连接
    private final ConcurrentHashMap<String, SseEmitter> SSE_CACHE = new ConcurrentHashMap<>();

    /**
     * 创建 SSE 连接
     * @return SseEmitter 实例
     */
    public synchronized SseEmitter createSession() {
        // 创建 SseEmitter 实例,设置超时时间(过期时间)为 0,表示永不过时
        SseEmitter emitter = new SseEmitter(0L);
        // 客户端唯一标识
        String clientId = UUID.randomUUID().toString().replaceAll("-", "");
        if (!SSE_CACHE.containsKey(clientId)){
            // 将连接存储到集合中
            SSE_CACHE.put(clientId,emitter);
            log.info("客户端:[{}]新建连接成功,当前客户端总数为[{}]", clientId,SSE_CACHE.size());
        }
        return emitter;
    }

    /**
     * 关闭 SSE 连接
     * @param clientId 客户端唯一标识
     * @return 是否成功断开连接
     */
    public void closeSession(String clientId) {
        if (SSE_CACHE.containsKey(clientId)){
            //将sse对象状态设为"完成"
            SSE_CACHE.get(clientId).complete();
            //关闭连接 直接将SSE客户端里连接从map中移除即可
            SSE_CACHE.remove(clientId);
            log.info("客户端:[{}]断开连接成功,当前客户端总数为[{}]", clientId,SSE_CACHE.size());
        }
    }

    /**
     * 发送消息给指定客户端即 一个 定时任务,用到spring提供的一个Scheduled定时框架
     */
    //@Scheduled 此注解使 sendHeartbeat() 方法成为定时任务,无需手动调用,由 Spring 自动执行,保证 SSE 连接的稳定性和可靠性
    @Scheduled(fixedRate = 3, initialDelay = 1, timeUnit = TimeUnit.SECONDS)
    //fixedRate = 3:每隔3秒执行一次;initialDelay = 1:延迟1秒开始执行;timeUnit = TimeUnit.SECONDS:指定时间单位为秒
    public void sendHeartbeat() {
        if (SSE_CACHE.size()>0){
            String msg ="心跳消息:"+ UUID.randomUUID();
            System.out.println("msg= "+msg);
            //遍历map:key是客户端id,value是sse对象,通过此对象可以发送消息给指定的客户端,发送的消息msg是随机字符串
            for (Map.Entry<String, SseEmitter> entry : SSE_CACHE.entrySet()){
                SseEmitter sseEmitter = SSE_CACHE.get(entry.getKey());
                try {
                    sseEmitter.send(SseEmitter.event()
                            .reconnectTime(10000L)  // 设置重连时间 10 秒
                            .name("heartbeat")  // 事件名称
                            .id(entry.getKey()) // 客户端ID作为事件ID
                            .data(msg));    // 消息内容
                }catch (IOException e){
                    System.out.println("Error sending message to client: clientId:" + entry.getKey() + ", error: " + e.getMessage());
                    // 如果发送失败,移除连接
                    SSE_CACHE.remove(entry.getKey());
                }
            }
        }
    }

}

2.3 application.yml

(可以删除)

相关推荐
rannn_1112 小时前
【苍穹外卖|Day4】套餐页面开发(新增套餐、分页查询、删除套餐、修改套餐、起售停售)
java·spring boot·后端·学习
qq_12498707532 小时前
基于JavaWeb的大学生房屋租赁系统(源码+论文+部署+安装)
java·数据库·人工智能·spring boot·计算机视觉·毕业设计·计算机毕业设计
短剑重铸之日2 小时前
《设计模式》第十一篇:总结
java·后端·设计模式·总结
若鱼19192 小时前
SpringBoot4.0新特性-Observability让生产环境更易于观测
java·spring
觉醒大王2 小时前
强女思维:着急,是贪欲外显的相。
java·论文阅读·笔记·深度学习·学习·自然语言处理·学习方法
努力学编程呀(๑•ี_เ•ี๑)3 小时前
【在 IntelliJ IDEA 中切换项目 JDK 版本】
java·开发语言·intellij-idea
码农小卡拉3 小时前
深入解析Spring Boot文件加载顺序与加载方式
java·数据库·spring boot
向上的车轮3 小时前
为什么.NET(C#)转 Java 开发时常常在“吐槽”Java:checked exception
java·c#·.net
Dragon Wu3 小时前
Spring Security Oauth2.1 授权码模式实现前后端分离的方案
java·spring boot·后端·spring cloud·springboot·springcloud
跳动的梦想家h3 小时前
环境配置 + AI 提效双管齐下
java·vue.js·spring