03. RestTemplate
- -
RestTemplate
가끔 REST API를 자바 영역에서 사용해야 할 경우가 있다. ajax로 처리해야 하는데 서비스를 제공하는 서버에서 cross origin에서의 접근을 허용하지 않는 경우가 대표적이다. 이런 경우는 자바 영역에서 일반 요청 형태로 REST 서비스를 호출해서 정보를 받고 이를 다시 ajax로 얻어와야 한다.
자바 영역에서 REST 서비스를 편리하게 사용하기 위해 RestTemplate을 사용할 수 있다.
빈 등록
RestTemplate은 스프링에서 제공해주는 기본 템플릿이다. 이를 사용하기 위해서는 아래와 같이 빈을 생성해 볼 수 있다.
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
추가로 RestTemplate을 사용할 때 연결 시간, 읽기 시간에 대한 설정을 설정하기 위해 httpcomponents의 httpclient에 대한 의존관계가 필요하다.
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
httpclient를 이용하면 아래와 같이 빈을 구성할 수 있다.
@Bean
public RestTemplate restTemplate() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(5000); // 읽기시간초과, ms
factory.setConnectTimeout(3000); // 연결시간초과, ms
return new RestTemplate(factory);
}
RestTemplate는 다음과 같은 메서드들을 제공한다.
메서드 명 | 설명 |
XXXForObject | http method 인 XXX(get/post)를 통해서 객체를 반환 받는다. |
XXXForEntity | http method인 XXX(get/post)를 통해 ResponseEntity를 반환 받는다. |
put | put method에 대한 요청을 처리하고 void를 반환한다. |
delete | delete method에 대한 요청을 처리하고 void를 반환한다. |
exchange | 주어지는 URI 템플릿을 주어진 http method에 기반해서 수행하고 ResponseEntity 형태로 반환한다. |
활용 예
UriComponents
호출하려는 서버의 경로를 생성할 때는 UriComponents를 사용하는 것이 편리하다.
UriComponents comp = UriComponentsBuilder
.newInstance()
.scheme("http")
.host("quietjun.asuscomm.com")
.port(8080)
.path("/users")
.queryParam("age", 30) // 추가적인 파라미터 전달
.encode() // URL에 대한 encoding 처리(한글 전달 시)
.build();
물론 문자열로 그냥 처리할 수도 있다. 이 경우 uriVariable 형태로 전달받는 파라미터를 설정할 수 있다.
// uri variable을 이용한 문자열 형태의 url 작성
String url = "http://quietjun.asuscomm.com:8080/users?age={age}";
// uri variable 전달 예
return rt.getForEntity(url, Map.class, Map.of("age",30));
get mapping 처리
정보 조회를 위한 get mapping의 처리 예를 살펴보자.
@GetMapping("/{id}")
public User select(@PathVariable String id)
throws RestClientException, URISyntaxException, UnsupportedEncodingException {
UriComponents comp = UriComponentsBuilder.newInstance()
.scheme("http")
.host("quietjun.com")
.port(8080)
.path("/users/" + id)
.encode() // 한글 id 처리
.build();
User data = rest.getForObject(comp.toUri(), User.class);
return data;
}
UriComponents 구성 시 id가 한글인 경우가 있어서 encode 처리해준 점을 확인하자.
post mapping 처리
다음은 정보 추가를 위한 post mapping의 처리 예이다.
@PostMapping
public Integer insert(@RequestBody User user) throws RestClientException, URISyntaxException {
UriComponents comp2 = UriComponentsBuilder.newInstance()
.scheme("http")
.host("quietjun.com")
.port(8080)
.path("/users")
.build();
// @RequestBody로 전달될 데이터를 user로 넘겨준다.
Integer data = rest.postForObject(comp2.toUri(), user, Integer.class);
return data;
}
또는 ResponseEntity를 사용하려는 경우 아래와 같이 처리할 수 있다.
@PostMapping
public ResponseEntity<Integer> insert2(@RequestBody User user) throws RestClientException, URISyntaxException {
UriComponents comp2 = UriComponentsBuilder.newInstance()
.scheme("http")
.host("quietjun.com")
.port(8080)
.path("/users")
.build();
ResponseEntity<Integer> res = rest.postForEntity(comp2.toUri(), user, Integer.class);
return res;
}
put mapping 처리
put mapping을 처리하기 위한 put method는 void를 반환하기 때문에 ajax client에게 원격지 서버에서 전달한 값을 전달해 주기가 어렵다. 다음은 단지 예외가 발생하지 않았을 경우 성공의 의미로 true를 반환하도록 처리한 예이다.
@PutMapping("/{id}")
public Boolean update(@PathVariable String id, @RequestBody User user)
throws RestClientException, URISyntaxException {
UriComponents comp2 = UriComponentsBuilder.newInstance()
.scheme("http")
.host("quietjun.com")
.port(8080)
.path("/users/" + id)
.build();
// put method는 void를 반환한다.
rest.put(comp2.toUri(), user);
return true;
}
원격지 서버가 반환한 값을 ajax client에게 반환하기 위해서는 exchange 메서드를 사용한다.
@PutMapping("/{id}")
public ResponseEntity<String> update(@PathVariable String id, @RequestBody User user)
throws RestClientException, URISyntaxException {
UriComponents comp2 = UriComponentsBuilder.newInstance()
.scheme("http")
.host("quietjun.com")
.port(8080)
.path("/users/" + id)
.build();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 전송할 데이터를 header를 통해서 전달한다.
HttpEntity<User> entity = new HttpEntity<>(user, headers);
ResponseEntity<String> response
= rest.exchange(comp2.toUriString(), HttpMethod.PUT, entity, String.class, id);
logger.debug("원격지 서버가 반환한 값: {}", response.getBody());
return response;
}
delete mapping 처리
delete mapping을 처리하는 delete 메서드도 put과 마찬가지로 void를 반환한다. 추가적인 정보의 전달을 위해서는 exchange를 사용한다.
@DeleteMapping("/{id}")
public ResponseEntity<String> delete(@PathVariable String id) throws RestClientException, URISyntaxException {
UriComponents comp2 = UriComponentsBuilder.newInstance()
.scheme("http")
.host("quietjun.com")
.port(8080)
.path("/users/" + id)
.encode()
.build();
// void를 반환한다.
// rest.delete(comp2.toUriString());
ResponseEntity<String> response = rest.exchange(comp2.toUri(), HttpMethod.DELETE, null, String.class);
return response;
}
data.go.kr 사용 시 주의사항
마지막으로 data.go.kr을 사용할 때 주의 사항을 알아보자. data.go.kr을 사용할 때는 대부분 Service Key를 사용하는데 encoding 과 decoding을 준다.
UrlComponentBuilder의 build 메서드는 파라미터로 boolean encoded를 받는데 true인 상태는 encoding 키를 넘겨줘야 하고 false인 경우는 decoding 키를 넘겨줘야 한다. 파라미터를 받지 않는 build는 encoded가 false인 상태이므로 decoding을 전달한다.
@GetMapping("/aptdeal")
public Object getAptDealInfo(@RequestParam Map<String, String> param)
throws UnsupportedEncodingException, URISyntaxException {
UriComponents comp = UriComponentsBuilder.newInstance()
.scheme("http")
.host("openapi.molit.go.kr")
.port(80)
.path("/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTradeDev")
.queryParam("ServiceKey","encoding 서비스키등록")
.queryParam("pageNo", "1")
.queryParam("numOfRows", "10")
.queryParam("LAWD_CD", param.get("LAWD_CD"))
.queryParam("DEAL_YMD", param.get("DEAL_YMD"))
// data.go.kr의 service 키는 이미 encoding 되어있는 값이다.
.build(true);
ResponseEntity<Map> result = rest.getForEntity(comp.toUri(), Map.class);
return result;
}
문자열 형태로 그냥 URL을 작성할 때는 Decoding 값을 활용한다.
@GetMapping("/apt")
public ResponseEntity<?> apt() {
String serviceKey = "일반인증키(Decoding)";
String url = "http://openapi.molit.go.kr/OpenAPI_ToolInstallPackage/service/rest/RTMSOBJSvc/getRTMSDataSvcAptTradeDev?type=json&serviceKey={serviceKey}&pageNo={pageNo}&numOfRows={numOfRows}&LAWD_CD={LAWD_CD}&DEAL_YMD={DEAL_YMD}";
return rt.getForEntity(url, Map.class, Map.of("LAWD_CD", "11110",
"DEAL_YMD", "201512",
"pageNo", "1",
"numOfRows", "10",
"serviceKey", serviceKey));
}
'Spring MVC > 04.Rest' 카테고리의 다른 글
[swagger]swagger와 interceptor (0) | 2021.12.09 |
---|---|
[springboot]CORS 설정 (0) | 2021.09.08 |
[spring boot]MockMVC 테스트시 response content의 한글 깨짐 (0) | 2021.08.30 |
02. REST를 위한 단위 테스트 (0) | 2020.07.13 |
01.Rest (0) | 2020.07.10 |
소중한 공감 감사합니다