Java/WebFlux

[Java] Spring Boot Webflux 이해하기 -2 : 활용하기

adjh54 2023. 8. 13. 16:14
728x170
해당 페이지에서는 Spring Boot Webflux를 이용하여 실제 구현하고 활용하는 방법과 WebClient를 이용한 다른 도메인 호출 방법에 대해 공유합니다.





💡 [참고] Spring WebFlux 관련 글에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
분류 링크
Spring Boot Webflux 이해하기 -1 : 흐름 및 주요 특징 이해 https://adjh54.tistory.com/232
Spring Boot Webflux 이해하기 -2 : 활용하기 https://adjh54.tistory.com/233
Spring Boot WebFlux 이해하고 구현하기 -1 : 반응형 프로그래밍에서 WebFlux까지 흐름 https://adjh54.tistory.com/627
Spring Boot WebFlux 활용하여 구현하기 -2: 계층구조 및 활용예시 https://adjh54.tistory.com/628
Spring Boot WebFlux 활용하여 구현하기 -3: Publisher/Subscriber 데이터 처리 타입, 에러 핸들러, 백프레셔 https://adjh54.tistory.com/629
Spring Boot WebFlux 활용 Github https://github.com/adjh54ir/blog-codes/tree/main/spring-boot-webflux

 

💡 [참고] Java에서 외부 통신을 하는 방법들에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다 
분류 주제 링크
RestTemplate Spring Boot Web 활용 : RestTemplate 이해하기 https://adjh54.tistory.com/234
WebClient Spring Boot Webflux 이해하기 -1 : 흐름 및 주요 특징 이해 https://adjh54.tistory.com/232
WebClient Spring Boot Webflux 이해하기 -2 : 활용하기 https://adjh54.tistory.com/233
Open Feign Spring Cloud OpenFeign 이해하고 활용하기 -1 : 주요 개념 및 환경 구성, 활용 예시 https://adjh54.tistory.com/616


 

1) 주요 구성요소 확인


💡 개발 환경을 구성하기 이전에 주요 구성 요소들에 대해 확인한 뒤에 환경을 설정합니다.

 
 

1. Controller vs Router


💡 Spring Webflux는 비동기적 서비스를 위한 Spring 프레임워크의 한 요소로 ‘Controller’와 ‘Router’라는 두 가지 주요 컴포넌트를 제공합니다.

💡 Controller 방식은 Spring MVC와 유사한 방식으로 HTTP 요청을 처리하는 데 사용됩니다. 이 컴포넌트는 주로 RESTful API 엔드포인트를 구현하는 데 사용됩니다.
💡 Router 방식은 HTTP 요청을 처리하는 데 사용되는 라우터 및 핸들러 함수를 정의하는 데 사용됩니다. 비동기적으로 실행되며 스레드가 블로킹되지 않아 더 높은 처리량을 달성할 수 있습니다.

결론적으로는 Controller 방식은 동기식 요청 처리에 적합하며, Router는 비동기식 요청처리에 적합합니다.
분류 Router 방식 Controller 방식
설정 방식 Java DSL을 사용하여 라우팅 규칙을 정의한다. Annotation을 사용하여 URL 경로를 정의한다.
요청 매핑 요청을 처리하는 메서드를 선택하기 위해 RequestPredicate를 사용한다. URL 경로에 @RequestMapping 어노테이션을 사용한다.
요청 처리 HandlerFunction 또는 WebFlux.fn.ServerResponse 타입의 객체를 반환한다. @RestController 어노테이션을 사용하여 해당 클래스의 모든 메서드가 HTTP 응답을 반환한다는 것을 나타낸다.
예외 처리 RouterFunction에서 예외 처리를 할 수 있다. @ControllerAdvice 어노테이션을 사용하여 예외 처리 핸들러를 등록할 수 있다.

 

[ 더 알아보기 ]

💡 엔드포인트(Endpoint)

