一、说明:
Retrofit是开源的java版本的http客户端,
retrofit-spring-boot-starter
实现了Retrofit
与SpringBoot
框架快速整合,并且支持了部分功能增强,从而极大的简化spring-boot项目下http接口调用开发,相较于okHttp和HttpClient等在项目开发中优势比较明显。
1、添加依赖:
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.0.2</version>
</dependency>
2、启动类添加注解
- @RetrofitScan(“com.dabby.service.client”) 标记扫描包路径
3、定义接口
-
@RetrofitClient(baseUrl = “${test.baseUrl}”) 指定RetrofitClient客户端类,baseUrl指定base地址
-
请求方式注解包括如下:
- @HTTP/@GET/@POST 常用提交数据和获取数据
- @PUT/@DELETE
- @PATH/@HEAD/OPTIONS/@HTTP
-
请求参数注解包括如下:
- @Header/@Headers 添加请求头
-
@URL/@PATH URL缺省值设置
- @Filed/@FieldMap 用于表单传入键值对 POST请求
-
@Part/@PartMap 用户文件上传的表单字体
- @Query/@QueryMap 用于表单形式数据请求GET请求
-
@Body 常用于POST请求数据
-
标记注解
- @FormUrlEncoded 表明这是一个表单格式请求,注意每个参数需要以@Filed注解
- @Multipart 表明这是一个文件上传的Form表单:form-encoded,注意每个参数需要用@Part注解
- @Streaming 表明返回的数据是以流的方式放回,适用于数据较大场景
@RetrofitClient(baseUrl = "${test.baseUrl}")
public interface HttpApi {
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name,
@Field("age") int age);
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name,
@Part("age") RequestBody age,
@Part MultipartBody.Part file);
}
4、注入使用
@Service
public class TestService {
@Autowired
private HttpApi httpApi;
public void test() {
// 通过httpApi发起http请求
}
}
二、拓展使用
1、请求中添加时间戳参数
(1)、注入式拦截器
针对有些请求发送需要添加时间戳
@Component
public class TimeStampInterceptor extends BasePathMatchInterceptor {
@Override
public Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url();
long timestamp = System.currentTimeMillis();
//url添加时间戳参数
HttpUrl newUrl = url.newBuilder().addQueryParameter("timestamp", String.valueOf(timestamp)).build();
Request newRequest = request.newBuilder().url(newUrl).build();
return chain.proceed(newRequest);
}
}
(2)、接口上使用标注
- @Intercept
- handler 指定处理器
- include 包含某些接口
- exclude 排除某些接口
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Intercept(handler = TimeStampInterceptor.class, include = {
"/api/**"}, exclude = "/api/test/savePerson")
public interface HttpApi {
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
@POST("savePerson")
Result<Person> savePerson(@Body Person person);
}
2、自定义@Sign注解
(1) 创建自定义@Sign注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@InterceptMark
public @interface Sign {
/**
* 密钥key 支持占位符形式配置。
*/
String accessKeyId();
/**
* 密钥支持占位符形式配置。
*/
String accessKeySecret();
/**
* 拦截器匹配路径
*/
String[] include() default {
"/**"};
/**
* 拦截器排除匹配,排除指定路径拦截
*/
String[] exclude() default {
};
/**
* 处理该注解的拦截器类
* 优先从spring容器获取对应的Bean,如果获取不到,则使用反射创建一个!
*/
Class<? extends BasePathMatchInterceptor> handler() default SignInterceptor.class;
}
(2)、实现SignInterceptor
@Component
public class SignInterceptor extends BasePathMatchInterceptor {
private String accessKeyId;
private String accessKeySecret;
public void setAccessKeyId(String accessKeyId) {
this.accessKeyId = accessKeyId;
}
public void setAccessKeySecret(String accessKeySecret) {
this.accessKeySecret = accessKeySecret;
}
@Override
public Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
Request newReq = request.newBuilder()
.addHeader("accessKeyId", accessKeyId)
.addHeader("accessKeySecret", accessKeySecret)
.build();
return chain.proceed(newReq);
}
}
(3)、接口上使用@Sign
@RetrofitClient(baseUrl = "${test.baseUrl}")
@Sign(accessKeyId = "${test.accessKeyId}", accessKeySecret = "${test.accessKeySecret}", exclude = {
"/api/test/person"})
public interface HttpApi {
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
@POST("savePerson")
Result<Person> savePerson(@Body Person person);
}
3、连接池管理:
(1)配置文件添加连接池配置
retrofit:
# 连接池配置
pool:
test1:
max-idle-connections: 3
keep-alive-second: 100
test2:
max-idle-connections: 5
keep-alive-second: 50
(2)、通过@RetrofitClient的poolName属性来指定使用的连接池。
@RetrofitClient(baseUrl = "${test.baseUrl}", poolName="test1")
public interface HttpApi {
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
}
4、日志打印
retrofit:
# 日志打印拦截器
logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
retrofit:
# Http异常信息格式化器
http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatter
5、异常格式化器
(1) 使用默认的异常格式化器
retrofit:
# Http异常信息格式化器
http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatter
(2)接口中使用
/**
* Call<T>
* 不执行适配处理,直接返回Call<T>对象
*/
@GET("person")
Call<Result<Person>> getPersonCall(@Query("id") Long id);
/**
* CompletableFuture<T>
* 将响应体内容适配成CompletableFuture<T>对象返回
*/
@GET("person")
CompletableFuture<Result<Person>> getPersonCompletableFuture(@Query("id") Long id);
/**
* Void
* 不关注返回类型可以使用Void。如果http状态码不是2xx,直接抛错!
*/
@GET("person")
Void getPersonVoid(@Query("id") Long id);
/**
* Response<T>
* 将响应内容适配成Response<T>对象返回
*/
@GET("person")
Response<Result<Person>> getPersonResponse(@Query("id") Long id);
/**
* 其他任意Java类型
* 将响应体内容适配成一个对应的Java类型对象返回,如果http状态码不是2xx,直接抛错!
*/
@GET("person")
Result<Person> getPerson(@Query("id") Long id);
6、全局拦截器
@Component
public class SourceInterceptor extends BaseGlobalInterceptor {
@Override
public Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
Request newReq = request.newBuilder()
.addHeader("source", "test")
.build();
return chain.proceed(newReq);
}
}