티스토리 뷰
목차
flatMapMany()
Mono를 받아 Flux를 반환하는 연산자이다. 하나의 값에서 시작해 여러 개의 값을 리턴한다는 점에서
reduce()와 반대되는 기능을 하는 것처럼 보이기도 한다.
사용 예시는 아래와 같다.
public class Example {
public static void main(String[] args) {
Mono<Integer> numbers = Mono.just(3);
Flux<Integer> result = numbers.flatMapMany(num ->
Flux.just(
num,
num + 2,
num * 2,
num * num
)
);
result.subscribe(System.out::println);
}
}
3
5
6
9
BodyInserters
protected WebClient getWebClient(String baseUrl) {
return WebClient.builder()
.baseUrl(baseUrl)
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.wiretap("reactor.netty.http.client.HttpClient", LogLevel.DEBUG,
AdvancedByteBufFormat.TEXTUAL)))
.build();
}
public Mono<CompletionResponseDTO> getResponse(CompletionRequestDTO dto) {
return getWebClient(baseUrl).post()
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + apiKey)
.body(BodyInserters.fromValue(getRequestDto(dto)))
.retrieve()
.onStatus(httpStatus -> !httpStatus.is2xxSuccessful(), clientResponse -> {
return Mono.empty();
}).bodyToMono(CompletionResponseDTO.class);
}
이어지는 몇 개의 클래스 및 메서드는 위에서 보듯이 WebClient에서 비동기 요청과 응답을 받는 데 사용되는 것들이다.
여기서 WebClient란 웹플럭스의 라이브러리로, 비동기적인 방식으로 HTTP 요청을 보내는 데 사용된다.
먼저 BodyInserters는 요청의 본문(body)을 구성하는 데 사용되는 클래스로,
다양한 정적 메서드를 사용해 요청 본문을 생성할 수 있다. 몇 가지 예를 들면 아래와 같다.
- fromValue(T value): 주어진 값으로 단일 객체를 본문에 삽입한다.
- fromPublisher(Publisher<? extends T> publisher, Class<T> elementClass)
: Mono 또는 Flux와 같은 Publisher를 사용해 본문에 스트림 데이터를 삽입한다. - fromMultipartData(Map<String, ?> parts)
: 멀티파트 형식의 본문을 생성한다. 맵을 사용해 파트의 이름과 값을 지정한다. - fromFormData(String name, String value): 폼 데이터 형식의 단일 파트를 본문에 삽입한다.
- fromFormData(String name, List<? extends CharSequence> values)
:위와 같으나 값이 두 개 이상일 경우 리스트를 사용한다. - fromFormData(MultiValueMap<String, String> formData)
:멀티파트 형식의 폼 데이터를 본문에 삽입한다. 맵을 이용해 파트를 지정한다. - fromFormData(Consumer<MultipartBodyBuilder> builderConsumer)
:멀티파트 형식의 폼 데이터를 빌더패턴을 이용해 본문에 삽입한다. - fromObject(Object value): 주어진 객체를 JSON 형식으로 직렬화하여 본문에 삽입한다.
- fromServerSentEvents(Iterable<? extends T> values): SSE 형식의 스트림 데이터를 본문에 삽입한다.
retrieve()
이 연산자 역시 웹플럭스의 WebClient에서 사용되는 메서드 중 하나이다.
이름대로 HTTP Response를 가져오는 데 사용되며, 'BodySpec'객체를 반환해 다양한 형태로 처리할 수 있다.
메서드 체이닝을 이용해 응답 처리에 사용되는 예제는 대략 아래와 같다.
- toEntity(Class<T> entityType): 응답을 지정한 클래스 형식으로 매핑하여 Mono<ResponseEntity<T>>를 반환
- toEntity(ParameterizedTypeReference<T> entityTypeRef)
: 응답을 지정한 매개변수화 타입 형식으로 매핑하여 Mono<ResponseEntity<T>>를 반환 - toEntityList(Class<T> elementType)
: 응답을 지정한 클래스 형식의 리스트로 매핑하여 Mono<ResponseEntity<List<T>>>를 반환 - toEntityList(ParameterizedTypeReference<T> elementTypeRef)
: 응답을 지정한 매개변수화 타입 형식의 리스트로 매핑하여 Mono<ResponseEntity<List<T>>>를 반환 - toBodilessEntity(): 응답을 무시하고, 응답 헤더만 포함하는 Mono<ResponseEntity<Void>>를 반환
- bodyToMono(Class<T> responseType): 응답 본문을 지정한 클래스 형식으로 매핑하여 Mono<T>를 반환
- bodyToMono(ParameterizedTypeReference<T> responseTypeRef)
: 응답 본문을 지정한 매개변수화 타입 형식으로 매핑하여 Mono<T>를 반환 - bodyToFlux(Class<T> responseType): 응답 본문을 지정한 클래스 형식으로 매핑하여 Flux<T>를 반환
- bodyToFlux(ParameterizedTypeReference<T> responseTypeRef)
: 응답 본문을 지정한 매개변수화 타입 형식으로 매핑하여 Flux<T>를 반환
onstatus()
이 메서드는 HTTP 응답 코드를 기반으로 조건부 동작을, 그러니까 원하는 예외처리나 추가 동작을 정의한다.
패키지를 열어 보면 아래와 같은 모습을 하고 있는데,
ResponseSpec onStatus(Predicate<HttpStatus> statusPredicate,
Function<ClientResponse, Mono<? extends Throwable>> exceptionFunction);
각 설명은 대략 아래와 같다.
- statusPredicate란 말 그대로 HttpStatus를 입력으로 받는다는 뜻이며,
당연하게도 해당 값이 true라면 조건이 충족되었다 간주된다. - exceptionFunction은 조건이 충족되었을 때 실행되는 함수이다. 이를 이용해 특정 코드에 대한 예외를 처리할 수 있다.
statusPredicate에 들어갈 수 있는 메서드는 아래와 같으며, 직관적인 이름 덕분에 역할을 빠르게 파악할 수 있다.
- is1xxInformational()
- is2xxSuccessful()
- is3xxRedirection()
- is4xxClientError()
- is5xxServerError()
위의 코드에서는 200번대 응답이 아니라면 비어있는 Mono를 반환하도록 되어있다.
clientConnector
설명이 길어졌으니 위 코드를 다시 가져오자.
protected WebClient getWebClient(String baseUrl) {
return WebClient.builder()
.baseUrl(baseUrl)
.clientConnector(new ReactorClientHttpConnector(
HttpClient.create()
.wiretap("reactor.netty.http.client.HttpClient", LogLevel.DEBUG,
AdvancedByteBufFormat.TEXTUAL)))
.build();
}
public Mono<CompletionResponseDTO> getResponse(CompletionRequestDTO dto) {
return getWebClient(baseUrl).post()
.accept(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + apiKey)
.body(BodyInserters.fromValue(getRequestDto(dto)))
.retrieve()
.onStatus(httpStatus -> !httpStatus.is2xxSuccessful(), clientResponse -> {
return Mono.empty();
}).bodyToMono(CompletionResponseDTO.class);
}
이번에 살펴볼 연산자는 WebClient를 구성할 때 사용되는 clientConnector와 함께 쓰이는 메서드이다.
기본적으로 WebClient는 기본 커넥터를 사용해 HTTP 요청을 처리하도록 되어있다.
하지만 clientConnector()를 사용하면 커스텀 커넥터를 지정할 수 있으며,
이를 통해 다양한 커넥터 구현체를 사용하거나 생성할 수 있다.
ReactorClientHttpConnector
clientConnector() 연산자는 ClientHttpConnector 타입의 매개변수가 필요하다.
여기서 ClientHttpConnector란 WebClient가 사용할 커넥터를 추상화한 인터페이스이다.
이때 일반적으로 ReactorClientHttpConnector를 사용해 Reactor Netty를 기반으로 한 커넥터를 설정하는데,
이때 ReactorClientHttpConnector는 실제 사용되는 클라이언트 커넥터이자 일종의 중계 역할을 맡는다고 볼 수 있다.
HttpClient.create()
이 ReactorClientHttpConnector를 생성할 때에는 HttpClient를 구성해 매개변수로 전달해주어야 하는데,
여기서 HttpClient란 Reactor Netty에서 다양한 구성 옵션과 함께 제공하는 HTTP클라이언트이다.
이때 HttpClient.create()를 이용해 새로운 HttpClient 객체를 생성할 수 있다.
wiretap()
로깅을 활성화하는 메서드이다. 첫 번째 매개변수로 로거 이름을 지정, 두 번째 매개변수로 로깅 수준을 지정한다.
위 코드에서는 reactor.netty.http.client.HttpClient 로거를 대상으로 LogLevel.DEBUG 수준의 로깅을 활성화하며,
AdvancedByteBufFormat.TEXTUAL를 이용해 로그의 형식을 텍스트로 지정한다.
'Java+Spring > WebFlux' 카테고리의 다른 글
[WebFlux]자주 사용하는 연산자 정리(5) (0) | 2023.08.27 |
---|---|
[WebFlux]자주 사용하는 연산자 정리(4) + (4) | 2023.06.04 |
[WebFlux]자주 사용하는 연산자 정리(2) - buffer (0) | 2023.05.21 |
[WebFlux]함수형 엔드포인트에서의 유효성 검증 (4) | 2023.04.07 |
[WebFlux]라우터, 함수형 엔드포인트 (2) | 2023.04.07 |
[WebFlux]현재 요청을 보낸, 로그인 사용자 정보 불러오기 (4) | 2023.04.06 |
- Total
- Today
- Yesterday
- Backjoon
- 중남미
- 면접 준비
- 세계일주
- 세계여행
- BOJ
- 여행
- 남미
- 알고리즘
- 야경
- java
- 칼이사
- Python
- 리스트
- 맛집
- 파이썬
- Algorithm
- spring
- 백준
- a6000
- 스프링
- 스트림
- 유럽여행
- RX100M5
- 유럽
- 동적계획법
- 세모
- 기술면접
- 자바
- 지지
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |