Spring 框架中可以使用 SseEmitter 实现服务端向客户端推送消息,今天盘一盘。
SseEmitter 简介
SseEmitter 是 Spring Framework 中用于服务器发送事件(Server-Sent Events, SSE)的类。SSE 是一种允许服务器主动向客户端推送数据的技术,通常用于实现如实时通知、数据流等功能。其工作原理基于 HTTP 协议,客户端通过 HTTP 请求订阅服务器的事件流,服务器则通过 SseEmitter 对象持续向客户端发送事件。
SseEmitter 的核心特性
单向通信:SSE 是单向的,只允许服务器向客户端推送数据,客户端不能通过此通道向服务器发送数据。
基于 HTTP:SSE 使用标准的 HTTP 协议,因此不需要额外的协议支持,易于实现和使用。
自动重连:如果连接中断,客户端浏览器会自动尝试重新连接服务器。
事件流格式:SSE 使用简单的文本格式传输数据,每条消息以 data:开头,并以两个换行符\n\n 结束
SseEmitter 的使用场景
实时数据流:在需要实时数据更新的应用中,如股票交易平台,服务器可以使用 SseEmitter 向客户端推送最新的股票价格和交易信息。
实时通知:适用于需要向用户发送实时通知的场景,例如在线教育平台的新课程发布或作业提交通知。
聊天应用:在聊天应用中,SseEmitter 可以用来实现实时消息推送,提高消息传递的效率。
监控系统:在监控系统中,SseEmitter 可以用于实时推送监控数据,如物联网项目中传感器采集的数据,以实时监控设备状态。
SseEmitter 的基本用法
创建 SseEmitter 实例:在控制器中创建一个 SseEmitter 实例,并将其返回给客户端。
发送事件:通过 SseEmitter 实例的 send 方法向客户端发送事件。
处理连接关闭:通过 SseEmitter 的 onCompletion 和 onTimeout 方法处理连接关闭或超时的情况。
通过 SseEmitter,开发者可以构建出高效、可靠的实时应用,提升用户体验和系统性能。
下面我们通过一个简单示例演示下
前端服务
使用 Vue CLI 创建一个 Vue 3 项目,
安装 Vue CLI
创建 Vue 3 项目
启动服务
cd my-vue3-app
npm run serve
复制代码
创建一个 vue 文件 EventList.vue
获取消息,然后进行等待服务端的消息。
<template>
<div>
<h1>Server-Sent Events</h1>
<ul>
<li v-for="message in messages" :key="message.id">{{ message.content }}</li>
</ul>
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from 'vue';
import { SseClient } from './SseClient';
const messages = ref([]);
const sseClient = new SseClient((event) => {
const data = JSON.parse(event.data);
messages.value.push(data);
});
onMounted(() => {
sseClient.connect();
});
onUnmounted(() => {
sseClient.disconnect();
});
</script>
<style scoped>
/* Add your styles here */
</style>
复制代码
创建 JS 文件 SseClient
export class SseClient {
constructor(onMessage) {
this.onMessage = onMessage;
this.eventSource = null;
}
connect() {
this.eventSource = new EventSource('http://localhost:8089/events/54321');
this.eventSource.onmessage = (event) => {
this.onMessage(event);
};
this.eventSource.onerror = (error) => {
this.disconnect();
};
}
disconnect() {
if (this.eventSource) {
this.eventSource.close();
this.eventSource = null;
}
}
}
复制代码
然后再 Vue 项目入口 APP.vue 中引入刚才的 Vue 文件。
后端服务
创建 SpringBoot 服务
直接写一个简易的 Controller,将 SseEmitter 缓存起来,可以直接进行消息发送。
@Controller
public class SseEmitterController {
private static Map<String, SseEmitter> sseCache = new ConcurrentHashMap<>();
@CrossOrigin(origins = "*")
@GetMapping("/events/{userId}")
public SseEmitter stream(@PathVariable String userId) throws IOException {
sseCache.put(userId,new SseEmitter(10 * 60 * 1000L));
SseEmitter emitter = sseCache.get(userId);
Map<String,String> map = new HashMap<>();
map.put("id", userId);
map.put("content", "连接成功");
emitter.send(map);
return emitter;
}
@GetMapping("/sendMessage/{userId}")
public String sendMessage(@PathVariable String userId,
@RequestParam(name = "message", required = false) String message) throws IOException {
SseEmitter emitter = sseCache.get(userId);
Map<String,String> map = new HashMap<>();
map.put("id", userId);
map.put("content", message);
emitter.send(map);
return "成功";
}
@GetMapping("/close/{userId}")
public String close(@PathVariable String userId
) throws IOException {
SseEmitter emitter = sseCache.get(userId);
emitter.complete();
return "成功";
}
}
复制代码
前后端启动后联调:
初始化连接成功。
再手动发送消息。
客户端接收消息:
以上是一个简易的服务端主动推送消息给客户端的例子。
来源:https://mp.weixin.qq.com/s/Flf0B1U5vUQ2nzCp8zv-6Q
评论