티스토리 뷰
안녕하세요! 이번 글에서는 RestTemplate 이란 무엇인지, 그리고 RestTemplate을 사용하는 방법에 대해 기술해보고자 합니다.
Rest Template 은
Spring 에서 제공하는 http 통신 템플릿이고, http 서버와의 통신을 단순화하기 위해 개발되었습니다. Spring 3.0 버전 이상부터 사용이 가능하며, RESTful 원칙을 지키고 이전에 문자열로 많이 나누어져 있던 통신 방식을 깔끔하게 정리할 수 있는 유용한 템플릿입니다.
-> 다시 말해 Spring 에서 사용이 가능한 Java 전용 라이브러리라고 생각해주시면 됩니다.
원시적인 코드와 비교하기
URLConnection
JDK 1.2 버전부터 포함되어 있어 오랫동안 사용했습니다. 보통 new URL("http://domain") 으로 사용하여 openConnection 함수를 통해 서버와의 통신망을 열어둔 후 I/O Stream (InputStream, OutputStream) 또는 BufferReader으로 데이터를 주고 받습니다.
소스 코드 (Get 요청인 경우)
URL url = new URL(urlStr);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setDoInput(true);
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
String json = objectMapper.writeValueAsString(req);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
os.write(bytes);
} catch (Exception e) {
e.printStackTrace();
}
con.connect();
if (con.getResponseCode() >= 500) {
throw new ServiceUnavailableException();
}
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(),
StandardCharsets.UTF_8));
String line = "";
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
br.close();
return sb.toString();
소스 코드(Post의 경우)
RL url = new URL(urlStr);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setRequestProperty("Content-Type", "application/json");
con.setRequestProperty("Accept", "application/json");
con.setDoInput(true);
con.setDoOutput(true);
try (OutputStream os = con.getOutputStream()) {
String json = objectMapper.writeValueAsString(req);
byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
os.write(bytes);
} catch (Exception e) {
e.printStackTrace();
}
con.connect();
if (con.getResponseCode() >= 500) {
throw new ServiceUnavailableException();
}
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(),
StandardCharsets.UTF_8));
String line = "";
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line).append("\n");
}
br.close();
return sb.toString();
하지만 이 부분에서의 단점은 HttpStatus.OK = 200 코드가 돌아오면 다행이지만, 서버의 상태가 원활하지 못해 클라이언트의 에러인 4xx, 요청 서버의 에러인 5xx 코드가 발생할 경우 통신이 어렵다는 단점이 있습니다.
HttpClient
Apache 재단에서 지원하는 라이브러리로 Maven 3.0 이상의 버전부터 사용할 수 있습니다. Maven Dependency에 아래와 같이 추가를 해주시거나 해당 링크로 들어가셔서 적용하셔도 됩니다.
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
사용 방법
final CloseableHttpClient client = HttpClients.createDefault();
final HttpGet httpGet = new HttpGet("http://domain.kr");
final CloseableHttpResponse execute = client.execute(httpGet);
final HttpEntity entity = execute.getEntity();
final InputStream content = entity.getContent();
물론 이전의 HttpURLConnection을 사용하였을 때보다 코드의 양이 많이 줄었지만 그래도 반복적으로 사용하는 코드가 있습니다. 또 대조되는 점으로는 타임아웃 설정과 쿠키 제어가 가능하다는 장점이 있습니다.
그럼 본격적으로 RestTemplate
RestTemplate은 사용 방법이 정말 간단합니다. org.springframework.http.client 패키지에 존재하고 HttpClient을 추상화하여 제공해주는 라이브러리이기 때문에 어떻게 보면 Apache HttpComponents를 사용한다고 볼 수 있습니다.
저는 HttpMethod 별로 사용 방법을 좀 나누어서 사용을 하곤 합니다. 그래서 이번 글에 기술할 내용은 GET, POST를 중심으로 작성해보려 합니다.
1의 방법은 GET 요청시, RequestParam 을 사용하여 표현하는 방법입니다. "http://domain.kr?key1=value1&key2=value2"와 같은 형태입니다.
try {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("accept", MediaType.APPLICATION_JSON_VALUE); // json 형태의 Response 를 받습니다.
HttpEntity<?> entity = new HttpEntity<>(headers);
UriComponentsBuilder builder = UriComponentsBuilder.fromUri(
URI.create(urlStr)
).queryParam("key1", key1)
.queryParam("key2", key2);
final ResponseEntity<ResponseDTO> response = restTemplate.exchange(builder.toUriString(), // uri
HttpMethod.GET, // request method
entity, // http entity
ResponseDTO.class); // 리턴받을 ResponseDTO 클래스
if(response.getStatusCode() == 200) {
return response.getBody();
} else {
throw new Exception();
}
} catch(Exception e) {
e.printStackTrace();
return null;
}
또는 아래와 같은 형태로도 가능합니다.
restTemplate.exchange("http://domain.kr/?key1={key1}&key2={key2},
HttpMethod.GET,
entity,
ResponseDTO.class,
"value1",
"value2"
);
파라미터로 Map을 사용하는 분도 있어 그러한 케이스도 같이 올려볼까 합니다.
Map<String, String> params = Map.of("key1", "value1",
"key2", "value2");
restTemplate.getForObject("http://domain.kr?key1={key1}&key2={key2},
ResponseDTO.class,
params);
2의 방법은 POST 요청시, RequestBody인 경우를 적용해보려 합니다. 여기서 주의할 점은 RestTemplate에 파라미터로 기본 Map을 받을 수 없으므로 MultiValueMap을 사용해야 한다는 점입니다.
try {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.set("accept", MediaType.APPLICATION_JSON_VALUE); // request body 형태의 Request 를 받습니다.
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("key1", value1);
params.add("key2", value2);
HttpEntity<MultiValueMap> entity = new HttpEntity<>(params, headers);
final ResponseEntity<ResponseDTO> response = restTemplate.postForEntity(URL,
entity, // http entity
ResponseDTO.class); // 리턴받을 ResponseDTO 클래스
if(response.getStatusCode() == 200) {
return response.getBody();
} else {
throw new Exception();
}
} catch(Exception e) {
e.printStackTrace();
return null;
}
그 다음으로 FormData로 요청시는 headers.set 부분만 변경을 해주시면 됩니다.
headers.set("accept", MediaType.APPLICATION_FORM_URLENCODED_VALUE);
이번 글에서는 간단히 RestTemplate 를 사용하여 다른 서버의 API와 통신하는 방법에 대해 설명드렸는데요, 생각보다 RestTemplate의 소스 코드 양이 많아 내용이 좀 길어지게 되었네요. 유용하게 사용하시기 바랍니다!
'Server' 카테고리의 다른 글
Ktor 프레임워크 공부하기 (1) | 2022.03.12 |
---|---|
지금 봐도 괜찮은 배달의민족 도메인 설계 (1) | 2022.03.06 |
[Java] JPA Detached Entity passed to persist 에러 해결 로그 (2) | 2022.02.14 |
[Java] Encode, Decode 함수 사용하기 (4) | 2022.02.04 |
특정 잡만 수행하고 싶을 때 (1) | 2022.01.10 |
Job & Step 병렬 처리 하기 (2) | 2022.01.05 |