Springboot 实现Server-Sent Events的项目实践

 更新时间:2024年12月24日 10:10:39   作者:it噩梦  
本文介绍了在Spring Boot中实现Server-Sent Events(SSE),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在 Spring Boot 中,返回 text/event-stream 类型的响应通常用于实现 Server-Sent Events (SSE),这种方式允许服务器推送实时更新到浏览器。客户端通过 EventSource API 监听并接收这些事件。Spring Boot 可以通过使用 @RestController 和 SseEmitter 来实现这一功能。

步骤 1:创建 SSE Controller 返回 text/event-stream

我们可以通过 @GetMapping 来创建一个 API,返回 text/event-stream 类型的数据。这个数据会是一个持续的流,浏览器会实时地接收它。

示例:通过 Spring Boot 返回 text/event-stream 类型的响应

  • 控制器:在 Spring Boot 中定义一个返回 text/event-stream 类型的 API 接口。
  • 使用 SseEmitterSseEmitter 是 Spring 提供的一个类,用于处理 Server-Sent Events 流。我们可以利用它来异步地向客户端推送数据。

示例 1:简单的 SSE 实现

在这个示例中,我们将创建一个简单的 Spring Boot 控制器,该控制器将返回一个实时的事件流(SSE)。

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

@RestController
public class SseController {

    /**
     * 这个接口会返回一个持续的事件流,浏览器会通过 EventSource 接收
     */
    @GetMapping("/sse")
    public SseEmitter handleSse() {
        SseEmitter emitter = new SseEmitter();

        // 启动一个新的线程模拟定期推送事件
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    // 向客户端发送数据
                    emitter.send("data: Event " + i + "\n\n");
                    Thread.sleep(1000); // 每秒发送一次
                }
                emitter.complete(); // 发送完毕后,标记事件流完成
            } catch (Exception e) {
                emitter.completeWithError(e); // 如果出现异常,标记事件流出错
            }
        }).start();

        return emitter; // 返回 SseEmitter 实例,它会处理异步流式数据
    }
}

说明:

  • SseEmitter 用于处理 SSE 连接。我们将数据通过 emitter.send() 发送到客户端。
  • 事件通过 data: <message> 格式发送给客户端,注意每条消息以两个换行符结束(\n\n)。
  • Thread.sleep(1000) 用于模拟每秒发送一个事件。如果你需要定期发送事件,可以通过类似的机制来实现。
  • 最后,通过 emitter.complete() 标记事件流结束。如果发生错误,则使用 emitter.completeWithError()

步骤 2:前端接收 SSE 事件

在前端,使用 JavaScript 的 EventSource API 接收服务器推送的事件。这个 API 会保持与服务器的连接,一旦有新的事件,浏览器会自动处理。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Server-Sent Events Example</title>
</head>
<body>

<h1>Server-Sent Events Example</h1>
<div id="messages"></div>

<script>
    // 创建一个 EventSource 对象,连接到 /sse 接口
    const eventSource = new EventSource("/sse");

    // 每当接收到数据时,处理该事件
    eventSource.onmessage = function(event) {
        const messagesDiv = document.getElementById('messages');
        const message = document.createElement('p');
        message.textContent = event.data;
        messagesDiv.appendChild(message);
    };

    // 错误处理
    eventSource.onerror = function(error) {
        console.error("EventSource failed:", error);
    };
</script>

</body>
</html>

步骤 3:配置 Spring Boot 启用异步支持

SSE 通常需要异步处理,因此在 Spring Boot 中启用异步支持是非常重要的。可以通过 @EnableAsync 来启用异步支持。

启用异步支持

import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

@Configuration
@EnableAsync
public class AsyncConfig {
}

步骤 4:定时推送数据(可选)

如果你希望定期推送事件(例如,每隔一定时间推送一个消息),可以使用 Spring 的 @Scheduled 注解来安排定时任务。

示例:定时发送事件

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;

@Controller
public class ScheduledSseController {

    private final SseEmitter emitter = new SseEmitter();

    @Scheduled(fixedRate = 5000)  // 每5秒发送一个事件
    public void sendScheduledEvent() {
        try {
            emitter.send("data: Scheduled Event at " + System.currentTimeMillis() + "\n\n");
        } catch (IOException e) {
            emitter.completeWithError(e);
        }
    }
}

