上文中,我们介绍了OkHttp的一些常见的用法,以及对其API进行了一些便于调用的封装。而笔者在深入学习的过程中发现了一个基于Lambda表达式、链式调用进行封装的OkHttps,使其的调用方式更加的优雅、简介。
简介 ok.zhxu.cn/v4/introduc… OkHttps 是 2020 年开源的对 OkHttp3 轻量封装的框架,它独创的异步预处理器,特色的标签,灵活的上传下载进度监听与过程控制功能,在轻松解决很多原本另人头疼问题的同时,设计上也力求纯粹与优雅。
Maven中要想使用OkHttps,我们需要引入一个OkHttps核心包和一个OkHttps-xxxx(序列化框架)的序列化包,比如FastJson2,我们可以通过 cn.zhxu okhttps 4.0.0 cn.zhxu okhttps-fastjson2 4.0.0
如果是Jackson的话,我们只需要将fastjson2换成 cn.zhxu okhttps-jackson 4.0.0 即可。
基本使用
首先,我们需要向使用OkHttp那样,构建一个HTTP请求, 为了使用方便,我们更愿意指定一个BaseUrl和MsgConverter: HTTP http = HTTP.builder() .baseUrl("api.example.com") // GsonMsgConverter源自okhttps-gons包中,使用时更换为实际导入的序列化包 .addMsgConvertor(new GsonMsgConvertor()) .build();
随后,我们可以通过链式调用的方式来开始一个同步请求了: List users = http.sync("/users") // api.example.com/users .get() // GET请求 .getBody() // 获取响应报文体 .toList(User.class); // 得到目标数据 或者是一个异步请求: http.async("/users/1") // api.example.com/users/1 .setOnResponse((HttpResult res) -> { // 得到目标数据 User user = res.getBody().toBean(User.class); }) .get(); // GET请求 如果你想要一个WebSocket通讯的话,可以这样: http.webSocket("/chat") .setOnOpen((WebSocket ws, HttpResult res) -> { ws.send("向服务器问好"); }) .setOnMessage((WebSocket ws,Message msg) -> { // 从服务器接收消息(自动反序列化) Chat chat = msg.toBean(Chat.class); // 相同的消息发送给服务器(自动序列化 Chat 对象) ws.send(chat); }) .listen(); // 启动监听
请求三部曲 对于任何请求,OkHttps都可以将其看作为三个步骤:
- 确定请求方式(同步、异步)
- 构建请求任务(添加请求参数、设置回调函数)
- 调用请求方法(get、post、delete、put) 而对于这种模板化的开发方式,作为IDEA的开发者我们可以通过Live Template来提高我们的开发效率:
注入配置 OkHttps还支持通过SPI的方式注入自定义配置类
第一步:新建一个配置类实现cn.zhxu.okhttps.Config接口 package com.example.okhttps;
import cn.zhxu.okhttps.Config; import cn.zhxu.okhttps.HTTP;
public class OkHttpsConfig implements Config {
@Override
public void with(HTTP.Builder builder) {
// 在这里对 HTTP.Builder 做一些自定义的配置
builder.baseUrl("https://api.domo.com");
// 如果项目中添加了 okhttps-fastjson 或 okhttps-gson 或 okhttps-jackson 依赖
// OkHttps 会自动注入它们提供的 MsgConvertor
// 所以这里就不需要再配置 MsgConvertor 了 (内部实现自动注入的原理也是 SPI)
// 但如果没有添加这些依赖,那还需要自定义一个 MsgConvertor
builder.addMsgConvertor(new MyMsgConvertor());
}
} 第二步:在项目的/src/main/目录下新建resources/META-INF/services/cn.zhxu.okhttps.Config文件,文件内容是上一个配置类的全类名
为什么要使用SPI注入配置而不是直接给OkHttps设置一个静态变量实例呢? 在一般情况下这样是没问题的,但是某些JVM上(特别是Android)会在某些情况下回收静态变量,而OkHttps的HTTP实例一旦被回收之后,配置都会丢失,导致严重的问题。
对于SpringBoot项目,如果还想要导入application.yml的配置的话,我们可以现在Spring的Bean中加载配置,然后提供静态访问方法,再去配置类中访问这个Bean。 @Component public class ConfigBean {
@Value("${okhttps.baseUrl}") // 加载配置
private String baseUrl;
private static ConfigBean instance;
public ConfigBean() {
instance = this; // 将该 Bean 单例化
}
public static ConfigBean getInstance() {
return instance; // 提供静态访问方法
}
// 省略 Getter Seatter
} public class OkHttpsConfig implements Config {
@Override
public void with(HTTP.Builder builder) {
// 获取 ConfigBean
ConfigBean confg = ConfigBean.getInstance();
// 使用配置
builder.baseUrl(confg.getBaseUrl());
// 省略其它配置
}
}