赞
踩
服务器发送事件(Server-Sent Events,SSE)是一种在HTTP协议上实现的服务器推送技术。它允许服务器单向地将实时更新推送到客户端。与WebSocket不同,SSE是基于HTTP协议的简化实现,非常适合需要从服务器向客户端单向推送数据的场景。
SSE通过HTTP协议的一个长连接来实现服务器到客户端的单向数据流。客户端通过发送一个普通的HTTP请求来建立连接,服务器接收到请求后,保持连接不断开,并通过这个连接持续地发送事件。客户端使用JavaScript的EventSource API来处理这些事件。
SSE适用于以下应用场景:
首先,使用Spring Initializr或IDE(如IntelliJ IDEA)创建一个新的Spring Boot项目,选择合适的Spring Boot版本(如2.5.x或3.x),并添加以下依赖:
在pom.xml
中添加Spring Web的依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 其他依赖 -->
</dependencies>
创建一个控制器来处理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; } }
在前端使用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>
假设我们需要实现一个股票价格实时推送的功能,服务器定期向客户端发送股票价格更新。
模拟股票价格变化的服务类。
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);
}
}
使用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>
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。