RestTemplate이란
스프링에서 제공하는 http 통신에 유용하게 쓸 수 있는 템플릿
Spring 3부터 지원 되었고 REST API 호출이후 응답을 받을 때까지 기다리는 동기방식이다
AsyncRestTemplate
Spring 4에 추가된 비동기 RestTemplate이다
Spring 5.0에서는 deprecated 되었다
메소드
메서드 |
HTTP |
설명 |
getForObject |
GET |
주어진 URL 주소로 HTTP GET 메서드로 객체로 결과를 반환받는다 |
getForEntity |
GET |
주어진 URL 주소로 HTTP GET 메서드로 결과는 ResponseEntity로 반환받는다 |
postForLocation |
POST |
POST 요청을 보내고 결과로 헤더에 저장된 URI를 결과로 반환받는다 |
postForObject |
POST |
POST 요청을 보내고 객체로 결과를 반환받는다 |
postForEntity |
POST |
POST 요청을 보내고 결과로 ResponseEntity로 반환받는다 |
delete |
DELETE |
주어진 URL 주소로 HTTP DELETE 메서드를 실행한다 |
headForHeaders |
HEADER |
헤더의 모든 정보를 얻을 수 있으면 HTTP HEAD 메서드를 사용한다 |
put |
PUT |
주어진 URL 주소로 HTTP PUT 메서드를 실행한다 |
patchForObject |
PATCH |
주어진 URL 주소로 HTTP PATCH 메서드를 실행한다 |
optionsForAllow |
OPTIONS |
주어진 URL 주소에서 지원하는 HTTP 메서드를 조회한다 |
exchange |
any |
HTTP 헤더를 새로 만들 수 있고 어떤 HTTP 메서드도 사용가능하다 |
execute |
any |
Request/Response 콜백을 수정할 수 있다 |
GET 메소드
getForObject()
Employee employee = restTemplate.getForObject(BASE_URL + "/{id}", Employee.class);
Employee 로의 매핑은 jackson-databind 가 기본적으로 담당하고 있다.
getForEntity()
응답을 ResponseEntity 객체로 받는다. getForObject()와 달리 HTTP 응답에 대한 추가 정보를 담고 있어서 GET 요청에 대한 응답 코드, 실제 데이터를 확인할 수 있다. 또한 ResponseEntity<T> 제네릭 타입에 따라서 응답을 String이나 Object 객체로 받을 수 있다.
ResponseEntity<String> responseEntity = restTemplate.getForEntity(BASE_URL + "/{id}", String.class, 25);
log.info("statusCode: {}", responseEntity.getStatusCode());
log.info("getBody: {}", responseEntity.getBody());
getForEntity()에 여러 값을 담은 params을 같이 넘겨주기
LinkedMultiValueMap 객체에 담아서 params로 넘겨줄 수 있다.
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("name", "Frank Oh");
params.add("country", "US");
ResponseEntity<Employee> responseEntity = restTemplate.getForEntity(BASE_URL + "/{name}/{country}", Employee.class, params);
log.info("statusCode: {}", responseEntity.getStatusCode());
log.info("getBody: {}", responseEntity.getBody());
get 요청에 header 값이 필요한 경우
get 메소드에서는 header 를 추가 할 수 가 없다.
exchange 메소드를 사용해야 한다.
HttpHeaders headers = new HttpHeaders();
headers.set("header", header);
headers.set("header2", header2);
HttpEntity request = new HttpEntity(headers);
ResponseEntity<String> response = restTemplate.exchange(
URL_PATH,
HttpMethod.GET,
request,
String.class
);
get 요청에 header 값 과 쿼리스트링(query String, param)이 필요한 경우
post 처럼 HttpEntity 에 넣어서 요청할 수가 없다.
HttpHeaders headers = new HttpHeaders();
headers.set("header", header);
headers.set("header2", header2);
HttpEntity request = new HttpEntity(headers);
//adding the query params to the URL
UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(URL_PATH)
.queryParam("keywords", "11");
.queryParam("name", "22");
ResponseEntity<String> response = restTemplate.exchange(
uriBuilder.toUriString(),
HttpMethod.GET,
request,
String.class
);
이렇게 UrlBuilder 를 사용해서 넣는 수 밖에 없다. post 방식과 달리 httpEntity 에 같이 넣거나 exchange 의 parameter 로 넘길 수가 없다.
사실 굳이 uriBuilder 를 써야 되나 싶기도 하다. 그냥 map 에 파라미터를 추가하고 map 을 parameter 로 변환해주는 메소드만 만들어서 사용하면 편할거 같다.
...
HttpHeaders headers = new HttpHeaders();
headers.set("header", header);
headers.set("header2", header2);
HttpEntity request = new HttpEntity(headers);
Map<String, String> params = new HashMap<String, String>();
params.put("query1", "test");
params.put("query2", "test2");
ResponseEntity<String> response = restTemplate.exchange(
URL_PATH + "?" + this.mapToUrlParam(params),
HttpMethod.GET,
request,
String.class
);
...
// 위에서 사용하려고 만든 util 메소드
private static String mapToUrlParam(Map<String, Object> params) {
StringBuffer paramData = new StringBuffer();
for (Map.Entry<String, Object> param : params.entrySet()) {
if (paramData.length() != 0) {
paramData.append('&');
}
paramData.append(param.getKey());
paramData.append('=');
paramData.append(String.valueOf(param.getValue()));
}
return paramData.toString();
}
사실 굳이 uriBuilder 를 써야 되나 싶기도 하다.
단순하게 map 에 파라미터를 추가하고 map 을 parameter 문자열로 변환해주는 메소드만 만들어서 사용하면 편할거 같다.
postForObject() 메소드 header 값 없는 경우
Employee newEmployee = Employee.builder()
.name("Frank")
.address(Address.builder()
.country("US")
.build())
.build();
Employee employee = restTemplate.postForObject(BASE_URL + "/employee", newEmployee, Employee.class);
postForObject() 메소드 header 포함해서 보내기
Employee newEmployee = Employee.builder()
.name("Frank")
.address(Address.builder()
.country("US")
.build())
.build();
HttpHeaders headers = new HttpHeaders();
headers.set("headerTest", "headerValue");
HttpEntity<Employee> request = new HttpEntity<>(newEmployee, headers);
Employee employee = restTemplate.postForObject(BASE_URL + "/employee", request, Employee.class);
postForEntity
getForEntity 와 동일해서 생략
post form data 사용
// 헤더 설정
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// 파라미터 세팅
MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
map.add("id", "1");
// 요청 세팅 완료
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
// 실제 요청부
ResponseEntity<String> response = restTemplate.postForEntity(fooResourceUrl+"/form", request , String.class);
Timeout 설정하기
timeout 을 설정하려면 ClientHttpRequestFactory 와 같은 팩토리 메소드를 만들고 RestTemplate 의 생성자에 추가해야 한다.
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 5000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory
= new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
return clientHttpRequestFactory;
}
참고사항으로 timeout 이 0 이면 무제한설정이다. (infinite timeout)
Execute()
Execute()는 콜백을 통해 요청 준비와 응답 추출을 완벽하게 제어하여 요청을 수행하는 가장 일반적인 메서드를 RestTemplate에서 제공한다.
getForObject(), postForeObject() 등은 excute() 를 내부적으로 호출한다.
connection pool 적용
RestTemplate 은 기본적으로 connection pool 을 사용하지 않는다. 따라서 연결할 때 마다, 로컬 포트를 열고 tcp connection 을 맺는다. 이때 문제는 close() 이후에 사용된 소켓은 TIME_WAIT 상태가 되는데, 요청량이 많다면 이런 소켓들을 재사용하지 못하고 소켓이 오링나서 응답이 지연될 것이다.
참고문헌
www.baeldung.com/rest-template [샘플 문서]
stackoverflow.com/questions/31869193/using-spring-rest-template-either-creating-too-many-connections-or-slow/ [커넥션 많을 경우 pool 관리
'Spring > spring boot 및 기타' 카테고리의 다른 글
[spring] 스프링 elasticsearch NativeSearchQuery 사용방법 (0) | 2021.03.16 |
---|---|
[spring] 스프링 elasticsearch ElasticsearchRepository underscore 오류 해결방법 (0) | 2021.03.16 |
[spring boot] 스프링부트 에서 elasticsearch 시작하기 (1) | 2021.02.24 |
Jasypt 암호화 - spring 설정파일 암호화하기 (0) | 2021.01.28 |
spring boot 1.X 와 2.X 차이점 (0) | 2021.01.08 |