- RESTful API에서 URI(Uniform Resource Identifier)로 식별되는 특정한 인터넷 자원에 대한 접근 경로를 말합니다.
- 클라이언트는 URI를 통해 서버에 요청을 보내고, 서버는 해당 요청에 대한 응답을 반환합니다.
- 예를 들어, https://example.com/api/users는 사용자 정보를 가져오기 위한 엔드포인트입니다.


💡 Java DSL(Java Domain Specific Languague)

- 특정 도메인에서 사용되는 언어를 의미하며 자바 코드를 사용하여 Router를 정의할 수 있습니다. Router는 요청을 처리하기 위해 적절한 핸들러 함수를 선택하는 메커니즘을 제공합니다.
- Java DSL을 사용하면 코드 가독성을 높일 수 있고, Router에 대한 정적 타입 검사를 수행할 수 있습니다.

 
 
 

2. Router Function


https://jstobigdata.com/spring/a-functional-endpoint-in-spring-webflux/

💡 Router Function

- Handler Function을 호출하는 역할을 합니다. 이를 통해 HTTP 요청을 받고 적절한 Handler Function으로 라우팅 할 수 있습니다.
- Router Function은 RouterFunctions 클래스를 사용하여 생성할 수 있으며 다양한 메서드를 사용하여 HTTP 요청에 따라 적절한 Handler Function으로 라우팅 할 수 있습니다.
- Router Function을 사용하면 라우팅 규칙을 보다 직관적이고 유연하게 제어할 수 있습니다.
@Bean
public RouterFunction<ServerResponse> routerFunction(ServiceHandler handler) {
    return RouterFunctions.route(RequestPredicates.GET("/service/{id}"), handler::getService)
            .andRoute(RequestPredicates.GET("/services"), handler::getServices)
            .andRoute(RequestPredicates.POST("/service"), handler::createService)
            .andRoute(RequestPredicates.PUT("/service/{id}"), handler::updateService)
            .andRoute(RequestPredicates.DELETE("/service/{id}"), handler::deleteService);
}

 

[ 더 알아보기 ]

💡RequestPredicates

- Spring WebFlux에서 HTTP 요청을 처리하기 위한 RouterFunction을 작성할 때 사용되는 요청 매핑 조건을 나타내는 클래스입니다.
- RequestPredicates 클래스는 정적 메서드로 여러 요청 매핑 조건을 만들 수 있습니다.

 
 
 

3. Handler Function


💡 Handler Function

- 단일 입력과 단일 출력을 가지며, Spring WebFlux Framework가 HTTP 요청을 처리하기 위해 호출하는 메서드입니다.

- Handler Function은 Router Function에 매핑됩니다. Router Function은 HTTP 요청을 Handler Function으로 라우팅 하는 Spring WebFlux Framework의 메서드입니다.
@Service
public class ServiceHandler {
    private final ServiceRepository serviceRepository;

    public ServiceHandler(ServiceRepository serviceRepository) {
        this.serviceRepository = serviceRepository;
    }

