首页 > 其他分享 >Spring Boot中集成 SSE

Spring Boot中集成 SSE

时间:2024-05-25 23:32:27浏览次数:17  
标签:Spring Boot EventSource eventSource import SSE SseEmitter div

目录

  1. SSE简介
  2. SSE原理
  3. SSE的使用场景
  4. 在Spring Boot中集成SSE
  5. 总结

SSE简介

服务器发送事件(Server-Sent Events,SSE)是一种在HTTP协议上实现的服务器推送技术。它允许服务器单向地将实时更新推送到客户端。与WebSocket不同,SSE是基于HTTP协议的简化实现,非常适合需要从服务器向客户端单向推送数据的场景。

SSE原理

SSE通过HTTP协议的一个长连接来实现服务器到客户端的单向数据流。客户端通过发送一个普通的HTTP请求来建立连接,服务器接收到请求后,保持连接不断开,并通过这个连接持续地发送事件。客户端使用JavaScript的EventSource API来处理这些事件。

SSE的使用场景

SSE适用于以下应用场景:

  • 实时通知:如邮件通知、系统消息推送。
  • 实时更新:如股票行情、新闻更新。
  • 监控和仪表盘:实时监控数据的展示。
  • 社交媒体更新:如实时评论和点赞。

在Spring Boot中集成SSE

创建Spring Boot项目

首先,使用Spring Initializr或IDE(如IntelliJ IDEA)创建一个新的Spring Boot项目,选择合适的Spring Boot版本(如2.5.x或3.x),并添加以下依赖:

  • Spring Web

添加依赖

pom.xml中添加Spring Web的依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 其他依赖 -->
</dependencies>

创建SSE控制器

创建一个控制器来处理SSE连接和事件推送。

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

import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
public class SseController {

    @GetMapping("/sse")
    public SseEmitter handleSse() {
        // 创建一个新的SseEmitter实例,超时时间为30秒
        SseEmitter emitter = new SseEmitter(30_000L);

        // 创建一个ScheduledExecutorService来定时发送事件
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

        // 每秒发送一个当前时间的消息
        executor.scheduleAtFixedRate(() -> {
            try {
                // 发送事件,事件名称为"message",数据为当前时间戳
                emitter.send(SseEmitter.event().name("message").data("Current Time: " + System.currentTimeMillis()));
            } catch (IOException e) {
                // 发送失败时完成该Emitter
                emitter.completeWithError(e);
            }
        }, 0, 1, TimeUnit.SECONDS);

        // 在30秒后完成该Emitter
        executor.schedule(() -> emitter.complete(), 30, TimeUnit.SECONDS);

        return emitter;
    }
}

前端使用SSE

在前端使用JavaScript的EventSource来接收服务器发送的事件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>SSE Demo</title>
</head>
<body>
    <h1>SSE Demo</h1>
    <div id="messages"></div>
    <script>
        // 创建一个新的EventSource实例,连接到服务器的/sse端点
        const eventSource = new EventSource("/sse");

        // 当收到服务器发送的消息时,执行此函数
        eventSource.onmessage = function(event) {
            // 获取消息展示的div
            const messagesDiv = document.getElementById("messages");
            // 创建一个新的div元素来展示新消息
            const newMessage = document.createElement("div");
            newMessage.textContent = event.data; // 设置div的文本内容为事件数据
            messagesDiv.appendChild(newMessage); // 将新消息添加到消息展示div中
        };

        // 当发生错误时,执行此函数
        eventSource.onerror = function(error) {
            console.error("EventSource failed: ", error);
            eventSource.close(); // 关闭EventSource
        };
    </script>
</body>
</html>

详细案例:股票价格实时推送

假设我们需要实现一个股票价格实时推送的功能,服务器定期向客户端发送股票价格更新。

创建StockService类

模拟股票价格变化的服务类。

import org.springframework.stereotype.Service;

import java.util.Random;

@Service
public class StockService {
    private Random random = new Random();

    // 模拟获取股票价格的方法
    public double getStockPrice(String symbol) {
        // 返回一个随机价格
        return 100 + (random.nextDouble() * 50);
    }
}
更新SseController类

使用StockService类来推送股票价格。

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

import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@RestController
public class SseController {

    private final StockService stockService;

    // 使用构造器注入StockService
    public SseController(StockService stockService) {
        this.stockService = stockService;
    }

    @GetMapping("/sse/{symbol}")
    public SseEmitter handleSse(@PathVariable String symbol) {
        // 创建一个新的SseEmitter实例,超时时间为30秒
        SseEmitter emitter = new SseEmitter(30_000L);

        // 创建一个ScheduledExecutorService来定时发送事件
        ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);

        // 每秒发送一个股票价格更新
        executor.scheduleAtFixedRate(() -> {
            try {
                // 获取股票价格
                double price = stockService.getStockPrice(symbol);
                // 发送事件,事件名称为"stock-price",数据为股票价格
                emitter.send(SseEmitter.event().name("stock-price").data("Stock Price of " + symbol + ": " + price));
            } catch (IOException e) {
                // 发送失败时完成该Emitter
                emitter.completeWithError(e);
            }
        }, 0, 1, TimeUnit.SECONDS);

