1. 개요
당사 서비스는 종종 다른 REST 서비스와 통신하여 정보를 가져옵니다.
Spring 5부터 우리는 WebClient 를 사용하여 이러한 요청을 반응적이고 차단하지 않는 방식으로 수행합니다. WebClient 는 Project Reactor 위에 구축된 새로운 WebFlux 프레임워크의 일부입니다 . 유창하고 반응적인 API가 있으며 기본 구현에서 HTTP 프로토콜을 사용합니다.
웹 요청을 하면 데이터가 JSON으로 반환되는 경우가 많습니다. WebClient 는 이것을 우리를 위해 변환할 수 있습니다.
이 기사에서는 WebClient 를 사용하여 JSON 배열 을 Object 의 Java 배열 , POJO 의 배열 및 POJO List 으로 변환하는 방법을 알아봅니다 .
2. 의존성
WebClient 를 사용하려면 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 및 서비스
좋아하는 책이 있는 독자 List을 JSON 배열로 반환 하는 엔드포인트 http://localhost:8080/readers 부터 시작하겠습니다.
[{
"id": 1,
"name": "reader1",
"favouriteBook": {
"author": "Milan Kundera",
"title": "The Unbearable Lightness of Being"
}
}, {
"id": 2,
"name": "reader2"
"favouriteBook": {
"author": "Douglas Adams",
"title": "The Hitchhiker's Guide to the Galaxy"
}
}]
데이터를 처리 하려면 해당하는 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..
}
인터페이스 구현을 위해 WebClient 를 의존성으로 사용하여 ReaderConsumerServiceImpl 을 작성합니다.
public class ReaderConsumerServiceImpl implements ReaderConsumerService {
private final WebClient webClient;
public ReaderConsumerServiceImpl(WebClient webclient) {
this.webclient = webclient;
}
// ...
}
4. JSON 개체 List 매핑
REST 요청에서 JSON 배열을 수신하면 여러 가지 방법으로 Java 컬렉션으로 변환할 수 있습니다. 다양한 옵션을 살펴보고 반환된 데이터를 처리하는 것이 얼마나 쉬운지 살펴보겠습니다. 독자들이 가장 좋아하는 책을 추출해 보겠습니다.
4.1. 모노 VS 플럭스
Project Reactor 는 두 가지 Publisher 구현인 Mono 및 Flux 를 도입 했습니다.
Flux<T> 는 0에서 많거나 잠재적으로 무한한 결과를 처리해야 할 때 유용합니다. Twitter 피드를 예로 생각할 수 있습니다.
사용 사례에서와 같이 결과가 한 번에 모두 반환된다는 것을 알고 있으면 Mono<T> 를 사용할 수 있습니다 .
4.2. 개체 배열 이 있는 WebClient
먼저 WebClient.get 으로 GET 호출을 만들고 Object[] 유형 의 Mono 를 사용 하여 응답을 수집합니다.
Mono<Object[]> response = webClient.get()
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(Object[].class).log();
다음으로 본문을 Object 배열로 추출해 보겠습니다 .
Object[] objects = response.block();
여기서 실제 개체 는 데이터를 포함하는 랜덤의 구조입니다. 이것을 Reader 개체 의 배열로 변환해 보겠습니다 .
이를 위해서는 ObjectMapper 가 필요합니다 .
ObjectMapper mapper = new ObjectMapper();
여기서는 인라인으로 선언했지만 일반적으로 클래스의 개인용 정적 최종 멤버로 수행됩니다.
마지막으로 독자들이 가장 좋아하는 책을 추출하여 List으로 모을 준비가 되었습니다.
return Arrays.stream(objects)
.map(object -> mapper.convertValue(object, Reader.class))
.map(Reader::getFavouriteBook)
.collect(Collectors.toList());
대상 유형으로 Object 를 생성 하도록 Jackson 디시리얼라이저 에 요청하면 실제로 JSON을 일련의 LinkedHashMap 객체 로 디시리얼라이즈합니다 . convertValue 를 사용한 사후 처리 는 비효율적입니다. 역직렬화 중에 원하는 유형을 Jackson에 제공하면 이를 피할 수 있습니다.
4.3. 리더 배열 이 있는 WebClient
WebClient 에 Object[ ] 대신 Reader[] 를 제공할 수 있습니다 .
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. 독자 List 이 있는 WebClient
Jackson이 배열 대신 독자 List 을 생성하도록 하려면 생성하려는 List 을 설명해야 합니다 . 이를 위해 익명의 내부 클래스 에서 생성된 ParameterizedTypeReference 를 메서드에 제공합니다.
Mono<List<Reader>> response = webClient.get()
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(new ParameterizedTypeReference<List<Reader>>() {});
List<Reader> 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 을 생성하기 위해 정보 유형을 제공하는 방법을 배웠습니다 .
항상 그렇듯이 이 기사의 코드는 GitHub에서 사용할 수 있습니다 .