    public Mono<ServerResponse> getService(ServerRequest request) {
        return serviceRepository.findById(request.pathVariable("id"))
                .flatMap(service -> ServerResponse.ok().body(BodyInserters.fromValue(service)))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    public Mono<ServerResponse> getServices(ServerRequest request) {
        return ServerResponse.ok().body(serviceRepository.findAll(), Service.class);
    }

    public Mono<ServerResponse> createService(ServerRequest request) {
        return request.bodyToMono(Service.class)
                .flatMap(service -> serviceRepository.save(service))
                .flatMap(service -> ServerResponse.created(URI.create("/service/" + service.getId())).build());
    }

    public Mono<ServerResponse> updateService(ServerRequest request) {
        return request.bodyToMono(Service.class)
                .flatMap(service -> serviceRepository.findById(request.pathVariable("id"))
                        .flatMap(existingService -> {
                            existingService.setName(service.getName());
                            existingService.setDescription(service.getDescription());
                            return serviceRepository.save(existingService);
                        }))
                .flatMap(service -> ServerResponse.noContent().build())
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    public Mono<ServerResponse> deleteService(ServerRequest request) {
        return serviceRepository.deleteById(request.pathVariable("id"))
                .flatMap(result -> ServerResponse.noContent().build())
                .switchIfEmpty(ServerResponse.notFound().build());
    }
}

 
 
 

4. Mono


💡 Mono

- Reactor 라이브러리에서 제공하는 Reactive Streams의 Publisher 중 하나로 오직 ‘0개 또는 하나의 데이터항목 생성’하고 이 결과가 생성되고 나면 스트림이 종료되면 결과 생성을 종료합니다.

- Mono를 사용하여 비동기적으로 결과를 반환하면 해당 결과를 구독하는 클라이언트는 결과가 생성될 때까지 블로킹하지 않고 다른 작업을 수행할 수 있습니다.
public Mono<String> getData() {
    // perform some database or API call to get data
    return Mono.just("example data");
}

 
 
 

5. Flux


💡 Flux

- Reactor 라이브러리에서 제공하는 Reactive Streams의 Publisher 중 하나로 Mono와 달리 ‘여러 개의 데이터 항목’를 생성하고 스트림이 종료되면 결과 생성을 종료합니다.

- 비동기 작업을 수행하면 작업이 완료될 때까지 블로킹하지 않고 다른 작업을 수행할 수 있습니다.
- Spring WebFlux에서 Flux를 사용하여 HTTP 요청을 처리하는 경우, 요청을 수신한 즉시 해당 요청을 처리하고 결과를 생성하는 대신 결과 생성이 완료될 때까지 다른 요청을 처리할 수 있습니다.
public Flux<String> getStreamedData() {
    // perform a continuous stream of data
    return Flux.just("streamed data 1", "streamed data 2", "streamed data 3");
}

 
 
 
 
 

2) 환경 구성


1. 개발환경


 

[ 더 알아보기 ]

💡 Webflux랑 SQL Mapper(MyBatis)는 함께 사용이 불가능 한가?

- 함께 사용하기가 어렵다. WebFlux의 경우는 비동기적이고 논 블로킹 방식으로 동작하며, MyBatis는 동기적 블로킹 방식으로 동작하기 때문에 같이 사용하면 MyBatis가 디폴트로 사용하는 스레드 풀을 블로킹하게 되어 전체적인 성능에 악영향을 미칠 수 있다고 합니다.


💡 그럼 Webflux랑 ORM(Object-Relational Mapping)는 함께 사용이 가능한가?

- WebFlux는 비동기 및 논 블로킹 방식으로 동작하며, ORM은 동기적인 블로킹 방식으로 동작하므로 함께 사용하면 전체적인 성능에 악영향을 미칠 수 있습니다.


💡 그럼 SQL Mapper, ORM 말고 무엇과 Webflux를 함께 사용해야하는가?
- RDBMS를 사용하는 것이 아닌 MongoDB를 함께 사용하는 것이 일반적입니다. MongoDB는 비동기적이고 논 블로킹 방식으로 동작하기 때문입니다.

 
 
 

2. gradle.build 라이브러리 추가


dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'               // Spring Boot Webflux
}

Maven Repository: org.springframework.boot » spring-boot-starter-webflux
 
 
 

3. HandlerFunction을 구성


💡 Hello 메시지를 반환해 주는 단일 반환(Mono) 값의 서비스를 구성하였습니다.
package com.adjh.multiflexapi.modules.flux.handler;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

/**
 * 코드와 관련된 라우터입니다.
 *
 * @author : jonghoon
 * @fileName : CodeRouter
 * @since : 2023/08/13
 */
@Configuration
public class CodeRouter {

    @Bean
    public RouterFunction<ServerResponse> routerFunction(CodeHandler handler) {
        return RouterFunctions.route(RequestPredicates.GET("/hello"), handler::hello)
                .andRoute(RequestPredicates.POST("/api/v2/hello"), handler::hello);
    }
}

 
 
 

4. Router Function을 구성


