### 스프링 부트의 RestTemplate에 대한 설명

스프링 부트에서 `RestTemplate`은 외부 HTTP 서비스와 통신하기 위한 동기식(Synchronous) REST 클라이언트입니다. 스프링 프레임워크에서 제공하는 이 클래스는 HTTP 요청(GET, POST, PUT, DELETE 등)을 쉽게 보내고 응답을 처리할 수 있도록 설계되었습니다. RESTful API 호출이 필요한 경우, `RestTemplate`은 간단한 설정과 직관적인 API로 개발자가 빠르게 통합할 수 있게 해줍니다. 아래에서 설정, 사용 방법, 주요 기능을 설명합니다.

---

#### 1. RestTemplate의 기본 개념
- **동기식**: 요청을 보내고 응답을 기다린 후 결과를 반환합니다 (비동기 처리는 `WebClient` 추천).
- **HTTP 메서드 지원**: GET, POST, PUT, DELETE 등 모든 표준 HTTP 메서드 지원.
- **유연성**: 요청 헤더, 바디, 응답 타입 등을 커스터마이징 가능.
- **스프링 통합**: 스프링의 의존성 주입과 설정을 활용해 쉽게 사용.

#### 2. 의존성
`RestTemplate`은 `spring-boot-starter-web`에 포함되어 별도 의존성 추가 없이 사용 가능합니다.

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
```

---

#### 3. 기본 설정
`RestTemplate`은 스프링 빈으로 등록해 사용할 수 있습니다. 기본 설정은 스프링 부트가 자동으로 제공하지만, 필요 시 커스터마이징 가능합니다.

```java
@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder
            .setConnectTimeout(Duration.ofSeconds(5))  // 연결 타임아웃 5초
            .setReadTimeout(Duration.ofSeconds(10))    // 읽기 타임아웃 10초
            .build();
    }
}
```

- **RestTemplateBuilder**: 타임아웃, 인터셉터, 메시지 컨버터 등을 설정.

---

#### 4. RestTemplate 사용 예시

##### (1) GET 요청
```java
@Service
public class UserService {

    private final RestTemplate restTemplate;

    public UserService(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    public User getUser(Long id) {
        String url = "https://api.example.com/users/{id}";
        return restTemplate.getForObject(url, User.class, id);
    }

    public ResponseEntity<User> getUserWithResponse(Long id) {
        String url = "https://api.example.com/users/{id}";
        return restTemplate.getForEntity(url, User.class, id);
    }
}

@Data
public class User {
    private Long id;
    private String name;
    private int age;
}
```

- **`getForObject`**: 응답 본문을 직접 객체로 변환.
- **`getForEntity`**: HTTP 상태 코드, 헤더, 본문을 포함한 `ResponseEntity` 반환.

##### (2) POST 요청
```java
public User createUser(User user) {
    String url = "https://api.example.com/users";
    return restTemplate.postForObject(url, user, User.class);
}
```

- **`postForObject`**: 요청 바디에 객체를 보내고 응답 객체 반환.
- **참고**: JSON 직렬화는 `Jackson` 라이브러리에 의존 (기본 포함).

##### (3) PUT 요청
```java
public void updateUser(Long id, User user) {
    String url = "https://api.example.com/users/{id}";
    restTemplate.put(url, user, id);
}
```

- **`put`**: 응답 본문이 필요 없는 업데이트 작업.

##### (4) DELETE 요청
```java
public void deleteUser(Long id) {
    String url = "https://api.example.com/users/{id}";
    restTemplate.delete(url, id);
}
```

- **`delete`**: 리소스 삭제 요청.

##### (5) 커스텀 요청 (exchange)
```java
public User customRequest(Long id) {
    String url = "https://api.example.com/users/{id}";
    HttpHeaders headers = new HttpHeaders();
    headers.set("Authorization", "Bearer token123");
    HttpEntity<String> entity = new HttpEntity<>(headers);

    ResponseEntity<User> response = restTemplate.exchange(
        url, HttpMethod.GET, entity, User.class, id
    );
    return response.getBody();
}
```

- **`exchange`**: HTTP 메서드, 헤더, 바디를 자유롭게 설정 가능.

---

#### 5. 주요 메서드
- **`getForObject(String url, Class<T> responseType, Object... uriVariables)`**: GET 요청 후 객체 반환.
- **`getForEntity(String url, Class<T> responseType, Object... uriVariables)`**: GET 요청 후 `ResponseEntity` 반환.
- **`postForObject(String url, Object request, Class<T> responseType)`**: POST 요청 후 객체 반환.
- **`put(String url, Object request, Object... uriVariables)`**: PUT 요청 실행.
- **`delete(String url, Object... uriVariables)`**: DELETE 요청 실행.
- **`exchange(String url, HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)`**: 모든 HTTP 메서드에 대한 유연한 요청.

---

#### 6. 에러 처리
`RestTemplate`은 HTTP 오류(4xx, 5xx)를 `RestClientException`으로抛출합니다. 이를 처리하려면 try-catch 사용:

```java
try {
    User user = restTemplate.getForObject("https://api.example.com/users/999", User.class);
    return user;
} catch (HttpClientErrorException e) {
    // 4xx 오류 처리 (예: 404 Not Found)
    log.error("Client error: {}", e.getStatusCode());
    return null;
} catch (HttpServerErrorException e) {
    // 5xx 오류 처리 (예: 500 Internal Server Error)
    log.error("Server error: {}", e.getStatusCode());
    return null;
}
```

- **커스텀 에러 핸들러**:
  ```java
  restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
      @Override
      public void handleError(ClientHttpResponse response) throws IOException {
          // 커스텀 처리
      }
  });
  ```

---

#### 7. 장점과 한계
- **장점**:
  - 사용이 간단하고 직관적.
  - 스프링 생태계와 잘 통합.
  - 다양한 HTTP 요청 지원.
- **한계**:
  - 동기식이라 비동기 작업에는 부적합 (`WebClient` 권장).
  - 대규모 병렬 요청 처리 시 성능 저하 가능.
  - 스프링 5.0 이후 `WebClient`로 대체되는 추세 (유지보수 모드).

---

#### 8. WebClient와의 비교
- **`RestTemplate`**: 동기식, 간단한 REST 호출에 적합.
- **`WebClient`**: 비동기/리액티브, 대규모 트래픽 및 스트리밍에 적합.
- **권장**: 새로운 프로젝트라면 `WebClient` 고려, 기존 코드 유지보수 시 `RestTemplate` 사용.

---

#### 9. 결론
`RestTemplate`은 스프링 부트에서 외부 REST API 호출을 쉽게 처리할 수 있는 도구로, 동기식 요청이 필요한 환경에서 유용합니다. 기본 메서드로 간단한 GET/POST 요청을 처리하거나, `exchange`로 복잡한 요청을 커스터마이징할 수 있습니다. 비록 `WebClient`가 최신 트렌드로 자리잡았지만, `RestTemplate`은 여전히 간단한 시나리오에서 강력한 선택지입니다. 위 예시를 참고하면 RESTful 통신을 빠르게 구현할 수 있습니다. 추가 질문이 있다면 언제든 물어보세요!

