Forest - 轻量级HTTP客户端框架
参考:再见,HttpClient!再见,Okhttp!
我觉得对于尤其是做对接第三方api的开发同学来说,这款开源框架能帮你提高很多效率。
Forest 底层封装了2种不同的http框架:Apache httpClient和OKhttp。所以这个开源框架并没有对底层实现进行重复造轮子,而是在易用性上面下足了功夫。
我用Forest最终完成了和多个服务商api对接的项目,这些风格迥异的API,我仅用了1个小时时间就把他们转化为了本地方法。然后项目顺利上线。
Forest作为一款更加高层的http框架,其实你并不需要写很多代码,大多数时候,你仅通过一些配置就能完成http的本地化调用。而这个框架所能覆盖的面,却非常之广,满足你绝大多数的http调用请求。
Forest有以下特点:
以Httpclient和OkHttp为后端框架 通过调用本地方法的方式去发送Http请求, 实现了业务逻辑与Http协议之间的解耦 相比Feign更轻量,不依赖Spring Cloud和任何注册中心 支持所有请求方法:GET, HEAD, OPTIONS, TRACE, POST, DELETE, PUT, PATCH 支持灵活的模板表达式 支持过滤器来过滤传入的数据 基于注解、配置化的方式定义Http请求 支持Spring和Springboot集成 实现JSON和XML的序列化和反序列化 支持JSON转换框架: Fastjson, Jackson, Gson 支持JAXB形式的XML转换 支持SSL的单向和双向加密 支持http连接池的设定 可以通过OnSuccess和OnError接口参数实现请求结果的回调 配置简单,一般只需要@Request一个注解就能完成绝大多数请求的定义 支持异步请求调用
依赖:
<dependency>
<groupId>com.dtflys.forest</groupId>
<artifactId>forest-spring-boot-starter</artifactId>
<version>1.5.2-BETA2</version>
</dependency>
启动类加上扫描
@ForestScan(basePackages = "com.yymt.controller.app")
测试调用
package com.yymt.controller.app;
import com.yymt.common.dto.request.BuildingAddReqDTO;
import com.yymt.common.utils.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import java.util.Map;
/**
* @Author:xielin
* @Description:
* @Date:2021/9/2 19:41
* @Version: 1.0
*/
@RestController
@Api(tags = "test-testForestClient")
public class TestController {
// 注入接口实例
@Autowired
private TestForestClient testForestClient;
/**
* 保存
*/
@ApiOperation("getLocation")
@PostMapping("/getLocation")
public R save(){
// 调用接口
Map result = testForestClient.getLocation("121.475078", "31.223577");
System.out.println(result);
return R.ok(result);
}
/**
*
*/
@ApiOperation("uploadtest")
@PostMapping("/uploadtest")
public R upload(){
Map result = testForestClient.upload("C:\\Users\\xielin\\Desktop\\一附院视频云智能认知项目架构流程图.png", progress -> {
System.out.println("progress: " + Math.round(progress.getRate() * 100) + "%"); // 已上传百分比
if (progress.isDone()) { // 是否上传完成
System.out.println("-------- Upload Completed! --------");
}
});
System.out.println("end");
return R.ok(result);
}
}
封装的接口
package com.yymt.controller.app;
import com.dtflys.forest.annotation.*;
import com.dtflys.forest.callback.OnProgress;
import com.dtflys.forest.extensions.BasicAuth;
import com.dtflys.forest.extensions.DownloadFile;
import com.dtflys.forest.http.ForestRequest;
import java.io.File;
import java.util.List;
import java.util.Map;
public interface TestForestClient {
@Get("http://ditu.amap.com/service/regeo?longitude=${0}&latitude=${1}")
Map getLocation(String longitude, String latitude);
@Post("http://localhost:1031/dataService/file/upload?file=${0}")
Map upload(@DataFile("file") String filePath, OnProgress onProgress);
@Post("/test/json")
String postJsonMap(@JSONBody Map mapObj);
@Post("/test/json")
String postJsonText(@JSONBody String jsonText);
@Post("/test/xml")
String postXmlBodyString(@XMLBody String xml);
@Post("/upload")
ForestRequest<Map> uploadByteArrayMap(@DataFile(value = "file", fileName = "${_key}") Map<String, byte[]> byteArrayMap);
@Post("/upload")
ForestRequest<Map> uploadByteArrayList(@DataFile(value = "file", fileName = "test-img-${_index}.jpg") List<byte[]> byteArrayList);
@Get("http://localhost:8080/images/xxx.jpg")
@DownloadFile(dir = "${0}")
File downloadFile(String dir, OnProgress onProgress);
@Post("/hello/user?username=${username}")
@BasicAuth(username = "${username}", password = "bar")
String send(@DataVariable("username") String username);
}
上传图片测试结果:
@Request(
url = "${0}/send?un=${1}&pw=${2}&ph=${3}&ct=${4}",
type = "get",
dataType = "json"
)
public Map send(
String base,
String userName,
String password,
String phone,
String content
);
@Request(
url = "${base}/send?un=${un}&pw=${pw}&ph=${3}&ct=${ct}",
type = "get",
dataType = "json"
)
public Map send(
@DataVariable("base") String base,
@DataVariable("un") String userName,
@DataVariable("pw") String password,
@DataVariable("ph") String phone,
@DataVariable("ct") String content
@Request(
url = "${base}/send",
type = "get",
dataType = "json"
)
public Map send(
@DataVariable("base") String base,
@DataParam("un") String userName,
@DataParam("pw") String password,
@DataParam("ph") String phone,
@DataParam("ct") String content
);
以上三种写法是等价的
当然你也可以把参数绑定到header和body里去,你甚至于可以用一些表达式简单的把对象序列化成json或者xml:
@Request(
url = "${base}/pay",
contentType = "application/json",
type = "post",
dataType = "json",
headers = {"Authorization: ${1}"},
data = "${json($0)}"
)
public PayResponse pay(PayRequest request, String auth);
4.2 对HTTPS的支持 以前用其他http框架处理https的时候,总觉得特别麻烦,尤其是双向证书。每次碰到问题也只能去baidu。然后根据别人的经验来修改自己的代码。
Forest对于这方面也想的很周到,底层完美封装了对https单双向证书的支持。也是只要通过简单的配置就能迅速完成。举个双向证书栗子:
@Request(
url = "${base}/pay",
contentType = "application/json",
type = "post",
dataType = "json",
keyStore = "pay-keystore",
data = "${json($0)}"
)
public PayResponse pay(PayRequest request);
其中pay-keystore对应着application.yml里的ssl-key-stores
forest:
...
ssl-key-stores:
- id: pay-keystore
file: test.keystore
keystore-pass: 123456
cert-pass: 123456
protocols: SSLv3
|