Forest v1.6.0 版本发布了!此次版本更新功能较多,新增了包括 SSE、Jsonpath、链式条件函数等新特性。
支持 SSE
此次最大的更新,主要是支持了 SSE,并且支持声名式和编程式两种 SSE 接口
声明式 SSE 接口:
接口定义:
public interface SSEClient {
// Forest SSE 控制器类作为 SSE 接口返回类型
@Get("/sse")
ForestSSE testSSE();
// 自定义 SSE 控制器类作为 SSE 接口返回类型
@Get("/sse")
MySSEHandler testSSE2();
}
自定义 SSE 控制器类:
public class MySSEHandler extends ForestSSE {
@Override
protected void onOpen(EventSource eventSource) {
// SSE 开始监听时执行
}
@Override
protected void onClose(ForestRequest request, ForestResponse response) {
// SSE 结束监听时执行
}
@SSEDataMessage
public void onHello(@SSEValue String value) {
// 监听名称为 data 的消息事件
// @SSEValue 注解修饰的 value 参数为消息的值
}
@SSEEventMessage(valueRegex = "\\{.*name.*\\}")
public void onEvent(@SSEValue Contact contact) {
// 监听名称为 event 的消息事件
// 并且消息要满足匹配正则表达式 "\\{.*name.*\\}" 的要求
}
}
接口调用:
// ForestSSE 作为返回值的接口调用
sseClient.testSSE().listen();
// 自定义 SSE 控制器作为返回值的接口调用
sseClient.testSSE().listen();
编程式 SSE 接口:
Forest.get("http://localhost:{}/", server.getPort())
.sse() // 指定请求为 SSE 请求
.setOnOpen(eventSource -> {
// SSE 开始监听时执行
})
.setOnClose((req, res) -> {
// SSE 结束监听时执行
})
.addOnData((eventSource, name, value) -> {
// 监听到名称为 data 的消息事件时执行
})
.addOnEventMatchesPrefix("close", (eventSource, name, value) -> {
// 监听到名称为 event 的消息事件,并且消息的值满足"close"前缀匹配要求时执行
eventSource.close(); // 手动关闭 SSE 监听
})
.listen(); // 开始监听
支持链式条件函数
Forest.get("http://localhost:{}", server.getPort())
.addHeader("A", 0)
.cond(b > 100, q -> q.addHeader("B", 100)) // [单分支] 如果 b > 100,则添加 Header B:100
.cond(c > 200, q -> q.addHeader("C", 200)) // [单分支] 如果 c > 200,则添加 Header C:100
.ifThen(a > 0, q -> q.addHeader("A", a + 1)) // [多分支] 如果 a > 0,则添加 Header A:a+1
.elseIfThen(a == 0, q -> q.addHeader("A", 0)) // [多分支] 但如果 a = 0,则添加 Header A:0
.elseIfThen(a == -1, q -> q.addHeader("A", -1)) // [多分支] 但如果 a = -1,则添加 Header A:-1
.elseIfThen(a == -2, q -> q.addHeader("A", -2)) // [多分支] 但如果 a = -2,则添加 Header A:-2
.elseThen(q -> q.addHeader("A", 10)) // [多分支] 否则添加 Header A:10
.execute();
支持 JsonPath
声名式 JsonPath 注解
public interface TestJSONPathClient {
@Get("/test/user")
@JSONPathResult("$.data")
TestUser getSingleUser();
@Get("/test/user")
@JSONPathResult("$.data")
List<TestUser> getListOfUsers();
@Get("/test/user")
@JSONPathResult("$.data[*].age")
List<Integer> getListOfUserAges();
@Get("/test/user")
@JSONPathResult("$.data[?(@.age>{minAge})].age")
List<Integer> getListOfUserAges(@Var("minAge") int minAge);
}
编程式 JsonPath 接口
TestUser user = Forest.get("http://localhost:{}/test/user", server.getPort())
.executeAsResponse()
.getByPath("$.data", TestUser.class);
安全流处理接口
Forest.get("http://localhost:{}/download/test-img.jpg", server.getPort())
.executeAsStream((in, req, res) -> {
// in 为已经打开的 InpuStream 流对象
// 在这里不需要手动打开和关闭流
});
大JSON数据的流式处理
List<MyUser> list = Forest.get("http://localhost:{}/user.json", server.getPort())
.executeAsStream((in, req, res) -> {
// 在回调函数返回的数据会作为请求的最终返回值
return new Gson()
.fromJson(new JsonReader(new InputStreamReader(in)), MyUser.class)
});
新增特性
- feat: 支持SSE
- feat: 链式条件接口
- feat: 支持Jsonpath
- feat: 字符串模板可以用 {} 替代 {数字} 作为参数占位符
- feat: 类级别
@BindingVar
注解 - feat: 适配Android环境的Log
- feat: 新增 onResponse 生命周期回调函数
- feat: 支持 Optional 作为接口返回结果类型
- feat: 支持 CompletableFuture 作为接口返回结果类型
- feat: 自定义 LogHandler 支持 Spring Bean 方式注入
- feat: 美化字符串表达式报错信息
- feat: 新增安全响应流处理接口
修复问题
- fix: 百分号无法被 URLEncode 的问题
- fix: @address 注解的属性无法重写的问题
- fix: 过滤器函数无法调用
- fix: 可能出现的 connection pool shut down 问题
- fix: 在后端为okhttp3情况下,打印content-type为multiparty/form-data,body为其他类型时报错的问题
- fix: 在拦截器的onMethodInitialized方法中调用setReturnType函数无效(#I8PJ9R)
- fix: 修复未恢复parentScope导致的栈溢出(#I9TP9Z)
代码改动
- update: 缓存框架换成Hutool的LRU缓存
- update: forest-solon-plugin 升级 solon 为:3.0.1(兼容 2.5.9+)
- update: 更新依赖最新稳定版本
- refactor: 在发生 Response: [Network Error] 错误时,可以打印 status 信息
- opt: query支持线程安全
- reflector: 重构 ForestAuthenticator 接口
- refactor: 重构响应的流处理逻辑
- add: ResultGetter.openStream 方法
- refactor: 修改表达式异常报错信息格式
贡献者
- @wittplus (witt)
- @Kiroe (Kiro)
- @noear_admin (西东)