💡 구성한 Handler Function 함수의 서비스에 대해 Router를 통해 Endpoint를 연결합니다.
package com.adjh.multiflexapi.modules.flux.handler;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerResponse;

/**
 * 코드와 관련된 라우터입니다.
 *
 * @author : jonghoon
 * @fileName : CodeRouter
 * @since : 2023/08/13
 */
@Configuration
public class CodeRouter {

    @Bean
    public RouterFunction<ServerResponse> route(CodeHandler codeHandler) {

        return RouterFunctions.route(
                RequestPredicates.GET("/api/v2/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), codeHandler::hello);
    }
}

 
 
 

 

💡 [참고] Java에서 외부 통신을 하는 방법들에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다
분류 주제 링크
RestTemplate Spring Boot Web 활용 : RestTemplate 이해하기 https://adjh54.tistory.com/234
WebClient Spring Boot Webflux 이해하기 -1 : 흐름 및 주요 특징 이해 https://adjh54.tistory.com/232
WebClient Spring Boot Webflux 이해하기 -2 : 활용하기 https://adjh54.tistory.com/233
Open Feign Spring Cloud OpenFeign 이해하고 활용하기 -1 : 주요 개념 및 환경 구성, 활용 예시 https://adjh54.tistory.com/616
Github 외부 통신의 활용 방법을 담은 예제 Repository https://github.com/adjh54ir/blog-codes/tree/main/spring-boot-external-network

 


 

3) WebClient 이용방법 : 주요 메서드


분류 메서드 설명
인스턴스 생성 create() WebClient 인스턴스를 생성합니다.
HTTP 메소드 get() GET 요청을 정의합니다.
HTTP 메소드 post() POST 요청을 정의합니다.
HTTP 메소드 put() PUT 요청을 정의합니다.
HTTP 메소드 delete() DELETE 요청을 정의합니다.
HTTP 메소드 head() HEAD 요청을 정의합니다.
HTTP 메소드 options() OPTIONS 요청을 정의합니다.
HTTP 메소드 patch() PATCH 요청을 정의합니다.
HTTP 메소드 method() 지정된 HTTP 메소드로 요청을 정의합니다.
URI uri() 요청할 엔드포인트 URL을 지정합니다.
요청 바디 body() 요청 바디에 담을 데이터를 설정합니다.
요청 바디 bodyValue() 요청 바디에 담을 데이터를 설정합니다.
응답 결과 bodyToMono() 응답 결과를 Mono로 래핑합니다.
응답 결과 bodyToFlux() 응답 결과를 Flux로 래핑합니다.
응답 결과 retrieve() 요청 결과를 가져오는 ResponseSpec 인스턴스를 반환합니다.
응답 결과 exchange() 요청 결과를 ClientResponse 인스턴스로 가져옵니다.
응답 결과 exchangeToMono() 요청 결과를 Mono로 래핑합니다.
응답 결과 exchangeToFlux() 요청 결과를 Flux로 래핑합니다.
응답 결과 exchangeToBodilessEntity() 응답 결과를 ResponseEntity<Void>로 래핑합니다.
응답 결과 toEntity() 응답 결과를 ResponseEntity로 래핑합니다.
요청 헤더 headers() 요청 헤더를 설정합니다.
요청 헤더 header() 요청 헤더를 설정합니다.
요청 헤더 cookies() 쿠키를 설정합니다.
요청 헤더 cookie() 쿠키를 설정합니다.
요청 헤더 accept() 요청 헤더에서 Accept 헤더를 설정합니다.
요청 헤더 acceptCharset() 요청 헤더에서 Accept-Charset 헤더를 설정합니다.
요청 헤더 acceptEncoding() 요청 헤더에서 Accept-Encoding 헤더를 설정합니다.
요청 헤더 acceptLanguage() 요청 헤더에서 Accept-Language 헤더를 설정합니다.
요청 헤더 contentType() 요청 헤더에서 Content-Type 헤더를 설정합니다.
요청 헤더 contentLength() 요청 헤더에서 Content-Length 헤더를 설정합니다.
요청 헤더 ifModifiedSince() 요청 헤더에서 If-Modified-Since 헤더를 설정합니다.
요청 헤더 ifNoneMatch() 요청 헤더에서 If-None-Match 헤더를 설정합니다.
예외 처리 onStatus() 지정된 HTTP 상태 코드에 대한 처리를 정의합니다.
예외 처리 onErrorResume() 지정된 예외가 발생했을 때 대체 동작을 정의합니다.
예외 처리 onErrorMap() 지정된 예외가 발생했을 때 예외를 변환하고, 변환된 예외를 다시 발생시킵니다.
예외 처리 onErrorReturn() 지정된 예외가 발생했을 때 반환할 값 또는 인스턴스를 정의합니다.
재시도 및 타임아웃 retries() 요청이 실패했을 때 재시도 횟수 및 재시도 조건을 설정합니다.
재시도 및 타임아웃 retryWhen() 재시도 횟수 및 재시도 조건을 정의합니다.
재시도 및 타임아웃 timeout() 요청이 일정 시간 이상 걸린 경우 타임아웃 처리 방법을 설정합니다.
Publisher 동작 doOnSuccess() Publisher가 값을 방출할 때마다 지정된 동작을 수행합니다.
Publisher 동작 doOnError() Publisher가 에러를 방출할 때마다 지정된 동작을 수행합니다.
Publisher 동작 doOnTerminate() Publisher가 종료될 때마다 지정된 동작을 수행합니다.
Publisher 동작 doOnSubscribe() Publisher가 구독될 때마다 지정된 동작을 수행합니다.
Publisher 동작 doOnCancel() Publisher가 취소될 때마다 지정된 동작을 수행합니다.
동기 메소드 block() Publisher가 갖는 값을 동기적으로 반환하는 메소드입니다. 해당 Publisher가 값을 방출할 때까지 대기한 후 값을 반환합니다.

 
 
 

4) WebClient 이용방법 -1 : WebClient.create() 이용방법


