RestTemplate 이란?
npm 의 axios 처럼 외부 api와 http rest 서버 통신을 하게 해주는 라이브러리
스프링은 REST 서비스에서 endpoint (API가 서버에서 리소스에 접근할 수 있도록 가능하게 하는 URL)를 호출하는 2가지 방법이 제공하는데, 바로 RestTemplate 과 WebClient 이다. 일단 기존에 많이 사용되던 RestTemplate 은 Spring 5.0부터는 deprecated 될 예정이므로 스프링에서는 WebClient 사용을 권장하고 있다.
RestTemplate 은 api 요청을 하게 되면 한 api 의 요청에 대한 응답이 올 때까지 기다리는 동기 방식이다. 반대로 비동기 방식에는 WebClient 가 있다. WebClient 를 사용하기 위해서는 webflux 와 mono 를 익혀야 한다. 근데 이게 어렵다. 그래서 웹 클라이언트를 사용하려다 도저히 안되어 RestTemplate으로 바꿨다.
RestTemplate으로 POST 사용하기
설정 (gradle 기준)
따로 해줄건 없다.
전반적 과정
1. RestTemplate 사용을 위해 설정을 해준다.
2. 설정해준것을 불러온다음 불러온 restTemplate에 양식에 맞추어 헤더와 바디를 만든다.
3. 사용해준다.
1. RestTemplate 설정
Bean 은 사용자가 직접만든 component가 아닌 경우 붙여준다. 그리고 Configuration 어노테이션이 필요하다.
레스트 템플릿을 사용하기 위해 아래와 같이 선언해준다. ( 그냥 아래처럼 선언해야 쓸수 있다고 생각하고 복잡하게 생각하지 말 것)
package com.example.demo;
import org.springframework.boot.web.client.*;
import org.springframework.context.annotation.*;
import org.springframework.http.client.*;
import org.springframework.http.converter.*;
import org.springframework.web.client.*;
import java.nio.charset.*;
import java.time.*;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
.setConnectTimeout(Duration.ofMillis(5000)) // connection-timeout
.setReadTimeout(Duration.ofMillis(5000)) // read-timeout
.additionalMessageConverters(new StringHttpMessageConverter(Charset.forName("UTF-8")))
.rootUri(String.format("https://api-alimtalk.cloud.toast.com"))
.errorHandler(new RestTemplateResponseErrorHandler())
.build();
}
}
설명
아래 코드는 시간을 주는건데 아마 api 호출할때 시간을 주는 것 같은데 이유가 있지만 로직에 큰 영향은 안미치는것 같다. 지워보고 작동이 안되면 넣어보도록한다.
.setConnectTimeout(Duration.ofMillis(5000)) // connection-timeout
.setReadTimeout(Duration.ofMillis(5000)) // read-timeout
UTF-8 로 맞춰줄것이므로
Charset.forName("UTF-8")
내가 호출할 외부 api BaseUrl
.rootUri(String.format("https://api-alimtalk.cloud.toast.com"))
에러 처리해줄 에러 핸들러도 받아주자(안해줘도 되는데 이럼 작동이 안될경우 이유 파악이 안된다. system out print로 하는법이 있긴한데 무언가 개발자 답지 않다 이후에 이것도 설명해줌)
.errorHandler(new RestTemplateResponseErrorHandler())
2. 에러 핸들러 설정
아래와 같이 설정해준다.
404 와 500 에러가 났을때 화면으로 에러 메시지를 받아줄 거다.
package com.example.demo;
import org.springframework.http.*;
import org.springframework.http.client.*;
import org.springframework.web.client.*;
import java.io.*;
public class RestTemplateResponseErrorHandler implements ResponseErrorHandler {
@Override
public boolean hasError(ClientHttpResponse response) throws IOException {
return response.getStatusCode() == HttpStatus.BAD_REQUEST
|| response.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR;
}
@Override
public void handleError(ClientHttpResponse response) throws IOException {
}
}
3. 사용하기
@RestController
public class AlimController {
//레스트 템플릿 선언해주기
private final RestTemplate restTemplate;
public AlimController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public JSONObject createRequestBody() throws MalformedURLException {
JSONObject jsonObject = new JSONObject();
JSONArray recipientList = new JSONArray();
JSONObject recipient = new JSONObject();
JSONObject templateParameter = new JSONObject();
recipient.put("recipientNo","01040202153");
templateParameter.put("name","김아무개");
templateParameter.put("url","https:github.com/");
recipient.put("templateParameter",templateParameter);
jsonObject.put("senderKey","보내는사람키");
jsonObject.put("templateCode","alimMessage");
recipientList.add(recipient);
jsonObject.put("recipientList",recipientList);
return jsonObject;
}
@GetMapping("alimTalk")
public ResponseEntity<String> alimTalk() throws JsonProcessingException, MalformedURLException {
String url = "baseUrl 에 붙여줄 추가 주소(없어도 무방)";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application","json", Charset.forName("UTF-8")));
headers.setAccept(Arrays.asList(new MediaType[] { MediaType.APPLICATION_JSON }));
// 3. 헤더 설정 : Key, Value 쌍으로 설정
headers.set("X-Secret-Key", "시크릿 키");
JSONObject body = createRequestBody();
ResponseEntity<String> response = restTemplate.exchange(
url, HttpMethod.POST, new HttpEntity<>(body,headers), String.class);
// 오류 코드를 로그에서 볼 수 있게하기 ( 에러 핸들링 해줬으면 상관없다.)
System.out.println("status : " + response.getStatusCode());
System.out.println("body : " + response.getBody());
return response;
}
}
조금 길지만 별거 아니다 하나씩 보도록 하자.
POST 에 넣어줄 JSON 객체 생성
createRequestBody로 내가 담고 싶은 JSON 객체를 담아주었다.
그러기 위해선 이게 필요하다.
implementation group: 'com.googlecode.json-simple',name:'json-simple',version:'1.1.1'
아래와 같은 JSON 값을 만들어준 거다. ( 각자 보낼 JSON 값이 다르니 그냥 어떻게 넣었는지만 보면된다.)
const data = {
senderKey: '보내는사람 키',
templateCode: '템플릿코드',
recipientList: [
{
recipientNo: '전화번호',
templateParameter: { name: '이름', url: 'https://github.com/' },
},
],
};
그 다음 컨트롤러의 반환값을 리스폰스엔터티로 해주고 통신해줄 헤더를 만들어준다.
헤더에서 미디어 타입을 알려줘여하므로 밝혀주고
그리고 헤더에 원하는 값을 담는다.
나는 시크릿키를 헤더로 보내줘야 승인이 되기때문에 담아주었다.
아래는 위 긴 코드 일부를 보기 쉽게 때온 것이다.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(new MediaType("application","json", Charset.forName("UTF-8")));
headers.setAccept(Arrays.asList(new MediaType[] { MediaType.APPLICATION_JSON }));
// 3. 헤더 설정 : Key, Value 쌍으로 설정
headers.set("X-Secret-Key", "시크릿 키");
아까 만들어준 JSON 객체를 body 로 만들어준 후
restTemplate의 exchange 메소드에 담는다.
exchnage 메소드에 뭐가 있는지 한번 직접 클릭해보면 더 정보가 많다.
JSONObject body = createRequestBody();
ResponseEntity<String> response = restTemplate.exchange(
url, HttpMethod.POST, new HttpEntity<>(body,headers), String.class);
exchange(원하는 api url, rest 방식, httpEntiy(바디,헤더정보), return할 타입)
이렇게 해주면 된다.
Tip
GET으로 api 에서 정보를 가져와 담을 것이라면 POST 가 아닌 GET 이 될 것이고 이때는 String 이 아니라 Map.class로 받아서 키와 밸류를 하나씩 저장해 데이터베이스에 담아주면 된다.
참고 블로그
댓글