        // 在30秒后完成该Emitter
        executor.schedule(() -> emitter.complete(), 30, TimeUnit.SECONDS);

        return emitter;
    }
}
更新前端代码

在前端展示股票价格更新。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Stock Price SSE Demo</title>
</head>
<body>
    <h1>Stock Price SSE Demo</h1>
    <input type="text" id="symbol" placeholder="Enter stock symbol">
    <button onclick="connect()">Connect</button>
    <div id="messages"></div>
    <script>
        let eventSource;

        function connect() {
            const symbol = document.getElementById("symbol").value;
            if (eventSource) {
                eventSource.close(); // 关闭已有的连接
            }
            // 创建一个新的EventSource实例,连接到服务器的/sse/{symbol}端点
            eventSource = new EventSource("/sse/" + symbol);

            // 当收到服务器发送的消息时,执行此函数
            eventSource.onmessage = function(event) {
                // 获取消息展示的div
                const messagesDiv = document.getElementById("messages");
                // 创建一个新的div元素来展示新消息
                const newMessage = document.createElement("div");
                newMessage.textContent = event.data; // 设置div的文本内容为事件数据
                messagesDiv.appendChild(newMessage); // 将新消息添加到消息展示div中
            };

            // 当发生错误时,执行此函数
            eventSource.onerror = function(error) {
                console.error("EventSource failed: ", error);
                eventSource.close(); // 关闭EventSource
            };
        }
    </script>
</body>
</html>

标签:Spring,Boot,EventSource,eventSource,import,SSE,SseEmitter,div
From: https://blog.csdn.net/imdeity/article/details/139151046

相关文章

  • 【精品毕设推荐】基于Springboot的智能物流管理系统设计与实现
    点击下载原文及代码,可辅助在本地配置运行摘要随着信息技术在管理上越来越深入而广泛的应用,管理信息系统的实施在技术上已逐步成熟。本文介绍了智能物流管理系统的开发全过程。通过分析智能物流管理系统管理的不足,创建了一个计算机管理智能物流管理系统的方案。文章介绍了智能......
  • springcloudalibaba入门(一)
    1、父工程pom文件<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apac......
  • 自定义一个SpringBoot场景启动器
    前言一个刚刚看完SpringBoot自动装配原理的萌新依据自己的理解写下的文章,如有大神发现错误,敬请斧正,不胜感激。分析SpringBoot自动配置原理SpringBoot的启动从被@SpringBootApplication修饰的启动类开始,@SpringBootApplicaiotn注解中最重要的注解是@EnableAutoConfigurat......
  • 【SpringBoot】服务对注册中心的注册时机
    1 前言我们看过很多的时机,比如服务数据源的关闭时机、服务正式开始处理请求的时机或者Tomcat和SpringBoot的协同、还有mybatis等一些插件的入场时机等,这节我们要再看一个时机,就是关于跟注册中心(Eureka、Nacos)的时机,比如你有没有思考过:我服务还没起来,你就到注册中心上线了,那......
  • Spring 框架类PropertySourcesPlaceholderConfigurer
    PropertyOverrideConfigurer是Spring框架中的一个类,它允许你在Spring的配置文件之外通过外部属性文件来覆盖已定义的bean属性。这在部署不同的环境(如开发、测试、生产)时特别有用,因为你可以为不同的环境定义不同的属性,而无需修改Spring的配置文件。演示:创建实体类:p......
  • springboot3.0+shardingsphere5.2 最简单的分库分表
    先看表结构两个数据库test1,test2每个库有4张sys_user表分别命名sys_user_0-4maven依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>......
  • spring boot 的常用注解
    Autowired与Resource的区别1、Autowired与Resource都是要装配beanAutowired是通过byType来注入Resource是同通过byName来注入一、AutowiredAutowired默认是按类型(type也就是参数化类型)装配(这个注解是属于spring的),默认情况下Autowired要求依赖对象必须存在,如果想要允许他......
  • SpringBoot自动装配原理是什么?
    1创建上下文publicConfigurableApplicationContextrun(String...args){//记录程序运行时间StopWatchstopWatch=newStopWatch();stopWatch.start();//ConfigurableApplicationContextSpring的上下文ConfigurableAppl......
  • Spring框架篇常考八股
    1.什么是Ioc和DIIoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。传统应用程序都是由我们在类内部主动创建依赖对象,从而导致类与类之间高耦合,难于测试;有了IoC容器后,把创建和查找依赖对象的控制权交给了容器,由容器......
  • 49.SpringMVC简单整理
    SpringMVC本质也是解耦先提前插一嘴这里用到的是简单的maven项目:在添加web应用时报错ArtifactsWebfacetresources爆红参考:https://blog.csdn.net/weixin_43739266/article/details/122133398添加web依赖要为项目添加web项目依赖否则无法tomcat访问为了介绍MVC......