1. WebClient 인스턴스 생성


💡 Webflux의 WebClient를 사용하기 위해 다른 웹 서비스에 HTTP 요청을 보내기 위해 공통 URI를 입력하고 인스턴스를 생성합니다.
WebClient client = WebClient.create("<http://localhost:8000>");

// or

/**
 * 공용으로 사용하는 WebClient
 *
 * @return Webclient Instance
 */
@Bean
public WebClient webClient() {
    return WebClient.create("<http://localhost:8080>");
}
분류 메서드 설명
인스턴스 생성 create() 지정된 URL을 기반으로 WebClient 인스턴스를 만듭니다.

 
 
 

2. WebClient HTTP Method, URI, 전송 데이터를 지정합니다.


webClient()
    .post()
    .uri("/api/v1/code/code")
    .bodyValue(codeDto)
    .retrieve();
분류 메서드 설명
HTTP 메소드 get() GET 요청을 정의합니다.
HTTP 메소드 post() POST 요청을 정의합니다.
HTTP 메소드 put() PUT 요청을 정의합니다.
HTTP 메소드 delete() DELETE 요청을 정의합니다.
HTTP 메소드 head() HEAD 요청을 정의합니다.
HTTP 메소드 options() OPTIONS 요청을 정의합니다.
HTTP 메소드 patch() PATCH 요청을 정의합니다.
HTTP 메소드 method() 지정된 HTTP 메소드로 요청을 정의합니다.
URI uri() 요청할 엔드포인트 URL을 지정합니다.
요청 바디 body() 요청 바디에 담을 데이터를 설정합니다.
요청 바디 bodyValue() 요청 바디에 담을 데이터를 설정합니다.
응답 결과 bodyToMono() 응답 결과를 Mono로 래핑합니다.
응답 결과 bodyToFlux() 응답 결과를 Flux로 래핑합니다.
응답 결과 retrieve() 요청 결과를 가져오는 ResponseSpec 인스턴스를 반환합니다.
응답 결과 exchange() 요청 결과를 ClientResponse 인스턴스로 가져옵니다.
응답 결과 exchangeToMono() 요청 결과를 Mono로 래핑합니다.
응답 결과 exchangeToFlux() 요청 결과를 Flux로 래핑합니다.
응답 결과 exchangeToBodilessEntity() 응답 결과를 ResponseEntity<Void>로 래핑합니다.
응답 결과 toEntity() 응답 결과를 ResponseEntity로 래핑합니다.

 
 
 

