Forest Forest
首页
  • 当前版本

    • v1.6.x
  • 历史版本

    • v1.5.36
    • v1.5.35
    • v1.5.33
    • v1.5.30 ~ v1.5.32
    • v1.5.0 ~ v1.5.28
  • 插件

    • ForestX
  • 问答

    • 常见问题
    • 更新记录
案例
  • 加入群聊
  • 赞助我们
  • 参与贡献
  • 贡献者们
  • 项目介绍
  • 开发团队
  • 关于作者
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Fast Request - IDEA版Postman,为简化API调试而生 (opens new window)
  • Bean Searcher - 专注高级查询的只读 ORM (opens new window)
  • zyplayer-doc - 可私有化部署的文档与知识库管理平台 (opens new window)
  • frSimple - 中后台脚手架/小程序商城 (opens new window)
  • Gitee (opens new window)
  • Github (opens new window)
  • GitCode (opens new window)
首页
  • 当前版本

    • v1.6.x
  • 历史版本

    • v1.5.36
    • v1.5.35
    • v1.5.33
    • v1.5.30 ~ v1.5.32
    • v1.5.0 ~ v1.5.28
  • 插件

    • ForestX
  • 问答

    • 常见问题
    • 更新记录
案例
  • 加入群聊
  • 赞助我们
  • 参与贡献
  • 贡献者们
  • 项目介绍
  • 开发团队
  • 关于作者
  • MaxKey - 业界领先的身份管理和认证产品 (opens new window)
  • Snowy - 国内首个国密前后端分离快速开发平台 (opens new window)
  • Eoapi - 一个开源、可拓展的 API 工具平台 (opens new window)
  • Fast Request - IDEA版Postman,为简化API调试而生 (opens new window)
  • Bean Searcher - 专注高级查询的只读 ORM (opens new window)
  • zyplayer-doc - 可私有化部署的文档与知识库管理平台 (opens new window)
  • frSimple - 中后台脚手架/小程序商城 (opens new window)
  • Gitee (opens new window)
  • Github (opens new window)
  • GitCode (opens new window)
  • 入门

    • 🎬 安装配置说明
    • 🏹 Springboot环境安装
    • 📐 Springboot环境配置
    • 🎯 Springboot环境使用
    • 🏹 Springboot3环境安装
    • 📐 Springboot3环境配置
    • 🎯 Springboot3环境使用
    • 🏹 Spring环境安装
    • 📐 Spring环境配置
    • 🎯 Spring环境使用
    • 🏹 Solon环境安装
    • 📐 Solon环境配置
    • 🎯 Solon环境使用
    • 🏹 原生Java环境安装
    • 📐 原生Java环境配置
    • 🎯 原生Java环境使用
    • 🧬 编程式接口
  • 配置项

    • 👜 Springboot环境配置项
    • 👝 Spring环境配置项
    • 👜 Solon环境配置项
    • 🎒 原生Java环境配置项
    • 📚 配置优先级/作用域
  • 声明式接口

    • 🧱 构建接口
    • 🍀 请求方法
    • 🚚 请求地址
    • 🎈 URL 参数
    • 🍭 请求头
    • 👔 请求体
    • 🍮 后端框架
    • 🧁 接口注解
    • 📬 接收数据
    • 🍛 数据转换
    • 🎀 对象字段
    • 🍓 成功/失败条件
    • 🍌 重试机制
    • 🥂 重定向
    • 🍔 Gzip解压
    • 🎂 日志管理
    • ⚽ 回调函数
    • 🍟 异步请求
    • 🛡️ HTTPS
    • 🍪 使用Cookie
    • 🛸 使用代理
    • 🍉 上传下载
    • 🚑 异常处理
  • 编程式接口

    • 请求API

      • 🚀 请求对象
      • 🚢 请求属性
      • ✨ 执行请求
      • 🎊 后端框架
      • 🎪 请求类型
      • 🔮 请求地址
      • 🧀 URL 参数
      • 🚅 请求头
      • 🚋 请求体
      • ⚓ 回调函数
      • 🚁 异步请求
      • 🥯 Cookie
      • 🍜 成功/失败条件
      • 🌶️ 重试机制
      • ⛵ 重定向
      • 🛰️ 请求代理
    • 响应API

      • 🌠 响应对象
      • ✒️ 读取数据
      • 🦋 响应状态码
      • 🏥 响应错误处理
      • 🎧 响应头
      • 🥞 Cookie
  • SSE

    • 🐿 声明式 SSE 接口
    • 🐠 编程式 SSE 接口
    • 🐶 SSE 控制器
    • 🐬 SSE 拦截器
      • SSE 拦截器
      • SSE 拦截器与 Spring 集成
      • 在 SSE 拦截器中传递数据
    • 🦄 SSE 事件处理方法
  • 模板表达式

    • 🍬 Hello World
    • 🍹 配置属性引用
    • 🍖 变量引用
    • 🥃 动态变量绑定
    • 🥗 参数序号引用
    • 🍍 引用对象属性
    • 🥝 调用对象方法
  • 高级特性

    • 🥪 拦截器
    • 🍏 自定义注解
    • 🍇 组合注解
    • 🥑 自定义转换器
  • v1.6.x文档
  • SSE
