Rest Client
同样我们的服务也会有调用其它第三方服务,或者我们系统内的其它微服务的需求,Quarkus提供了对Http Rest 调用的封装。这比我们直接使用HttpClient 或者 OkHttp 等Http客户端插件简单一些。类似于Spring Cloud中 RestTemplate 或者 Feign的封装功能。
本章目标
- 搭建Rest cliet
- Rest Client 异步支持
- Rest Client MultiPart支持
1 搭建Rest Client 项目
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-rest-client-jackson</artifactId>
</dependency>
1.1 实体对象:
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Country {
public String name;
public String alpha2Code;
public String capital;
public List<Currency> currencies;
public Country(String name, String alpha2Code, String capital) {
this.name = name;
this.alpha2Code = alpha2Code;
this.capital = capital;
}
public static class Currency {
public String code;
public String name;
public String symbol;
}
}
1.2 创建一个接口
这里的接口就是定义Rest client的
@Path("v2")
@RegisterRestClient(configKey = "country-api")
@RegisterClientHeaders(RestClientHeaderFactory.class)
public interface CountriesService {
@GET
@Path("/name/{name}")
Country getByName(@PathParam("name") String name);
}
- @RegisterRestClient 指定当前接口注册为一个Rest Client 属性configKey 可以理解为当前客户端配置的别称,待会在配置中可以看到。
- @RegisterClientHeaders 自定义Header的 后面说
其它跟我们定义一个普通的接口基本一致。
1.3 配置
country-api/mp-rest/url=http://127.0.0.1:8080
country-api/mp-rest/scope=javax.inject.Singleton
country-api 就是我们在上面声明的configKey 如果没有这个配置的配置文件应该这么写:
org.acme.rest.client.CountriesService/mp-rest/url=http://127.0.0.1:8080
org.acme.rest.client.CountriesService/mp-rest/scope=javax.inject.Singleton
- url: 接口的base url 如 我们定义的这个Client的全部url就是: http://127.0.0.1:8080/v2/name/jack
- scope 作用域 同Quarkus的作用域 默认是
@Dependent
- mp-rest 这个暂时没看明白 本以为是个别名 修改了之后发现不好使
1.4 定义一个接口
模式外部接口
@Path("v2/name")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class CountryResource {
private Map<String, Country> countries = new HashMap<>();
public CountryResource() {
countries.put("china", new Country("china", "Apple", "Winter fruit"));
countries.put("us", new Country("us", "Pineapple", "Tropical fruit"));
}
@Path("{name}")
@GET
public Country list(@PathParam("name") String name) {
return countries.get(name);
}
}
测试: 我这写了一个接口测试
@Path("country")
public class TestRestClientResource {
@RestClient
@Inject
CountriesService countriesService;
@GET
@Path("{name}")
@Produces(MediaType.APPLICATION_JSON)
public Country getByName(@PathParam("name") String name, @HeaderParam("Content-Type") String contentType){
System.out.println(contentType);
return countriesService.getByName(name);
}
}
可以正常返回接口的内容:
2 异步支持
这里异步有两种方式
- CompletionStage
- Uni
只需要修改一下接口的定义即可。
@GET
@Path("/name/{name}")
CompletionStage<Country> getByName2(@PathParam("name") String name);
Uni 目前并没有测试成功,可能是少了某个依赖
@GET
@Path("/name/{name}")
@Produces("application/json")
Uni<Country> getByName3(@PathParam("name") String name);
3. 自定义Header
在第一节已经说过了,在接口定义上添加@RegisterClientHeaders(RestClientHeaderFactory.class)
这个注解来指定我们自定义Hearder的实现。
public class RestClientHeaderFactory implements ClientHeadersFactory {
@Override
public MultivaluedMap<String, String> update(MultivaluedMap<String, String> incomingHeaders, MultivaluedMap<String, String> clientOutgoingHeaders) {
return incomingHeaders;
}
}
4 Multipart 支持
4.1添加依赖
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-multipart</artifactId>
</dependency>
4.2 Multipart 参数类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class MultipartBody {
@FormParam("file")
@PartType(MediaType.APPLICATION_OCTET_STREAM)
public InputStream file;
@FormParam("fileName")
@PartType(MediaType.TEXT_PLAIN)
public String fileName;
}
配置什么的沿用上面的即可,本节只是增加对Multipart这种类型的支持。
4.3 Server 端
转成字符串后原样返回:
@Path("echo")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
public String echo(String requestBody) throws Exception {
System.err.println(requestBody);
return requestBody;
}
4.4 测试代码
@POST
@Path("/multipart")
@Produces(MediaType.TEXT_PLAIN)
public String sendFile() throws Exception {
MultipartBody body = new MultipartBody();
body.fileName = "greeting.txt";
body.file = new ByteArrayInputStream("HELLO WORLD".getBytes(StandardCharsets.UTF_8));
return countriesService.sendMultipartData(body);
}
}
结果
总结
本文简单介绍了在Quarkus 定义Rest Client 方便接口调用。当然单独使用HttpClient等工具也是可以的。不过封装过的Rest Client 使用起来更加简单。