3. WebClient의 응답 결과를 지정합니다.


webClient()
                .post()
                .uri("/api/v1/code/code")
                .bodyValue(codeDto)
                .retrieve()
                .toEntity(CodeDto.class)
                .block();
분류 메서드 설명
응답 결과 bodyToMono() 응답 결과를 Mono로 래핑합니다.
응답 결과 bodyToFlux() 응답 결과를 Flux로 래핑합니다.
응답 결과 retrieve() 요청 결과를 가져오는 ResponseSpec 인스턴스를 반환합니다.
응답 결과 exchange() 요청 결과를 ClientResponse 인스턴스로 가져옵니다.
응답 결과 exchangeToMono() 요청 결과를 Mono로 래핑합니다.
응답 결과 exchangeToFlux() 요청 결과를 Flux로 래핑합니다.
응답 결과 exchangeToBodilessEntity() 응답 결과를 ResponseEntity<Void>로 래핑합니다.
응답 결과 toEntity() 응답 결과를 ResponseEntity로 래핑합니다.
동기 메소드 block() Publisher가 갖는 값을 동기적으로 반환하는 메소드입니다. 해당 Publisher가 값을 방출할 때까지 대기한 후 값을 반환합니다.

 
 

4. 종합 결과


1. WebClient 인스턴스를 최초 생성합니다.
2. WebClient 인스턴스를 기반으로 HTTP Method의 POST 방식을 이용합니다.
3. 최종 전달하려는 http://localhost:8000/api/v1/code/code로 POST의 Body 데이터를 담아 전송합니다.
4. 전송이 되면 반환값으로 CodeDto.class 객체의 값으로 반환받습니다.
WebClient client = WebClient.create("<http://localhost:8000>");
ResponseEntity<ApiResponseWrapper> result = client
                .post()
                .uri("/api/v1/code/code")
                .bodyValue(codeDto)
                .retrieve()
                .toEntity(CodeDto.class)
                .block();
Map<String, Object> resultMap = (Map<String, Object>) result.getBody().getResult();
log.info("resultJsonObj :: " + resultMap);

 
 
 

5) WebClient 이용방법 -2 : Builder()를 이용한 방법


 💡 WebClient에서 Builder()를 사용하면 WebClient 인스턴스를 더욱 유연하게 초기화할 수 있습니다.

 

1. WebClient : Builder 메서드


