Skip to content

Releases: dromara/forest

v1.6.0

18 Dec 12:58
Compare
Choose a tag to compare

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 (西东)

v1.5.36

10 Apr 03:16
Compare
Choose a tag to compare

Forest v1.5.36 版本发布了!此次改动主要支持了 Fastjson2,以及 solon 版本更新

新增特性

  • feat: 支持 Fastjson2

修复问题

  • fix: okhttp 后端response.getContentLength()取不到值 (#I90MUX)
  • fix: Jackson转换器中Lazy转换Map出错

代码改动

  • Update: solon 升级为v2.6.5
  • refactor: 不在生成 multipart boundary 字符串时使用 okio 包的方法

v1.5.35

10 Apr 03:16
Compare
Choose a tag to compare

v1.5.35版本发布了!此次版本更新主要实现了后端客户端缓存可配置空间大小以及过期时间

配置后端客户端缓存

配置缓存大小和过期时间

forest:
  backend-client-cache-max-size: 512      # 后端客户端缓存最大空间大小(单位为实例个数,默认为128)
  backend-client-cache-expire-time: 3h    # 后端客户端缓存超时时间(单位为时间长度,默认为6小时)

新增特性:

  • feat: 后端客户端实例缓存可配置大小以及过期时间

v1.5.34

10 Apr 03:15
Compare
Choose a tag to compare

v1.5.34版本发布了!此次更新为解决请求不同的域名很多时,内存消耗越来越大的问题,使用 Caffeine 缓存框架作为后端客户端缓存的缓存

修复问题

  • fix: 当请求不同的域名很多时,内存消耗越来越大 (#I8J5PN)
  • fix: 高并发环境下,监控runningPoolSize值,出现负值情况&且有时候所有请求都结束了,但值没有
    归零 (#I8JNBU )
  • fix:完善单元测试之修复声明式接口,@BaseRequest@BaseURL,在有baseURL属性下,如果方法的完整URL不写端口,就会被baseURL属性的端口覆盖,并不是默认的80端口的bug
  • fix: 修复不管是是用@Address还是@BaseRequest都无法将baseUrl和@Get()中的url拼接在一起的bug (#I7CAYS)
  • fix:处理@Addrees注解中basePath已/结尾,方法url不以/开头,最终地址会出现//的bug。
  • fix: MultipartRequestBody 类冲突 (154)

代码改动

  • refactor: 将gson改为单例
  • refactor: 去掉@DownloadFile注解在下载文件时的进度日志
  • refactor: 将 forest-spring-boot3 的相关测试用例移动到 forest-test 下

贡献者

v1.5.33

10 Apr 03:15
Compare
Choose a tag to compare

Forest v1.5.33 发布了,此次版本更新主要支持了 Socks 协议的代理,以及组合注解的属性重写

新增特性:

  • feat: 支持socks代理 (#I6MLMD)
  • feat: 组合注解支持属性重写

修复问题:

  • fix: @Body注解的数组参数无法正常解析为JSON数组 (#I7UPBR)
  • fix: Content-Type为application/xml的情况下,发送byte数组数据错误 (#I7F3F0)
  • fix: @JSONBody Collection codes 报错 (#I7QLTS)

代码改动:

  • add: @SocksProxy注解
  • add: @OverrideAttribute注解
  • opt: 优化URL更新方式
  • update: forest-solon-plugin 升级 solon 为:2.4.0

鸣谢:

  • forest-solon-plugin 升级 solon 为:2.4.0 由 @noear_admin 贡献
  • 解决issure:#I7QLTS 由 @angle94 贡献

新特性如何使用:

v1.5.32

10 Apr 03:14
Compare
Choose a tag to compare

v1.5.32 版本发布了!此次版本更新主要修复一些BUG。

修复问题:

  • fix: 在@Header参数中传入 Lazy Lambda 出错 (#I7EIAB)
  • fix: URLEncoder 无法编码百分号字符 (134)

代码改动:

opt: 异步线程池初始化时并发优化

v1.5.31

10 Apr 03:14
Compare
Choose a tag to compare

Forest v1.5.31 发布了!该版本是一个小版本发布,主要修复了一些BUG

新增特性

  • feat: 所有 Forest 请求默认带上User-Agent: forest/{version}的请求头

修复问题

  • fix: maven中各模块的JDK版本控制
  • fix: 不同 ForestConfiguration 产生的 Client 实例存在参数污染的情况
  • fix: 当@Address注解的 schema 属性设置为 https 时报错 (#I6Y6E2)
  • fix: ReflectUtils.getFields非线程安全 (#I6W9TF)

代码改动

  • opt: ForestMethod 使用懒加载的方式初始化
  • refactor: 使用 revision 进行多模块版本管理
  • refactor: 请求注解的 interceptor 属性只接受继承自 Interceptor 接口的类
  • add: Forest.VERSION字段,可动态获取 Forest 版本号

v1.5.30

10 Apr 03:13
Compare
Choose a tag to compare

v1.5.30版本发布了,这次版本更新有了较大的改动,支持和适配了 SpringBoot3 和 Solon 框架,将XML模块拆分出了主模块,以及新增了延迟参数特性

适配 SpringBoot3

项目中新增了forest-spring-boot3-starter模块,集成时需引入如下的依赖

<!-- Forest 的 SpringBoot3 适配模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-spring-boot3-starter</artifactId>
    <version>1.5.30</version>
</dependency>

<!-- Forest 的 Jakarta XML 支持模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-jakarta-xml</artifactId>
    <version>1.5.30</version>
</dependency>

如果是老版本 SpringBoot,依赖方式基本不变,但XML的模块需额外引入

<!-- Forest 对 SpringBoot1或2 的适配模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-spring-boot-starter</artifactId>
    <version>1.5.30</version>
</dependency>

<!-- Forest 的 JAXB 支持模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-jaxb</artifactId>
    <version>1.5.30</version>
</dependency>

具体做法参考示例项目 https://gitee.com/dromara/forest/tree/master/forest-examples

适配 Solon

项目中新增了forest-solon-plugin模块,集成时需引入如下的依赖

<!-- Forest 的 Solon 适配模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-solon-plugin</artifactId>
    <version>1.5.30</version>
</dependency>

<!-- Fastjson、Jackson、Gson 中任选一个JSON框架 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.83</version>
</dependency>

<!-- Forest 的 JAXB 支持模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-jaxb</artifactId>
    <version>1.5.30</version>
</dependency>

具体做法参考示例项目 https://gitee.com/dromara/forest/tree/master/forest-examples

关于XML模块的说明

本次更新将XML序列化和反序列化相关功能移出了forest-core主模块,需根据不同的项目情况选择相应的 Forest XML 模块依赖。

如果项目,即普通非 SpringBoot3 项目(Spring、SpringBoot1或2)JDK版本也在17以下的项目,则用forest-jaxb依赖

<!-- Forest 的 JAXB 支持模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-jaxb</artifactId>
    <version>1.5.30</version>
</dependency>

如果您的项目是 SpringBoot3,或是 JDK 17及以上版本的项目,这选择forest-jakarta-xml依赖

<!-- Forest 的 Jakarta XML 支持模块 -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-jakarta-xml</artifactId>
    <version>1.5.30</version>
</dependency>

延迟参数 (Lambda参数)

有很多情况,Header、Query、Body的参数值不能马上得出,而是在请求发送前的那一刻(所有请求参数都到位时)才能得出,典型的例子就是加签验证的场景(在Header中添加一个参数token,而token的值是对整个body做加密的结果)

  • 请求头的延迟参数
Forest.post("/test")
        .addHeader("Content-Type", "application/json; charset=UTF-8")
        // 这里传入的是一个 Lambda 表达式,它会在请求发送的前一刻才执行
        // 将会通过对整个请求的Body做序列化后再进行Base64运算得出一个值,并给到Authorization请求头
        .addHeader("Authorization", req -> Base64.encode("Token=" + req.body().encodeToString()))
        .addBody("id", "1972664191")
        .addBody("name", "XieYu20011008")
        .execute();
  • 请求体的延迟参数
Forest.post("/test")
        .addHeader("Content-Type", "application/json; charset=UTF-8")
        .addHeader("_id", "20011008")
        .addBody("id", "1972664191")
        // 这里传入的是一个 Lambda 表达式,它会在请求发送的前一刻才执行
        // 执行过程和原理同上
        .addBody("name", req -> "Foo" + req.headerValue("_id"))
        .addBody("token", req -> Base64.encode(req.body().encode()))
        .execute();

这里在延迟参数Lambda表达式中调用的req.body().encode()执行的body序列化过程,会自动排除调用它的延迟参数本身,所以不必担心会发生死循环的情况

新增特性

  • feat: 适配 springboot3
  • feat: 适配 solon
  • feat: 延迟参数 (Lambda参数),支持 Query, Header,Body 三种参数的延迟求值
  • feat: 可自定义异步请求池拒绝策略
  • feat: 请求体序列化接口,ForestRequest.body().encode() 和 ForestRequest.body().encodeToString()

修复问题

  • fix: #I63WWN ForestProxy添加header没有效果
  • fix: onBodyEncode 生命周期顺序问题
  • fix: 不同 ForestConfiguration 对象共用同一个异步线程池的问题
  • fix: 无法解析 localhost:8080 这类省略 http:// 的 url

其他改动

  • reflector: 将xml解析模块拆分成了 forest-jaxb 和 forest-jakarta-xml 两个子模块,需要的情况要分别自行引入
  • reflector: request body encoder
  • refactor: Forest Body clone
  • refactor: 构建 Query String 部分
  • add: HTTPRoxy 注解的 headers 属性
  • add: forest 示例工程

特别鸣谢

特别感谢 Solon 作者 (@noear_admin) 对 Forest 项目在 Solon 适配上的支持

v1.5.28

07 Dec 03:12
Compare
Choose a tag to compare

v1.5.28版本发布了,此次版本发布是小版本更新,主要是修复一些BUG,并添加了onBodyEncode拦截器回调函数

新增特性

  • feat: 拦截器新增 onBodyEncode 回调函数 (#I4WF5Q)
  • feat: 隐式转换带 BasicAuth 认证信息的请求 (#I62BTW)
  • feat: 声明式接口可返回 ForestFuture<T> 类型

修复问题

  • fix: 下载文件,从URL中取得文件名时前后双引号的问题 (#I61NPK)
  • fix: 参数为空,导致空指针问题 (110)
  • fix: @HttpClient 和 @OkHttp3 注解在 1.5.27 失效的问题
  • fix: SpringSSLKeyStore构造方法缺少参数导致SpringBoot项目启动失败
  • fix: Null Pointer Error 当指定RetryWhen (#I5WEBC)
  • fix: @BaseRequest里的 connectTimeout和readTimeout没效果 (#I5WC6U)
  • fix: 接口上@address注解的basePath设置为完整URL时,request.basePath() 结果不正确

特别鸣谢

v1.5.26

08 Aug 04:25
Compare
Choose a tag to compare

Forest v1.5.26版本发布了!此次更新主要对一些BUG进行修复

新增特性

  • feat: 在使用 OkHttp3 后端情况下,允许Query参数不转义大括号 (#I5ITW9)
  • feat: 在使用 OkHttp3 时绕过空 Multipart 错误 (#I5I1AC)

修复问题

  • fix: 默认自动绕过SSL验证
  • fix: 声明的接口返回类型如果是String(或其他Charsequencel类型)导致自定义converter (#I5L2P6)
  • fix: okhttp后端自动将charset=UTF-8转成了小写 (#I5L4AS)
  • fix: url域名信息参数赋值会自动参数后添加”/“符号路径导致错误 (#I5I62P)
  • fix: URL路径中的$字符会被转义
  • fix: 请求的ForestURL的ssl属性没有继承类里@BaseRequest的ssl信息 (#I5HXHX)

其它改动

  • update: 更新 spring 版本到5.3.19
  • update: 更新 spring boot 版本到2.6.7