1.概述
我们的服务通常与其他REST服务进行通信以获取信息。
从Spring 5开始,我们将使用WebClient
以反应性,非阻塞的方式执行这些请求。 WebClient
是新WebFlux
框架的一部分,该框架基于Project Reactor
构建。它具有流畅的反应式API,并且在其底层实现中使用HTTP协议。
当我们发出Web请求时,数据通常以JSON返回。 WebClient
可以为我们转换此内容。
在这篇文章中,我们将介绍如何将一个JSON数组转换为Java Array
的Object
, Array
POJO的,和List
使用POJO的WebClient
。
2.依赖关系
要使用WebClient,
我们需要在pom.xml:
添加几个依赖项pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.projectreactor</groupId>
<artifactId>reactor-spring</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
3. JSON,POJO和服务
让我们从端点http://localhost:8080/readers
开始,该端点以JSON数组的形式返回读者及其喜爱的书籍的列表:
[{
"id": 1,
"name": "reader1",
"favouriteBook": {
"author": "Milan Kundera",
"title": "The Unbearable Lightness of Being"
}
我们将需要相应的Reader
和Book
类来处理数据:
public class Reader {
private int id;
private String name;
private Book favouriteBook;
// getters and setters..
}
public class Book {
private final String author;
private final String title;
// getters and setters..
}
对于我们的接口实现,我们编写一个ReaderConsumerServiceImpl
并将其作为WebClient
的依赖项:
public class ReaderConsumerServiceImpl implements ReaderConsumerService {
private final WebClient webClient;
public ReaderConsumerServiceImpl(WebClient webclient) {
this.webclient = webclient;
}
// ...
}
4.映射JSON对象List
当我们从REST请求接收到JSON数组时,有多种方法可以将其转换为Java集合。让我们看一下各种选项,看看处理返回的数据有多么容易。我们将研究提取读者最喜欢的书。
4.1。 Mono
与Flux
Project Reactor
引入了Publisher: **Mono**
两种实现Publisher: **Mono**
和**Flux**
。
当我们需要处理零到许多或可能无限的结果时, Flux<T>
很有用。我们可以以Twitter供稿为例。
当我们知道一次返回所有结果时(如在用例中一样),我们可以使用Mono<T>
。
4.2。 WebClient
与Object
数组
首先,让我们使用WebClient.get
进行GET
调用,并使用Object[]
类型的Mono
来收集响应:
Mono<Object[]> response = webClient.get()
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Object[].class).log();
接下来,让我们将主体提取到Object
数组中:
Object[] objects = response.block();
实际的Object
这里是包含我们的数据中的任意结构。让我们将其转换为Reader
对象的数组。
为此,我们需要一个ObjectMapper
:
ObjectMapper mapper = new ObjectMapper();
在这里,我们将其声明为内联,尽管通常将其作为类的private static final
成员来完成。
最后,我们准备提取读者喜爱的书籍并将其收集到列表中:
return Arrays.stream(objects)
.map(object -> mapper.convertValue(object, Reader.class))
.map(Reader::getFavouriteBook)
.collect(Collectors.toList());
当我们要求Jackson的反序列化器将Object
作为目标类型生成时,它实际上将JSON反序列化为一系列LinkedHashMap
对象。使用convertValue
后处理效率低下。如果我们在反序列化期间向Jackson提供所需的类型,则可以避免这种情况。
4.3。带Reader
阵列的WebClient
我们可以向WebClient
提供Reader[]
而不是Object[]
:
Mono<Reader[]> response = webClient.get()
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Reader[].class).log();
Reader[] readers = response.block();
return Arrays.stream(readers)
.map(Reader:getFavouriteBook)
.collect(Collectors.toList());
在这里,我们可以看到我们不再需要ObjectMapper.convertValue
。但是,我们仍然需要进行其他转换以使用Java Stream
API并使我们的代码与List
一起使用。
4.4。带Reader
List
WebClient
如果我们希望Jackson生成Reader
的List
而不是数组,则需要描述我们要创建的List
。为此,我们向该方法提供一个由匿名内部类产生的ParameterizedTypeReference
:
Mono<List> response = webClient.get()
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List>() {});
List readers = response.block();
return readers.stream()
.map(Reader::getFavouriteBook)
.collect(Collectors.toList());
这为我们提供了我们可以使用的List
。
让我们更深入地探讨为什么需要使用**ParameterizedTypeReference** .
当类型信息在运行时可用时,Spring的WebClient可以轻松地将JSON反序列化为Reader.class
。
但是,对于泛型,如果我们尝试使用List<Reader>.class
,则会发生类型擦除。因此,Jackson将无法确定泛型的类型参数。
通过使用ParameterizedTypeReference
,我们可以克服此问题。将其实例化为匿名内部类利用了以下事实:泛型类的子类包含编译时类型信息,该信息不受类型擦除的影响,可以通过反射使用。
5.结论
在本教程中,我们看到了使用WebClient
处理JSON对象的三种不同方式.
我们看到了指定Object
数组类型和我们自己的自定义类的方法。
然后,我们学习了如何使用ParameterizedTypeReference
提供类型信息以生成List
。
0 评论