분류 메서드 설명
일반적인 설정 baseUrl(String baseUrl) WebClient 인스턴스의 기본 URL을 설정합니다.
일반적인 설정 codecs(Consumer<CodecConfigurer> configurer) 요청 및 응답 바디에 사용할 코덱을 구성합니다.
일반적인 설정 defaultCookie(String name, String value) 요청에 대한 기본 쿠키 값을 설정합니다.
일반적인 설정 defaultHeader(String headerName, String... headerValues) 요청에 대한 기본 헤더 값을 설정합니다.
일반적인 설정 defaultUriVariables(Map<String, ?> defaultUriVariables) 확장된 URI 템플릿에서 사용할 기본 URI 변수를 설정합니다.
일반적인 설정 defaultUriVariables(Consumer<UriBuilderFactory> builderConsumer) UriBuilderFactory를 사용하여 확장된 URI 템플릿에서 사용할 기본 URI 변수를 설정합니다.
일반적인 설정 exchangeStrategies(ExchangeStrategies strategies) 요청 및 응답 바디에 사용할 교환 전략을 구성합니다.
일반적인 설정 filter(ExchangeFilterFunction filterFunction) ExchangeFilterFunction을 WebClient 인스턴스에 추가합니다.
일반적인 설정 filters(Consumer<List<ExchangeFilterFunction>> filters) 여러 ExchangeFilterFunction을 WebClient 인스턴스에 추가합니다.
요청 설정 accept(MediaType... acceptableMediaTypes) 응답에 대한 허용 가능한 미디어 유형을 설정합니다.
요청 설정 attribute(String name, Object value) 요청에 속성을 추가합니다.
요청 설정 body(BodyInserter<?, ? super ClientHttpRequest> inserter) 요청 바디를 설정합니다.
요청 설정 body(BodyInserter<?, ? super ClientHttpRequest> inserter, Class<?> elementClass) 요청 바디를 설정하고 요소의 클래스를 지정합니다.
요청 설정 cookies(Consumer<MultiValueMap<String, HttpCookie>> cookiesConsumer) 요청에 쿠키를 추가합니다.
요청 설정 header(String headerName, String... headerValues) 요청에 헤더를 추가합니다.
요청 설정 headers(Consumer<HttpHeaders> headersConsumer) 요청에 여러 헤더를 추가합니다.
요청 설정 ifModifiedSince(ZonedDateTime ifModifiedSince) 요청의 "If-Modified-Since" 헤더를 설정합니다.
요청 설정 ifNoneMatch(String ifNoneMatch) 요청의 "If-None-Match" 헤더를 설정합니다.
요청 설정 uri(URI uri) 요청 URI를 설정합니다.
요청 설정 uri(String uri, Object... uriVariables) 포맷된 문자열과 URI 변수를 사용하여 요청 URI를 설정합니다.
HTTP 메소드 get() GET 요청을 설정합니다.
HTTP 메소드 post() POST 요청을 설정합니다.
HTTP 메소드 put() PUT 요청을 설정합니다.
HTTP 메소드 delete() DELETE 요청을 설정합니다.
HTTP 메소드 head() HEAD 요청을 설정합니다.
HTTP 메소드 options() OPTIONS 요청을 설정합니다.
HTTP 메소드 patch() PATCH 요청을 설정합니다.
HTTP 메소드 method() 지정된 HTTP 메소드로 요청을 설정합니다.

 
 
 

2. 일반적인 방식 vs Builder를 이용한 방식


 💡 아래의 두 개의 코드가 있습니다.
- 하나는 일반적으로 사용하는 WebClient.create() 방식과 다른 하나는 Builder()를 이용한 방식입니다.
- 빌더를 사용하면 defaultHeader 메서드를 통해 공통적으로 사용되는 헤더를 추가할 수 있습니다. 또한 header 메서드를 통해 요청에 특정 헤더를 추가할 수 있습니다.

 
 

2.1. 일반적인 방식 : WebClient.create()

WebClient client = WebClient.create("<http://localhost:8000>");
ResponseEntity<ApiResponseWrapper> result = client
                .post()
                .uri("/api/v1/code/code")
                .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .header(HttpHeaders.AUTHORIZATION, "Bearer my-token")
                .bodyValue(codeDto)
                .retrieve()
                .toEntity(CodeDto.class)
                .block();
Map<String, Object> resultMap = (Map<String, Object>) result.getBody().getResult();
log.info("resultJsonObj :: " + resultMap);

 
 

2.2. Builder를 이용한 방식

WebClient client = WebClient.builder()
                .baseUrl("<http://localhost:8000>")
                .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                .defaultHeader(HttpHeaders.AUTHORIZATION, "Bearer my-token")
                .build();
ResponseEntity<ApiResponseWrapper> result = client
                .post()
                .uri("/api/v1/code/code")
                .bodyValue(codeDto)
                .retrieve()
                .toEntity(CodeDto.class)
                .block();
Map<String, Object> resultMap = (Map<String, Object>) result.getBody().getResult();
log.info("resultJsonObj :: " + resultMap);

 
 
 
 
 
오늘도 감사합니다. 😀
 
 
 
 
 

그리드형