🔸 기존에 많이 사용한 RestTemplate과 WebClient의 가장 큰 차이점은 RestTemplate는 Blocking이고, WebClient는 Non-Blocking 방식이라는 것
- Blocking은 호출되는 함수가 호출하는 함수에게 제어권을 넘기지 않고 대기하게 함
 - Non-Blocking은 제어권을 바로 넘김
 
현재 RestTemplate는 Spring 5.0 이후부터 Deprecated되었고, WebClient는 앞서 설명하였듯 블로킹되지 않아 성능이 더 좋기 때문에 WebClient를 사용하는 것이 권장됨
: Spring에서 제공하는 HTTP Client로 REST API를 호출하기 위한 함수를 제공하는 클래스
💡 동기
동기는 데이터 요청의 결과를 기다림 👉 요청과 결과가 한 자리에서 동시에 일어남
ex)
카페에 방문해 커피를 주문할 때, 직원이 한 명 뿐이라면
→ 직원에게 커피를 주문
→ 주문을 받은 직원은 즉시 커피를 제조
→ 제조된 커피 수령
이러한 프로세스가 진행되고 이처럼 요청과 결과가 동시에 일어나는 것을 동기라고 함
💡 비동기
비동기는 데이터를 요청한 후 결과를 기다리지 않음 👉 요청과 결과가 동시에 일어나지 않음
ex)
카페에 방문해 커피를 주문할 때, 주문을 받는 직원과 커피를 내리는 직원이 있다면
→ 주문을 받는 직원에게 커피를 주문
→ 주문을 받은 직원은 커피를 내리는 직원에게 주문 전달
→ 이후 새로운 주문을 받음
이처럼 요청과 결과가 동시에 일어나지 않는 것을 비동기라고 합니다.
- getForObject() : 주어진 URL 주소로 HTTP GET 메소드로 객체 결과를 반환받음
 - getForEntity() : 주어진 URL 주소로 HTTP GET 메소드로 ResponseEntity로 결과를 반환받음
 - postForLocation() : POST 요청을 보내고 결과로 헤더에 저장된 URI를 결과로 반환받음
 - postForObject() : POST 요청을 보내고 객체로 결과를 반환받음
 - postForEntity() : POST 요청을 보내고 결과로 ResponseEntity로 반환받음
 - delete() : 주어진 URL 주소로 HTTP DELETE 메소드를 실행
 - headForHeaders() : 헤더의 모든 정보를 얻을 수 있으며 HTTP HEAD 메소드를 사용
 - put() : 주어진 URL 주소로 HTTP PUT 메소드를 실행
 - patchForObject() : 주어진 URL 주소로 HTTP PATCH 메소드를 실행
 - optionsForAllow() : 주어진 URL 주소에서 지원하는 HTTP 메소드를 조회
 - exchange() : HTTP 헤더를 새로 만들 수 있고 어떤 HTTP 메소드도 사용 가능
 - execute() : Request/Response 콜백을 수정할 수 있음
 
🔹 getForObject → 응답 body만 있으면 될 때
public void getBeerObject() {
	RestTemplate restTemplate = new RestTemplate();
    // 랜덤으로 세계 맥주에 대한 정보를 주는 url
    String url = "https://random-data-api.com/api/v2/beers";
    
    BeerGetDto responseBody = restTemplate.getForObject(url, BeerGetDto.class);
    log.info(responseBody.toString());
}
👉 getForObject는 응답을 지정한 타입으로 변환해서 받아줌
🔹 getForEntity → 응답을 좀더 상세하게 받을 때 사용
public void getBeerEntity() {
	RestTemplate restTemplate = new RestTemplate();
    // 랜덤으로 세계 맥주에 대한 정보를 주는 url
    String url = "https://random-data-api.com/api/v2/beers";
    
    ResponseEntity<BeerGetDto> response =
    		restTemplate.getForEntity(url, BeerGetDto.class);
    log.info(response.getStatusCode().toString());
    log.info(response.getHeaders().toString());
}
🔹 postForObject → Request Body를 DTO의 형태로 포함해서 요청
public void postBeerObject() {
	RestTemplate restTemplate = new RestTemplate();
    // 랜덤으로 세계 맥주에 대한 정보를 주는 url
    String url = "https://random-data-api.com/api/v2/beers";
    
    BeerPostDto dto = new BeerPostDto();
    dto.setName("Stella Artois");
    dto.setCc(2000L);
    dto.setAlcohol(5.0);
    
    // POST 요청 보낼 때 requestBody를 같이 전달
    MessageDto responseBody = restTemplate.postForObject(
    		url,	// 요청 URL
            dto,	// request Body
            MessageDto.class	// 응답 해석 타입
    );
    log.info(responseBody.toString());
}
🔺 응답 Body가 없을 경우, Void 클래스를 활용
 url = "http://localhost:8081/give-me-beer-204";
        ResponseEntity<Void> response = restTemplate.postForEntity(
                url,
                dto,
                Void.class  // void 의 클래스 (객체화 불가)
        );
        log.info(response.getStatusCode().toString());     
🔹 exchange() 메소드
restTemplate.exchange(
		url,
        HttpMethod.Post,
        new HttpEntity<>(dto),
        Void.class
);
: Blocking 동기방식인 RestTemplate와 달리 Non-Blocking 방식
→ 현재는 Spring에서 WebClient의 사용을 강력히 권고함
implementation 'org.springframework.boot:spring-boot-starter-webflux'
@Service
@Slf4j
public class BeerClientService {
	public void getBeer() {
    	// WebClient는 Builder 패턴 처럼 사용
    	WebClient webClient = WebClient.builder().build();
        String url = "https://random-data-api.com/api/v2/beers";
        
        // 어떤 HTTP 메소드로 요청 보낼지를 get(), post() 메소드 등으로 결정
        // 만일 다른 메소드를 쓰고 싶다면, method()
        String response = webClient.get() // webClient.method(HttpMethod.GET)
        		.uri(url)	// 요청 경로 설정
                .header("x-test", "header") // 요청 헤더 추가
                // body도 메소드에 따라 추가
                .retrieve()	// 여기 전까지가 요청을 정의 한 부분
                // 여기부터 정의하는건 응답을 어떻게 처리할 것인지
                .bodyToMono(String.class)	// 응답이 한번 돌아오고, 응답의 body를 String으로 해석
                .block();	// 동기식으로 처리
       	log.info(response);
   	}
}
	public void postBeer() {
    	WebClient webClient = WebClient.builder().build();
        String url = "https://random-data-api.com/api/v2/beers";
        
        BeerPostDto dto = new BeerPostDto();
        // POST 요청
        MessageDto responseBody = webClient.post()
        		.uri(url)	// url 정의
                .bodyValue(dto)	// requestBody 정의
                .retrieve()	// 응답 정의 시작
                .bodyTOMono(MessageDto.class)	// 응답 데이터 정의
                .block();	// 동기식 처리
                
       	log.info(responseBody.toString());
  	}
잘읽고갑니다