开源的声明式 HTTP 客户端,无需关心请求细节,减轻开发负担!

Forest 是一个开源的 Java HTTP 客户端框架,它能够将 HTTP 所有请求信息(包括 URL、Header 以及 Body 等信息)绑定到自定义的 Interface 方法上,能够通过调用本地接口方法的方式发送 HTTP 请求。

使用 Forest 就像使用类似 Dubbo 那样的 RPC 框架一样,只需要定义接口,调用接口即可,不必关心具体发送 HTTP 请求的细节。同时将 HTTP 请求信息与业务代码解耦,方便统一管理大量 HTTP 的 URL、Header 等信息。而请求的调用方完全不必在意 HTTP 的具体内容,即使该 HTTP 请求信息发生变更,大多数情况也不需要修改调用发送请求的代码。

开源的声明式 HTTP 客户端,无需关心请求细节,减轻开发负担!


功能特性

  • 声明式接口: 通过定义地接口+注解的方式封装Http请求, 实现了业务逻辑与Http协议之间的解耦
  • 多种底层HTTP框架: 以Httpclient和OkHttp为后端框架(可根据需要二选一)
  • 不依赖中间件: 因为针对第三方接口,所以不需要依赖Spring Cloud和任何注册中心
  • 支持所有请求方法: GET, HEAD, OPTIONS, TRACE, POST, DELETE, PUT, PATCH
  • 约定大于配置: 只要添加好依赖,基本上可以什么都不配置,就能马上运行
  • 自动 JSON 转换: 内置 Jackson、Fastjson、Gson 三种JSON转换器
  • 自动 XML 转换: 内置 JAXB 形式的 XML 转换器
  • 自动 Protobuf 转换: 内置 Protobuf 格式数据转换器
  • 多种验签方式: Basic Auth、 OAuth2、以及通过自定义拦截器或注解来验签
  • Spring/Spring boot: 支持Spring和SpringBoot集成
  • 上传下载: 支持多种上传和下载的方式,并能监听数据传输进度
  • 模板表达式: 支持灵活的模板表达式,来配合声明式注解使用
  • 拦截器: 支持拦截器处理请求的各个生命周期
  • 自定义注解: 支持自定义注解,来极大增强扩展能力
  • 回调函数: 支持通过OnSuccess和OnError接口参数实现请求结果的回调
  • 异步请求: 支持方便的异步请求调用方式
  • 编程式接口: 除声明式接口外,也支持直观的编程式接口

工作原理

Forest 会将定义好的接口通过动态代理的方式生成一个具体的实现类,然后组织、验证 HTTP 请求信息,绑定动态数据,转换数据形式,SSL 验证签名,调用后端 HTTP API(httpclient 等 API)执行实际请求,等待响应,失败重试,转换响应数据到 Java 类型等脏活累活都由这动态代理的实现类给包了。请求发送方调用这个接口时,实际上就是在调用这个干脏活累活的实现类。

开源的声明式 HTTP 客户端,无需关心请求细节,减轻开发负担!

快速开始

添加Maven依赖

Springboot环境:

<dependency>  
  <groupId>com.dtflys.forest</groupId>  
  <artifactId>forest-spring-boot-starter</artifactId>  
  <version>1.5.25</version>  
</dependency>

Spring环境:

<dependency>  
    <groupId>com.dtflys.forest</groupId>  
    <artifactId>forest-core</artifactId>  
    <version>1.5.25</version>  
</dependency>  
  
<dependency>  
  <groupId>com.dtflys.forest</groupId>  
  <artifactId>forest-spring</artifactId>  
  <version>1.5.25</version>  
</dependency>

原生Java环境:

<dependency>  
  <groupId>com.dtflys.forest</groupId>  
  <artifactId>forest-core</artifactId>  
  <version>1.5.25</version>  
</dependency>

创建一个interface

以高德地图API为例:

package com.yoursite.client;  
  
import com.dtflys.forest.annotation.Request;  
import com.dtflys.forest.annotation.DataParam;  
  
public interface AmapClient {  
  
    /**  
     * 聪明的你一定看出来了@Get注解代表该方法专做GET请求  
     * 在url中的{0}代表引用第一个参数,{1}引用第二个参数  
     */
  
    @Get("http://ditu.amap.com/service/regeo?longitude={0}&latitude={1}")  
    Map getLocation(String longitude, String latitude);  
}

扫描接口

