티스토리 뷰

728x90
반응형

 

목차

     

    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를 이용해 로그의 형식을 텍스트로 지정한다.

    반응형
    댓글
    공지사항
    최근에 올라온 글
    최근에 달린 댓글
    Total
    Today
    Yesterday
    링크
    «   2024/05   »
    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
    글 보관함