现如今 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();
}
}