公子骏
2024-12-26
目录

🐬 SSE 拦截器

# SSE 拦截器

SSE 拦截器也是普通拦截器的一种,实现自定义的 SSE 拦截器需要实现com.dtflys.forest.interceptor.SSEInterceptor接口。

如果还不了解什么是拦截器和Interceptor接口,可以先参见《拦截器》。

相比于自定义 SSE 控制器,SSE 拦截器同样可以控制 SSE 事件流的各个生命周期、以及处理所有事件消息,唯一有所不同的是,SSE 拦截器是单例,不会像 SSE 控制器那样每发起一次 SSE 请求都会实例化一个独立的对象,一个 SSE 拦截器类永远都只有一个实例。

// 自定义 SSE 拦截器,需实现 SSEInterceptor 接口
public class MySSEInterceptor implements SSEInterceptor {
    
    // onSuccess 方法可重写,可不重写
    @Override
    public void onSuccess(InputStream data, ForestRequest request, ForestResponse response) {
        // 和普通拦截器 onSuccess 相同,data 是 SSE 的消息流,不建议在这里动它
    }

    // afterExecute 方法可重写,可不重写
    @Override
    public void afterExecute(ForestRequest request, ForestResponse response) {
        // 和普通拦截器 afterExecute 相同
    }

    // onSSEOpen 方法可重写,可不重写
    @Override
    public void onSSEOpen(EventSource eventSource) {
        // SSE 开始监听时调用
    }

    // onSSEClose 方法可重写,可不重写
    @Override
    public void onSSEClose(ForestRequest request, ForestResponse response) {
        // SSE 结束监听时调用
    }