在上面的示例中,@Scheduled(fixedRate = 5000) 会定期每 5 秒发送一次事件。

步骤 5:处理多客户端连接

如果你需要管理多个客户端连接,可以将 SseEmitter 实例存储在一个列表中,并为每个连接发送事件。每当有新事件时,你可以通过遍历这些连接,发送事件到所有连接的客户端。

import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import org.springframework.web.bind.annotation.GetMapping;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

@Controller
public class MultiClientSseController {

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

    @GetMapping("/sse")
    public SseEmitter handleSse() {
        SseEmitter emitter = new SseEmitter();
        emitters.add(emitter);

        // 在新线程中发送数据
        new Thread(() -> {
            try {
                for (int i = 0; i < 10; i++) {
                    for (SseEmitter e : emitters) {
                        e.send("data: Event " + i + "\n\n");
                    }
                    Thread.sleep(1000); // 每秒发送一次
                }
            } catch (Exception e) {
                emitters.forEach(SseEmitter::completeWithError);
            }
        }).start();

        return emitter;
    }
}

总结

  • 返回 text/event-stream:在 Spring Boot 控制器中使用 SseEmitter 或直接通过 @GetMapping 返回流式数据。
  • 前端接收事件:使用浏览器的 EventSource API 来接收事件流。
  • 定时事件:可以使用 @Scheduled 来定期推送事件,或者通过后台线程推送动态数据。
  • 多客户端支持:可以管理多个 SseEmitter 实例,为每个客户端推送事件。

这种方式非常适合实时数据推送,例如股票行情更新、社交媒体通知、实时消息等应用场景。

到此这篇关于Springboot 实现Server-Sent Events的项目实践的文章就介绍到这了,更多相关Springboot实现Server-Sent Events内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 从0到1构建springboot web应用镜像并使用容器部署的过程

    从0到1构建springboot web应用镜像并使用容器部署的过程

    这篇文章主要介绍了从0到1构建springboot web应用镜像并使用容器部署,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • 图文详解Maven工程打jar包的N种方式

    图文详解Maven工程打jar包的N种方式

    最近在打包maven项目时,该项目中仅有一个测试类,想打成jar包运行测试,所以下面这篇文章主要给大家介绍了关于Maven工程打jar包的N种方式,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • 解决IDEA中不能正常输入光标变粗的问题

    解决IDEA中不能正常输入光标变粗的问题

    这篇文章主要介绍了在IDEA中不能正常输入光标变粗的解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2020-09-09
  • 基于SpringBoot项目遇到的坑--Date入参问题

    基于SpringBoot项目遇到的坑--Date入参问题

    这篇文章主要介绍了SpringBoot项目遇到的坑--Date入参问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • spring+maven实现发送邮件功能

    spring+maven实现发送邮件功能

    这篇文章主要为大家详细介绍了spring+maven实现发送邮件功能,利用spring提供的邮件工具来发送邮件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • SpringBoot使用LomBok的示例代码

    SpringBoot使用LomBok的示例代码

    这篇文章主要介绍了SpringBoot使用LomBok的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 使用1招搞定maven打包空间不足的问题

    使用1招搞定maven打包空间不足的问题

    这篇文章主要介绍了使用1招搞定maven打包空间不足的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-09-09
  • Java gRPC拦截器简单实现分布式日志链路追踪器过程详解

    Java gRPC拦截器简单实现分布式日志链路追踪器过程详解

    有请求的发送、处理,当然就会有拦截器的需求,例如在服务端通过拦截器统一进行请求认证等操作,这些就需要拦截器来完成,今天松哥先和小伙伴们来聊一聊gRPC中拦截器的基本用法,后面我再整一篇文章和小伙伴们做一个基于拦截器实现的JWT认证的gRPC
    2023-03-03
  • Java总结篇系列:Java泛型详解

    Java总结篇系列:Java泛型详解

    下面小编就为大家带来一篇Java总结篇系列:Java泛型详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-09-09
  • FastJson对于JSON格式字符串、JSON对象及JavaBean之间的相互转换操作

    FastJson对于JSON格式字符串、JSON对象及JavaBean之间的相互转换操作

    这篇文章主要介绍了FastJson对于JSON格式字符串、JSON对象及JavaBean之间的相互转换,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-11-11

最新评论