在Spring Boot的配置类或者启动类上加上 @ForestScan 注解,并在basePackages属性里填上远程接口的所在的包名

@SpringBootApplication  
@Configuration  
@ForestScan(basePackages = "com.yoursite.client")  
public class MyApplication {  
  public static void main(String[] args) {  
      SpringApplication.run(MyApplication.classargs);  
   }  
}

调用接口

// 注入接口实例  
@Autowired  
private AmapClient amapClient;  
...  
  
// 调用接口  
Map result = amapClient.getLocation("121.475078""31.223577");  
System.out.println(result);

发送JSON数据

/**  
 * 将对象参数解析为JSON字符串,并放在请求的Body进行传输  
 */
  
@Post("/register")  
String registerUser(@JSONBody MyUser user);  
  
/**  
 * 将Map类型参数解析为JSON字符串,并放在请求的Body进行传输  
 */
  
@Post("/test/json")  
String postJsonMap(@JSONBody Map mapObj);  
  
/**  
 * 直接传入一个JSON字符串,并放在请求的Body进行传输  
 */
  
@Post("/test/json")  
String postJsonText(@JSONBody String jsonText);

发送XML数据

/**  
 * 将一个通过JAXB注解修饰过的类型对象解析为XML字符串  
 * 并放在请求的Body进行传输  
 */
  
@Post("/message")  
String sendXmlMessage(@XMLBody MyMessage message);  
  
/**  
 * 直接传入一个XML字符串,并放在请求的Body进行传输  
 */
  
@Post("/test/xml")  
String postXmlBodyString(@XMLBody String xml);

发送Protobuf数据

/**  
 * ProtobufProto.MyMessage 为 Protobuf 生成的数据类  
 * 将 Protobuf 生成的数据对象转换为 Protobuf 格式的字节流  
 * 并放在请求的Body进行传输  
 *   
 * 注: 需要引入 google protobuf 依赖  
 */
  
@Post(url = "/message", contentType = "application/octet-stream")  
String sendProtobufMessage(@ProtobufBody ProtobufProto.MyMessage message);

文件上传

/**  
 * 用@DataFile注解修饰要上传的参数对象  
 * OnProgress参数为监听上传进度的回调函数  
 */
  
@Post("/upload")  
Map upload(@DataFile("file") String filePath, OnProgress onProgress);

可以用一个方法加Lambda同时解决文件上传和上传的进度监听

Map result = myClient.upload("D:\TestUpload\xxx.jpg", progress -> {  
    System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%");  // 已上传百分比  
    if (progress.isDone()) {   // 是否上传完成  
        System.out.println("--------   Upload Completed!   --------");  
    }  
});

多文件批量上传

/**  
 * 上传Map包装的文件列表,其中 {_key} 代表Map中每一次迭代中的键值  
 */
  
@Post("/upload")  
ForestRequest<Map> uploadByteArrayMap(@DataFile(value = "file", fileName = "{_key}") Map<String, byte[]> byteArrayMap);  
  
/**  
 * 上传List包装的文件列表,其中 {_index} 代表每次迭代List的循环计数(从零开始计)  
 */
  
@Post("/upload")  
ForestRequest<Map> uploadByteArrayList(@DataFile(value = "file", fileName = "test-img-{_index}.jpg") List<byte[]> byteArrayList);

文件下载

下载文件也是同样的简单

/**  
* 在方法上加上@DownloadFile注解 
* dir属性表示文件下载到哪个目录 
* OnProgress参数为监听上传进度的回调函数  
* {0}代表引用第一个参数  
*/
  
  
@Get("http://localhost:8080/images/xxx.jpg")  
  
@DownloadFile(dir = "{0}")  
  
File downloadFile(String dir, OnProgress onProgress);

调用下载接口以及监听下载进度的代码如下:

File file = myClient.downloadFile("D:\TestDownload", progress -> {  
  
   System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%"); // 已下载百分比   
   if (progress.isDone()) { // 是否下载完成  
   System.out.println("-------- Download Completed! --------");  
  
   }  
});

传送门

开源地址:

  • https://github.com/dromara/forest
推荐:
最全的java面试题库
开源的声明式 HTTP 客户端,无需关心请求细节,减轻开发负担!
PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。“在看”支持我们吧!

原文始发于微信公众号(Java笔记虾):开源的声明式 HTTP 客户端,无需关心请求细节,减轻开发负担!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/129507.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!