반응형
반응형
해당 글에서는 RestTemplate에 대해 이해하고 활용 방법에 대해 확인해 봅니다.
1) RestTemplate
💡 RestTemplate
- HTTP 통신을 위한 도구로 RESTful API 웹 서비스와의 상호작용을 쉽게 외부 도메인에서 데이터를 가져오거나 전송할 때 사용되는 스프링 프레임워크의 클래스를 의미합니다.
- 다양한 HTTP 메서드(GET, POST, PUT, DELETE 등)를 사용하며 원격 서버와 ‘동기식 방식’으로 JSON, XML 등의 다양한 데이터 형식으로 통신합니다.
- 동기식 방식으로 요청을 보내고 응답을 받을 때까지 블로킹되며, 요청과 응답이 완료되기 전까지 다음 코드로 진행되지 않습니다. 원격 서버와 통신할 때는 응답을 기다리는 동안 대기해야 합니다.
[ 더 알아보기 ]
💡 The RestTemplate will be deprecated?
- Spring Framework 5.2.1 버전에서 RestTemplate가 Depreacted 되고 Spring Framework 5.x 버전부터 생긴 WebClient로 Migration을 하라는 이야기가 있습니다.
- 이런 이야기가 나오기는 하지만 현재 6.0.11 버전에서까지 릴리즈가 되고 있기에 Deprecated 되지 않는것 같습니다.
2) RestTemplate 특징
1. HTTP 요청 및 응답에 대해 동기식 요청으로 블로킹하여 데이터를 주고받습니다.
1.1. 동기식 요청(Synchronous request) & 블로킹 요청(Blocking Request)
💡 동기식 요청(Synchronous request) & 블로킹 요청(Blocking Request)
- RestTemplate은 기본적으로 ‘동기식 요청’ 처리를 수행하며 요청을 보내고 응답을 받을 때까지 블로킹됩니다.
[ 더 알아보기 ]
💡 블로킹 요청(Blocking Request)
- 클라이언트에서 요청을 보내면 결과가 반환될 때까지 대기를 하는 것을 의미합니다. unblocked 상태가 되면 다음 요청에 대해 처리를 수행합니다.
1.2. 비동기식 요청(Asynchrouse Request) & 논 블로킹 요청(Non-Blocking Request)
💡 비동기식 요청(Asynchrouse Request) & 논 블로킹 요청(Non-Blocking Request)
- webflux에서 제공하는 Non-Blocking Request을 수행하면서 요청을 보내고 결과가 반환되지 않더라도 다른 작업을 수행할 수 있는 것을 의미합니다.
💡 [참고] 비동기식 요청 & 논 블로킹 요청에 사용되는 WebClient에 대해 궁금하시면 아래의 글을 참고하시면 도움이 됩니다.
비교 | 동기식(Synchronous) | 비동기식(Asynchronous) |
실행 모델 | 요청과 응답이 동시에 일어남 | 요청과 응답이 동시에 일어나지 않음 |
블로킹 | 요청에 대한 응답이 올 때까지 블로킹 됨 | 요청에 대한 응답을 기다리지 않고 다른 작업을 수행할 수 있음 |
성능 | 대량의 요청이 동시에 발생하면 성능 저하가 발생할 수 있음 | 대량의 요청을 효율적으로 처리할 수 있음 |
코드 복잡도 | 비교적 간단하고 직관적임 | 코드가 복잡해지고 디버깅이 어려움 |
2. HTTP 요청 및 응답에 대한 다양한 메서드를 제공합니다
💡 RestTemplate의 경우 HTTP 요청 및 응답에 대한 HTTP Method 별(GET, POST, PUT, PATCH, DELETE) 다양한 메서드를 제공합니다.
Method | HTTP Method | Return Type | 설명 |
getForObject() | GET | Object | GET 요청에 대한 결과를 객체로 반환합니다 |
getForEntity() | GET | ResponseEntity | GET 요청에 대한 결과를 ResponseEntity로 반환합니다 |
postForLocation() | POST | URI | POST 요청에 대한 결과로 헤더에 저장된 URI 반환합니다 |
postForObject() | POST | Object | POST 요청에 대한 결과를 객체로 반환합니다 |
postForEntity() | POST | ResponseEntity | POST 요청에 대한 결과를 ResponseEntity로 반환합니다 |
put() | PUT | void | PUT 요청을 실행합니다 |
patchForObject() | PATCH | Object | PATCH 요청을 실행하고 결과를 객체로 반환합니다 |
delete() | DELETE | void | DELETE 요청을 실행합니다 |
headForHeaders() | HEADER | HttpHeaders | 헤더 정보를 추출하고 HTTP HEAD 메서드를 사용합니다 |
optionsForAllow() | OPTIONS | Set<HttpMethod> | 지원되는 HTTP 메서드를 추출합니다 |
exchange() | any | ResponseEntity | 헤더를 생성하고 모든 요청 방법을 허용합니다 |
execute() | any | T | 요청/응답 콜백을 수정합니다 |
3. HTTP 요청 및 응답을 자동으로 변환하고 역직렬화합니다.
💡 HTTP 요청 및 응답을 ‘자동’으로 변환하고 역직렬화하는 기능을 제공합니다. 이를 위해 RestTemplate은 기본적으로 MessageConverter를 사용합니다.
💡 MessageConverter는 요청 및 응답 바디의 데이터 형식을 변환하고, 요청 및 응답 헤더의 콘텐츠 형식을 설정합니다. RestTemplate은 기본적으로 다양한 MessageConverter를 제공하며, 애플리케이션에서 직접 추가할 수 있습니다.
// RestTemplate 생성
RestTemplate restTemplate = new RestTemplate();
// 요청 매개변수 설정
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<RequestDto> request = new HttpEntity<>(requestDto, headers);
// HTTP 요청 및 응답 처리
ResponseDto responseDto = restTemplate.exchange(url, HttpMethod.POST, request, ResponseDto.class).getBody();
Http Message Converters with the Spring Framework | Baeldung
[ 더 알아보기 ]
💡 직렬화(Serialization)
- 자바 객체를 외부 저장소에 저장하거나 네트워크를 통해 전송하기 위해 객체를 데이터 스트림으로 변환하는 과정입니다. 이 과정에서 객체의 필드 값들이 데이터 스트림에 쓰여집니다.
💡 역직렬화(Deserialization)
- 데이터 스트림으로부터 객체를 재구성하는 과정입니다. 이 과정에서 데이터 스트림에서 읽은 값들이 객체의 필드 값으로 설정됩니다. 이 과정에서는 데이터 스트림이 어떤 객체인지 알아야 하므로 객체의 클래스 정보가 함께 전달되어야 합니다.
4. HTTP 요청 및 응답을 다양한 형식으로 처리할 수 있습니다.
💡 RestTemplate을 이용하여 HTTP 요청 및 응답 처리를 수행하는데 여러 가지 형식으로 요청 및 응답 처리를 할 수 있습니다.
JSON, XML 및 바이너리 데이터 형식과 같은 데이터 형식으로 응답 처리를 할 수 있고 또한 HTTP 요청 및 응답의 부분을 추출하거나 수정할 수 있습니다.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
headers.add("Authorization", "Bearer <access_token>");
헤더 | 이름 값 | 설명 |
Accept | - | 클라이언트가 서버에서 받기 원하는 미디어 타입을 지정합니다. |
Accept | text/plain | 일반적인 텍스트 형식을 지정합니다. |
Accept | application/json | JSON 형식을 지정합니다. |
Accept | application/xml | XML 형식을 지정합니다. |
Content-Type | - | 서버에서 클라이언트로 보내는 미디어 타입을 지정합니다. |
Content-Type | text/plain | 일반적인 텍스트 형식을 지정합니다. |
Content-Type | application/json | JSON 형식을 지정합니다. |
Content-Type | application/xml | XML 형식을 지정합니다. |
5. HTTP 요청에 대한 요청 헤더 및 쿼리 매개변수를 설정할 수 있습니다.
💡 HTTP 요청에 대한 요청 헤더 및 쿼리 매개변수를 설정할 수 있습니다.
- 요청 헤더는 RestTemplate의 HttpHeaders 클래스를 사용하여 설정할 수 있습니다. HttpHeaders 클래스의 add() 메서드를 사용하여 요청 헤더에 새 항목을 추가할 수 있습니다.
- 쿼리 매개변수는 RestTemplate의 exchange() 메서드를 호출할 때 UriComponentsBuilder를 사용하여 설정할 수 있습니다. UriComponentsBuilder의 queryParam() 메서드를 사용하여 쿼리 매개변수를 추가할 수 있습니다.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("<http://example.com/api/users>")
.queryParam("page", 2)
.queryParam("size", 10);
HttpEntity entity = new HttpEntity<>(headers);
ResponseEntity response = restTemplate.exchange(
builder.toUriString(),
HttpMethod.GET,
entity,
String.class);
6. HTTP 요청 및 응답에 대한 로깅을 제공합니다.
💡 HTTP 요청 및 응답에 대한 로깅을 제공합니다. RestTemplate Bean을 구성하는 데 사용되는 HttpClient는 HTTP 요청 및 응답을 로깅할 수 있는 HttpClientInterceptor를 제공합니다.
💡 HttpClientInterceptor의 구현체로 재 구성합니다.
public class CustomInterceptor implements HttpClientInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
ClientHttpRequestExecution execution) throws IOException {
// Request 수정
request.getHeaders().add("Custom-Header", "Custom-Value");
// Request 정보 로깅
log.info("Request URI : {}", request.getURI());
log.info("Request Method : {}", request.getMethod());
log.info("Request Headers : {}", request.getHeaders());
log.info("Request Body : {}", new String(body, "UTF-8"));
// 다음 인터셉터 또는 요청 실행
ClientHttpResponse response = execution.execute(request, body);
// Response 정보 로깅
log.info("Response Status : {}", response.getStatusCode());
log.info("Response Headers : {}", response.getHeaders());
return response;
}
}
💡 RestTemplate 객체를 만들 때 interceptors 속성에 해당 구현체 객체를 넣습니다.
RestTemplate restTemplate = new RestTemplateBuilder()
.interceptors(new CustomInterceptor())
.build();
💡 HttpClientInterceptor
- RestTemplate에서 HTTP 요청/응답을 가로채서 수정하거나 로깅하는 인터셉터입니다.
- 로깅을 활성화하려면 RestTemplate Bean에 HttpClientInterceptor를 추가하면 됩니다.
3) RestTemplate vs WebClient
💡 동기적으로 처리되는 RestTemplate와 비 동기로 처리되는 WebClient를 비교합니다.
구분 | RestTemplate | WebClient |
요청/응답 | 동기 | 비동기 |
Connection pool | Apache Http Client | Netty |
기본 인증 | 지원 | 지원 |
OAuth2 인증 | 지원 | 지원 |
JSON 처리 | Jackson, Gson 등 | Jackson, Gson 등 |
XML 처리 | JAXB, Jackson 등 | Jackson 등 |
multipart/form-data | 지원 | 지원 |
쿠키 | 지원 | 지원 |
헤더 설정 | 지원 | 지원 |
요청 시간 초과 설정 | 지원 | 지원 |
SSL 인증서 검증 | 지원 | 지원 |
로깅 | 지원 | 지원 |
성능 | 느림 | 빠름 |
💡 [참고] Webclient에 대해 궁금하시면 아래의 글을 읽어보시면 도움이 됩니다.
4) RestTemplate 활용하기
1. 의존성 추가
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' // Spring Boot Web
}
2. RestTemplate 객체 생성
💡 RestTemplate을 사용하기 위해 최초 객체를 생성합니다.
2.1. 클래스 내의 객체 생성 방법
// RestTemplate 생성
RestTemplate restTemplate = new RestTemplate();
2.2. Bean 등록 방법
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class AppConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
💡 [참고] Bean으로 등록한 RestTemplate 객체는 @Autowired 어노테이션을 사용하여 다른 클래스에서 쉽게 사용할 수 있습니다.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Service
public class MyService {
@Autowired
private RestTemplate restTemplate;
public void myMethod() {
String url = "https://example.com/api";
ResponseEntity response = restTemplate.getForEntity(url, String.class);
System.out.println(response.getBody());
}
}
3. RestTemplate Header 구성
💡 Request Header를 설정합니다. 이 코드에서는 JSON 형식의 Request Body를 사용하므로, Content-Type을 APPLICATION_JSON으로 설정합니다.
// Request Header 설정
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
💡 [참고] HttpHeaders의 메서드 종류
메서드 | 설명 |
setContentType(MediaType mediaType) | Content-Type 헤더 설정 |
setAccept(List<MediaType> acceptableMediaTypes) | Accept 헤더 설정 |
add(String headerName, String headerValue) | 특정 헤더 추가 |
addAll(Map<String, String> headers) | 여러 개의 헤더 추가 |
setBearerAuth(String token) | Authorization 헤더에 Bearer 토큰 추가 |
setBasicAuth(String username, String password) | Authorization 헤더에 Basic 인증 정보 추가 |
setIfNoneMatch(String etag) | If-None-Match 헤더 추가 |
setIfModifiedSince(ZonedDateTime ifModifiedSince) | If-Modified-Since 헤더 추가 |
set(String headerName, String headerValue) | 특정 헤더 설정 |
[ 더 알아보기 ]
💡 Content-Type 헤더
- HTTP 요청 또는 응답에서 ‘전송되는 데이터의 형식’을 지정합니다. 이 헤더는 브라우저나 서버가 어떻게 처리해야 할지를 결정합니다.
- 예를 들어, text/plain은 일반적인 텍스트 데이터를 나타내고, application/json은 JSON 형식의 데이터를 나타냅니다.
💡 Accept 헤더
- 클라이언트가 서버에게 요청한 ‘데이터 유형’을 알려줍니다. 이 헤더는 클라이언트가 서버로부터 어떤 유형의 데이터를 받기를 원하는지 지정합니다.
- 예를 들어, text/html은 HTML 문서를 나타내고, application/json은 JSON 형식의 데이터를 나타냅니다.
💡 If-None-Match 헤더
- ‘캐시 된 리소스를 다시 가져오는 것을 방지’ 하기 위해 사용됩니다. 이 헤더는 이전에 클라이언트에서 가져온 리소스의 ETag 값을 서버에 전송하여, 새로운 ETag 값이 없는 경우, 서버는 304 Not Modified 응답을 반환하여 클라이언트에게 새로운 리소스를 다시 가져올 필요가 없음을 알려줍니다.
💡 If-Modified-Since 헤더
- 클라이언트가 마지막으로 리소스를 가져온 시간’을 지정합니다. 이 헤더는 클라이언트가 리소스가 수정되었는지 여부를 확인하기 위해 사용됩니다. 서버가 클라이언트가 지정한 시간 이후에 리소스를 수정한 경우, 서버는 새로운 리소스를 반환하고, 그렇지 않은 경우 304 Not Modified 응답을 반환하여 클라이언트에게 새로운 리소스를 다시 가져올 필요가 없음을 알려줍니다.
💡 [참고] MediaType 별 종류 설명
MediaType | Content Type | 설명 |
APPLICATION_JSON | application/json | JSON 형식 |
TEXT_PLAIN | text/plain | 일반 텍스트 형식 |
APPLICATION_XML | application/xml | XML 형식 |
APPLICATION_ATOM_XML | application/atom+xml | Atom 피드 형식 |
APPLICATION_FORM_URLENCODED | application/x-www-form-urlencoded | HTML 폼 형식 |
APPLICATION_OCTET_STREAM | application/octet-stream | 임의의 바이너리 데이터 |
APPLICATION_PDF | application/pdf | PDF 형식 |
APPLICATION_RSS_XML | application/rss+xml | RSS 피드 형식 |
APPLICATION_XHTML_XML | application/xhtml+xml | XHTML 형식 |
IMAGE_GIF | image/gif | GIF 이미지 형식 |
IMAGE_JPEG | image/jpeg | JPEG 이미지 형식 |
IMAGE_PNG | image/png | PNG 이미지 형식 |
MULTIPART_FORM_DATA | multipart/form-data | 여러 개의 다른 형식의 파트를 하나의 요청에 함께 전송 |
TEXT_HTML | text/html | HTML 형식 |
TEXT_XML | text/xml | XML 형식 |
4. RestTemplate Body & Request Entity 구성
💡 HTTP 요청을 보내기 위한 Request Body 설정과 Request Entity 생성하는 코드입니다.
1. JSON 형태로 객체를 생성하고 전달하려는 값을 넣습니다.
2. 생성된 객체를 toString() 과정을 통해 직렬화(Serialization) 과정을 수행합니다.
3. 직렬화된 문자열과 Header를 포함하여 HttpEntity 객체를 생성합니다.
// Request Body 설정
JSONObject requestBody = new JSONObject();
requestBody.put("key", "value");
// Request Entity 생성
HttpEntity<String> entity = new HttpEntity<String>(requestBody.toString(), headers);
5. API 호출
💡 RestTemplate을 사용하여 HTTP POST 요청을 보내는 예시입니다
1. url 변수에 API Endpoint 주소를 할당합니다.
2. restTemplate.exchange 메서드를 호출하여 HTTP POST 요청을 보냅니다.
3. entity 매개 변수는 요청 본문을 포함하고 있습니다.
4. 요청 본문과 함께 url과 HttpMethod.POST를 restTemplate.exchange 메서드의 매개 변수로 전달합니다.
5. 응답은 ResponseEntity 객체로 반환되며, 반환된 데이터는 String 타입의 response 변수에 할당됩니다.
// API 호출
String url = "<https://example.com/api>";
ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
6. API 호출 반환 값 확인
💡 해당 부분에서는 RestTemplate에서 통신을 수행한 결과값으로 Response Body 값을 반환받습니다. 동기적인 수행이기에 통신이 완료될 때까지 대기한 상태 이후 결과값을 받습니다.
// Response Body 출력
System.out.println(response.getBody());
7. 모든 과정 요약
💡 해당 RestTemplate의 경우 Spring MVC 기준으로 ‘서비스 레이어’에 등록하여 사용하는 것을 권장합니다.
💡 과정 : 객체 생성 → Header 구성 → Body 구성 → Header, Body를 하여 객체에 넣어둡니다 → API내에 데이터를 포함하여 전송합니다. → 결과값을 반환받습니다.
// RestTemplate 생성
RestTemplate restTemplate = new RestTemplate();
// Request Header 설정
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// Request Body 설정
JSONObject requestBody = new JSONObject();
requestBody.put("key", "value");
// Request Entity 생성
HttpEntity entity = new HttpEntity(requestBody.toString(), headers);
// API 호출
String url = "<https://example.com/api>";
ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
// Response Body 출력
System.out.println(response.getBody());
오늘도 감사합니다. 😀
반응형
'Java > Spring Boot' 카테고리의 다른 글
[Java] Spring Web Annotation 이해하고 사용하기 -1 : 환경 구성 (2) | 2023.11.11 |
---|---|
[Java] Spring Boot OAuth2 Client + Spring Security + JWT + Kakao 구성하기 -1 : 초기 환경 (0) | 2023.08.19 |
[Java] Spring Boot Webflux 이해하기 -2 : 활용하기 (2) | 2023.08.13 |
[Java] Spring Boot Webflux 이해하기 -1 : 흐름 및 주요 특징 이해 (3) | 2023.08.09 |
[Java] Spring Boot OAuth 2 Client 이해하기 -2: Security 없이 카카오 로그인 구성 (8) | 2023.07.16 |