SSE服务搭建

首先了解什么SSE服务?

SSE(Server-Sent Events,服务器发送事件)是一种基于 HTTP 的服务器向客户端单向推送实时数据的技术,它允许服务器主动向客户端发送事件流,适用于实时通知、数据更新等场景

特点:

  1. 单向通信:仅服务器向客户端推送数据(客户端不能通过 SSE 向服务器发送数据,需用 HTTP 或 WebSocket 补充)。
  2. 基于 HTTP:复用 HTTP 连接,无需额外协议(WebSocket 是独立协议),兼容性更好。
  3. 自动重连:客户端断开连接后会自动重试(可配置重连时间)。
  4. 文本数据:传输的数据是 UTF-8 编码的文本(通常用 JSON 格式)。
  5. 轻量级:协议简单,实现成本低,适合简单的实时场景。
java 复制代码
@Slf4j
public class SSEServer {

    //存放所有用户的SseEmitter
    private static final Map<String, SseEmitter> SSE_EMITTER_MAP=new ConcurrentHashMap<>();
    /**
     * 连接SSE
     * @return
     */
      public static SseEmitter connect(String userId){
         //设置超时时间,0表示不超时;默认是30秒,超时会抛出异常
          SseEmitter sseEmitter=new SseEmitter(0L);
          //注册回调方法
          //超时回调
          sseEmitter.onTimeout(timeOutCallBack(userId));
          //SSE完成后回调,完成后会调用的方法
          sseEmitter.onCompletion(completionCallBack(userId));
          //异常回调
          sseEmitter.onError(errorCallBack(userId));
          SSE_EMITTER_MAP.put(userId,sseEmitter);
          log.info("用户{}连接SSE成功",userId);
          return sseEmitter;
      }
      /**
       * 发送SSE消息
       * @param userId
       * @param message
       * @param msgType
       */
      public static void senMessage(String userId,String message,SSEMsgType msgType){
            if (CollectionUtil.isEmpty(SSE_EMITTER_MAP)){
                return;
            }
            if (SSE_EMITTER_MAP.containsKey(userId)) {
                SseEmitter sseEmitter = SSE_EMITTER_MAP.get(userId);
                //发送事件
                 sendEvent(sseEmitter,userId,message,msgType);
            }

      }
      /**
       * 发送SSE事件
       * @param sseEmitter
       * @param userId
       * @param message
       * @param msgType
       */
      private static void sendEvent(SseEmitter sseEmitter,
                                   String userId,
                                   String message,
                                   SSEMsgType msgType){

          try{
              SseEmitter.SseEventBuilder eventBuilder = SseEmitter.event()
                      .id(userId)
                      .name(msgType.type)
                      .data(message);
              sseEmitter.send(eventBuilder);
          }catch (Exception e){
              log.error("用户{}发送SSE消息异常",userId,e);
              remove(userId);
          }



      }
      /**
       * 异常回调
       * @param userId
       * @return
       */
      public static Consumer<Throwable> errorCallBack(String userId){
          return throwable -> {
              log.error("用户{}SSE连接异常",userId,throwable);
              //异常处理逻辑
             remove(userId);
          };
      }
      /**
       * 超时回调
       * @param userId
       * @return
       */
      public static Runnable timeOutCallBack(String userId){
          return () -> {
              log.info("用户{}超时",userId);
              //超时处理逻辑
             remove(userId);
          };
      }
      /**
       * 完成回调
       * @param userId
       * @return
       */
      public static Runnable completionCallBack(String userId){
          return () -> {
              log.info("用户SSE{}完成",userId);
              //完成处理逻辑
             remove(userId);
          };
      }
      /**
       * 移除用户的SseEmitter
       * @param userId
       */
      public static void remove(String userId){
          SSE_EMITTER_MAP.remove(userId);
          log.info("移除用户{}的SseEmitter",userId);
      }
}

定义枚举类型,代表SSE返回的消息类型

java 复制代码
/**
 * SSE消息类型
 */
public enum SSEMsgType {
   MESSAGE("message","单词发送的普通类型消息"),
   ADD("add","消息追加,适用于流式消息"),
   FINISH("finish","消息完成"),
   CUSTOM_EVENT("custom_event","自定义事件"),
   DONE("done","消息完成,适用于流式消息");



   public final String type;
   public final String value;

   SSEMsgType(String type,String value){
      this.type=type;
      this.value=value;
   }

}
相关推荐
云烟成雨TD9 分钟前
Micrometer 系列【63】统一观测:基于 Spring Boot 的生产级演示案例 | 基于 OTLP 集成 Prometheus + Jaeger
spring boot·云原生·prometheus
码匠许师傅12 分钟前
【C++ 面试真题】聊聊 C++ 的虚函数和多态
java·c++·面试
csdn2015_14 分钟前
springboot +mybatis 查询myql开启程序级别缓存
spring boot·缓存·mybatis
chuan.bai39 分钟前
Java RAG 实战(第 8 篇):Spring Boot RAG 查询 API
java·spring boot·贪心算法
FlyWIHTSKY40 分钟前
idea中集成claude功能
java·ide·人工智能·intellij-idea·cloudera
Java成神之路-1 小时前
Spring AI 统一结构化返回:ChatModel / ChatClient 两种实现方式
java·springaialibaba
Mr. zhihao1 小时前
深度解析:为什么Java序列化需要搭配ByteArrayOutputStream?IO装饰器模式的精妙设计
java·开发语言·装饰器模式
存在morning1 小时前
【Python 开发实践 一】Python vs Go vs Java 三门语言对比
java·python·golang
vx-程序开发1 小时前
springboot旅游推介平台---附源码24175
java·spring boot·python·spring cloud·eclipse·django·idea
艾莉丝努力练剑1 小时前
【QT:解决问题】Qt5Core.dll:无法定位程序输入点
java·开发语言·qt·学习·面试