|
@@ -0,0 +1,73 @@
|
|
|
|
+/*
|
|
|
|
+ * 爱组搭,低代码组件化开发平台
|
|
|
|
+ * ------------------------------------------
|
|
|
|
+ * 受知识产权保护,请勿删除版权申明,开发平台不允许做非法网站,后果自负
|
|
|
|
+ */
|
|
|
|
+package com.aizuda.boot.modules.system.service.impl;
|
|
|
|
+
|
|
|
|
+import com.aizuda.boot.modules.system.service.ISysSSEService;
|
|
|
|
+import com.aizuda.service.web.UserSession;
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
|
|
|
+
|
|
|
|
+import java.io.IOException;
|
|
|
|
+import java.util.Map;
|
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
+
|
|
|
|
+import static org.springframework.http.MediaType.APPLICATION_JSON;
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * SSE消息推送 服务实现类
|
|
|
|
+ *
|
|
|
|
+ * @author 青苗
|
|
|
|
+ * @since 2024-09-05
|
|
|
|
+ */
|
|
|
|
+@Service
|
|
|
|
+public class SysSSEServiceImpl implements ISysSSEService {
|
|
|
|
+ private final static Map<Long, Map<String, SseEmitter>> USER_TOKEN_EMITTERS = new ConcurrentHashMap<>();
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public SseEmitter connect() {
|
|
|
|
+ UserSession userSession = UserSession.getLoginInfo();
|
|
|
|
+ Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.computeIfAbsent(userSession.getId(), k -> new ConcurrentHashMap<>());
|
|
|
|
+
|
|
|
|
+ // 创建一个新的 SseEmitter 实例,默认30秒超时,设置为0L则永不超时
|
|
|
|
+ SseEmitter emitter = new SseEmitter(0L);
|
|
|
|
+
|
|
|
|
+ // 用户会话ID
|
|
|
|
+ String sid = userSession.getSid();
|
|
|
|
+
|
|
|
|
+ // 会话关联推送
|
|
|
|
+ emitters.put(sid, emitter);
|
|
|
|
+
|
|
|
|
+ // 当 emitter 完成、超时或发生错误时,从映射表中移除对应的会话信息
|
|
|
|
+ emitter.onCompletion(() -> emitters.remove(sid));
|
|
|
|
+ emitter.onTimeout(() -> emitters.remove(sid));
|
|
|
|
+ emitter.onError((e) -> emitters.remove(sid));
|
|
|
|
+
|
|
|
|
+ try {
|
|
|
|
+ // 向客户端发送一条连接成功的事件
|
|
|
|
+ emitter.send(SseEmitter.event().comment("connected"));
|
|
|
|
+ } catch (IOException e) {
|
|
|
|
+ // 如果发送消息失败,则从映射表中移除 emitter
|
|
|
|
+ emitters.remove(sid);
|
|
|
|
+ }
|
|
|
|
+ return emitter;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Override
|
|
|
|
+ public void send(Long userId, String eventName, String message) {
|
|
|
|
+ Map<String, SseEmitter> emitters = USER_TOKEN_EMITTERS.get(userId);
|
|
|
|
+ if (emitters != null) {
|
|
|
|
+ for (Map.Entry<String, SseEmitter> entry : emitters.entrySet()) {
|
|
|
|
+ SseEmitter sseEmitter = entry.getValue();
|
|
|
|
+ try {
|
|
|
|
+ sseEmitter.send(SseEmitter.event().name(eventName).data(message, APPLICATION_JSON));
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
+ emitters.remove(entry.getKey());
|
|
|
|
+ sseEmitter.completeWithError(e);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|