    // 1.6.4+ 版本可以重写 onMessage 方法来接收 SSE 消息
    @Override
    public void onMessage(EventSource event) {
        // 接收到 SSE 消息时调用
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

由上面代码可见,SSE 拦截器也是普通拦截器接口Interceptor的实现类,而相比于普通拦截器而言,SSE 拦截器多了onSSEOpen和onSSEClose方法可重写,分别用于在 SSE 开始监听和结束监听时调用。

此外,和自定义 SSE 控制器一样,可以在 SSE 拦截器中也可以声明和定义 SSE 事件处理方法

// 自定义 SSE 拦截器,需实现 SSEInterceptor 接口
public class MySSEInterceptor implements SSEInterceptor {
    
    // onSSEOpen 方法可重写,可不重写
    @Override
    public void onSSEOpen(EventSource eventSource) {
        // SSE 开始监听时调用
    }

    // onSSEClose 方法可重写,可不重写
    @Override
    public void onSSEClose(ForestRequest request, ForestResponse response) {
        // SSE 结束监听时调用
    }

    // 1.6.4+ 版本可以重写 onMessage 方法来接收 SSE 消息
    @Override
    public void onMessage(EventSource event) {
        event.id(); // 获取消息名称为 id 的消息值
        event.event(); // 获取消息名称为 event 的消息值
        event.data(); // 获取消息名称为 data 的消息值
        event.retry(); // 获取消息名称为 retry 的消息值
        event.value("text"); // 获取非标准消息名称为 text 的消息值
    }

    // 只处理消息名为 data 的事件
    @SSEDataMessage
    public void onSSEData(EventSource eventSource, @SSEName String name, @SSEValue String value) {
        // 处理事件消息名称为 data 的事件
        // 声明的方法名和处理的事件消息名称没有关系,方法名可以是 onData、onSseData、onMessage、xxx、以及任何名称都可以
        // @SSEName 注解修饰的参数 name 为事件消息名称 (同 eventSource.name())
        // @SSEValue 注解修饰的参数 value 为事件消息的值
        eventSource.sse(); // 获取 SSE 控制器
        eventSource.request(); // 获取 Forest 请求对象
        eventSource.response(); // 获取 Forest 响应对象
        eventSource.rawData(); // 获取事件消息的原始数据
        eventSource.name(); // 获取事件消息的名称,如 data、event、id 等
        eventSource.value(); // 获取事件消息的值,返回字符串类型数据
        // 获取事件消息的值,并将消息转换为指定的自定义类型
        eventSource.value(MyUser.class);
        // 获取事件消息的值,并将消息转换为指定的自定义泛型类型
        eventSource.value(new TypeReference<List<MyUser>>() {});
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

关于具体如何声明和定义 SSE 事件消息的处理方法,请参见《SSE事件处理方法》

# SSE 拦截器与 Spring 集成

SSE 控制器和自定义 SSE 控制器都是非单例的独立实例对象,所以无法直接注入和使用 spring 上下文中的资源。

而 SSE 拦截器接口SSEInterceptor继承自Interceptor,可以注入到 spring 上下文中并使用其中的 bean,但和普通拦截器一样,一定要加上@Component注解,或者确保它一定被 Spring 扫描器扫描到

// 要注入 Spring 上下文的,一定要加上 @Component 注解,不加上就不能注入到 Spring 上下文
@Component
public class MySSEInterceptor implements SSEInterceptor {
    
    // 可以注入 Spring 上下文中的对象
    @Resource
    private MyUserService myUserService;

}
1
2
3
4
5
6
7
8
9

# 在 SSE 拦截器中传递数据

注意

不能使用共享变量

由于 SSE 拦截器是单例,所以不能像 SSE 控制器那样使用共享变量的方式来传递数据

而应该像普通拦截器那样使用Attribute或Attachment

详情请参见《在拦截器中传递数据》

使用Attribute或Attachment来实现跨生命周期、跨事件消息的数据传递

// 自定义 SSE 拦截器,需实现 SSEInterceptor 接口
public class MySSEInterceptor implements SSEInterceptor {

    @Override
    public void onSuccess(InputStream data, ForestRequest request, ForestResponse response) {
        // 请求发送成功是调用
        // 创建或获取名为 text 的 Attachment,类型为 StringBuilder
        StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
        builder.append("onSuccess\n");
    }

    @Override
    public void afterExecute(ForestRequest request, ForestResponse response) {
        // 请求执行完成后调用
        // 创建或获取名为 text 的 Attachment,类型为 StringBuilder
        StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
        builder.append("afterExecute\n");
    }

    @SSEDataMessage
    public void onData(ForestRequest request, @SSEName String name, @SSEValue String value) {
        // 处理事件消息名称为 data 的事件 
        // 创建或获取名为 text 的 Attachment,类型为 StringBuilder
        StringBuilder builder = (StringBuilder) request.getOrAddAttachment("text", StringBuilder::new);
        builder.append("Receive name=" + name + "; value=" + value + "\n");
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
帮助我们改善此文档 (opens new window)
上次更新: 2025/02/27, 23:53:41
🐶 SSE 控制器
🦄 SSE 事件处理方法

← 🐶 SSE 控制器 🦄 SSE 事件处理方法→

Theme by Vdoing | Copyright © 2016-2025 公子骏 | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式