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;
   }

}
相关推荐
似水明俊德18 分钟前
04-C#.Net-委托和事件-面试题
java·开发语言·面试·c#·.net
海南java第二人38 分钟前
Cursor 高级实战:从 Spring Boot 到微服务,AI 驱动的全流程开发指南
人工智能·spring boot·微服务
好家伙VCC41 分钟前
# 发散创新:用 Rust构建高性能游戏日系统,从零实现事件驱动架构 在现代游戏开发中,**性能与可扩展性**是核心命题。传统基于
java·python·游戏·架构·rust
爱笑的源码基地1 小时前
门诊his系统源码,中西医结合的数字化门诊解决方案
java·spring boot·源码·二次开发·门诊系统·云诊所系统·诊所软件源码
庞轩px1 小时前
缓存Key设计的“七要七不要”
java·jvm·redis·缓存
小璐资源网1 小时前
Java 21 新特性实战:虚拟线程详解
java·开发语言·python
SimonKing1 小时前
全网爆火的OpenClaw保姆级教程Linux版,它来了。
java·后端·程序员
于慨1 小时前
tauri
java·服务器·前端
WZTTMoon1 小时前
从互斥锁到无锁,Java 20年并发安全进化史
java·python·安全
2501_918126911 小时前
学习所有6502写游戏控制器的语句
java·linux·网络·汇编·嵌入式硬件