Forest声明式HTTP客户端框架
背景说明
项目间互调RestFul接口时,需要写一堆代码,就算封装工具后也不轻松,尤其涉及到不同项目的权限问题,不同项目对外的权限认证不统一,有的是token认证,有的是密码认证,还有 OAuth2认证,不管是调用还是处理返回数据,都会消耗大量时间精力,无意中发现开源项目Forest,很是惊喜,通过简单的注解并声明相关变量,即可调用外部接口,而且返回值可以根据具体情况进行自动封装,大大节约了开发成本。 项目介绍:
Forest是一个高层的、极简的声明式HTTP调用API框架。 相比于直接使用Httpclient您不再用写一大堆重复的代码了,而是像调用本地方法一样去发送HTTP请求。
Forest能够帮助您使用更简单的方式编写Java的HTTP客户端,快速接入第三方RESTful接口 Forest特性以Httpclient和OkHttp为后端框架 通过调用本地方法的方式去发送Http请求, 实现了业务逻辑与Http协议之间的解耦 因为针对第三方接口,所以不需要依赖Spring Cloud和任何注册中心 支持所有请求方法:GET, HEAD, OPTIONS, TRACE, POST, DELETE, PUT, PATCH 支持文件上传和下载 支持灵活的模板表达方式 支持拦截器处理请求的各个生命周期 支持自定义注解 支持OAuth2验证 支持过滤器来过滤传入的数据 基于注解、配置化的方式定义Http请求 支持Spring和Springboot集成 JSON格式数据序列化和反序列化 XML格式数据序列化和反序列化 Protobuf格式数据序列化和反序列化 JSON、XML或其他类型转换器可以随意扩展和替换 支持JSON转换框架: Fastjson, Jackson, Gson 支持JAXB形式的XML转换 可以通过OnSuccess和OnError接口参数实现请求结果的回调 配置简单,一般只需要@Request一个注解就能完成绝大多数请求的定义 支持异步请求调用 极速开始
以下例子基于Spring Boot 第一步:添加Maven依赖
直接添加以下maven依赖即可 com.dtflys.forest forest-spring-boot-starter 1.5.17 第二步:创建一个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.class, args); } }第四步:调用接口
OK,我们可以愉快地调用接口了 // 注入接口实例 @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:TestUploadxxx.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