现如今 Spring Boot 已然成为 Java 开发的不二之选,随着越来越多的项目选择 Spring Boot 框架,如何简单高效的实现不同项目间的通信便尤为关键。
Retrofit 则孕育而生,其核心即为通过 HTTP 网络请求,在此基础之上进行二次封装达到更易上手的目的。
下面介绍如何在 Spring Boot 项目中集成 Retrofit 从而实现网络通讯。
一、工程结构
新建一个工程并在其下创建两个 Spring Boot 项目,其中 retrofit-server 作为服务端用于向外提供接口,retrofit-client 用于模拟客户端请求服务端,项目结构如图:
二、 服务端
1. 接口定义
服务端 retrofit-server 比较简单,通过 @RestController 创建了几个测试接口用于模拟服务,这里仅截取部分控制层接口代码。
@RestController
@RequestMapping("api/server")
public class ServerController {
@GetMapping("demo1")
public String demo1() {
return "You request demo1.";
}
@GetMapping("demo2")
public String demo2(@RequestParam("msg") String msg) {
return "You request demo2, params is: " + msg;
}
@PostMapping("demo3")
public User demo3(@RequestBody User user) {
return "You request demo3, params is: " + user.toString();
}
}
三、客户端
完成服务端的接口服务创建之后新建客户端 retrofit-client 用于模拟服务请求。
1. 依赖导入
在客户端 retrofit-client 中引入 Retrofit 依赖,配置信息如下:
<dependency>
<groupId>com.github.lianjiatech</groupId>
<artifactId>retrofit-spring-boot-starter</artifactId>
<version>2.3.9</version>
</dependency>
2. 配置示例
新建接口类 ClientApi ,并在类上添加 @RetrofitClient 注解标识请求地址。
其中 baseUrl 即为 retrofit-server 中的请求前缀,其允许通过 ${} 方式读取 yml 文件参数。同时也可根据业务场景设置连接超时时间等参数,这里不作详细介绍。
@RetrofitClient(baseUrl = "${address.url}/api/server", readTimeoutMs = 5 * 60 * 1000)
public interface ClientApi {
@GET("demo1")
Response<String> test1();
/**
* @GET => @GetMapping
* @Query => @RequestParam
*/
@GET("demo2")
Response<String> test2(@Query("msg") String msg);
/**
* @POST => @PostMapping
* @Body => @RequestBody
*/
@POST("demo3")
Response<User> test3(@Body User user);
}
3. 注解说明
在上面的例子中可以看到 retrofit 根据不同的接口请求方式定义了系列注解,其与 Spring Boot 中的注解对应关系参考下表。
| 注解 | 描述 |
|---|---|
| @GET | 作用于方法,对应接口注解中的 @GetMapping。 |
| @POST | 作用于方法,对应接口注解中的 @PostMapping。 |
| @Query | 作用于方法参数,对应接口注解中的 @RequestParam。 |
| @Body | 作用于方法参数,对应接口注解中的 @RequestBody。 |
| @Url | 作用于方法参数,用于动态指定服务地址,覆盖 baseUrl 值。 |
4. 动态服务
在第二点的例子中我们是将请求接口前缀配置在 baseUrl 中同时配置 @GET(value) 等注解使用。在 Retrofit 提供另一种请求方式,通过 @Url 参数注解覆盖 baseUrl 中值。
需要注意使用 @URL 时 @GET 等注解不能带参,此时方法上的 @GET 等参数仅用于指定请求类型。
@RetrofitClient(baseUrl = "${address.url}/api/server", readTimeoutMs = 5 * 60 * 1000)
public interface ClientApi {
@GET
Response<String> test4(@Url String url,
@Query("msg") String msg);
}
5. 拦截器
Retrofit 同时提供拦截器功能,如常见的服务请求提前认证拼接,通过继承 BasePathMatchInterceptor 类并重写 doIntercept() 方法即可,其在发送请求之前将会触发。
如下示例中在 Retrofit 发送的请求头新增了当前时间戳。
import com.github.lianjiatech.retrofit.spring.boot.interceptor.BasePathMatchInterceptor;
public class TimestampInterceptor extends BasePathMatchInterceptor {
@Override
protected Response doIntercept(Chain chain) throws IOException {
Request request = chain.request();
HttpUrl url = request.url();
long timestamp = System.currentTimeMillis();
Request newRequest = request.newBuilder()
.url(url)
.addHeader("timestamp", String.valueOf(timestamp))
.build();
return chain.proceed(newRequest);
}
}
拦截器的使用也十分简单,通过 @Intercept 注解作用于对应的服务类接口,注解包含三个参数,其描述参考下表。
| 参数 | 描述 |
|---|---|
| handler | 用于指定使用的拦截器类。 |
| include | 用于指定拦截器作用范围。 |
| exclude | 用于配置拦截器接口白名单。 |
import com.github.lianjiatech.retrofit.spring.boot.core.RetrofitClient;
import com.github.lianjiatech.retrofit.spring.boot.interceptor.Intercept;
@RetrofitClient(baseUrl = "${address.url}/api/server", readTimeoutMs = 5 * 60 * 1000)
@Intercept(handler = TestInterceptor.class, include = {"/api/**"}, exclude = "/api/test/")
public interface ClientApi {
}
四、项目配置
1. 启动配置
在工程启动类添加 @RetrofitScan 注解,参数为 Retrofit 接口类所在包路径。
@SpringBootApplication
@RetrofitScan("xyz.ibudai.retrofit")
public class RestfulClientApplication {
public static void main(String[] args) {
SpringApplication.run(RestfulClientApplication.class, args);
}
}
2. 文件配置
在工程 yml 文件添加如下配置,非必须,未配置不影响正常使用。
retrofit:
# 日志打印拦截器
logging-interceptor: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultLoggingInterceptor
# Http异常信息格式化器
http-exception-message-formatter: com.github.lianjiatech.retrofit.spring.boot.interceptor.DefaultHttpExceptionMessageFormatter
# 全局转换器工厂
global-converter-factories:
- com.github.lianjiatech.retrofit.spring.boot.core.BasicTypeConverterFactory
- retrofit2.converter.jackson.JacksonConverterFactory
# 全局调用适配器工厂
global-call-adapter-factories:
- com.github.lianjiatech.retrofit.spring.boot.core.BodyCallAdapterFactory
- com.github.lianjiatech.retrofit.spring.boot.core.ResponseCallAdapterFactory
3. 服务测试
至此已经完成 Retrofit 的基本配置,在 retrofit-client 模块中新建测试类 ClientController 并通过 @Autowired 注解注入定义的 ClientApi 进行接口调用。
完成配置后启动项目,请求下述中的接口即可通过客户端实现服务端 retrofit-server 的服务访问。
@RestController
@RequestMapping("/api/client")
public class ClientController {
@Autowired
private ClientApi clientApi;
@GetMapping("demo1")
public String demo1() {
String data = clientApi.test1().body();
return data;
}
@GetMapping("demo2")
public String demo2() {
String msg = "123";
String data = clientApi.test2(msg).body();
return data;
}
@PostMapping("demo3")
public String demo3() {
User user = new User("123", "Alex", "123456");
User data = clientApi.test3(user).body();
return data.toString();
}
@GetMapping("demo4")
public String demo4() {
String url = "http://127.0.0.1:9091/api/server/demo1";
return clientApi.test4(url).body();
}
}