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
(可以删除)
