스프링에서 rest api call 하기 / spring 에서 rest call / spring 에서 http request
RestTemplate
Spring framework 에서 Rest API 호출을 위해 RestTemplate 이라는 것을 제공한다. ref. 2, ref. 3 에서 간단한 예제를 확인할 수 있다.
postForObject
Server 에서 RESTful API server 에 request 를 POST 방식으로 form 의 data 는 json 형식으로 보낼 때 방법. ElasticSearch 등을 사용할 때 활용할 수 있다. 혹시나 해서 적어놓는데, ElasticSearch 는 Java API 를 따로 제공한다.(참고)
@Override
public JsonResult retrieve() {
String JSONInput = ("{\n" +
" \"aggs\": {\n" +
" \"aggs_stats\" : {\n" +
" \"date_histogram\":{\n" +
" \"field\" : \"event_timestamp\",\n" +
" \"interval\" : \"hour\"\n" +
" }\n" +
" }\n" +
" }\n" +
"} ");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity param= new HttpEntity(JSONInput, headers);
RestTemplate restTemplate = new RestTemplate();
String result = restTemplate.postForObject(url, param, String.class);
return new ElasticSearchResult(result);
}
setMessageConverters
ref. 5, ref. 6 을 통해서 MessageConverters 를 설정해서 postForObject 를 이용하는 방법을 알아볼 수 있다.
// RestTemplate 에 MessageConverter 세팅
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new FormHttpMessageConverter());
converters.add(new StringHttpMessageConverter());
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(converters);
// parameter 세팅
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("name", "xx");
map.add("password", "xx");
// post
String result = rest.postForObject("http://localhost:8080/soa-server/user/", map, String.class);
System.out.println(result);
getForObject 의 한계
Accept 를 따로 정해주지 않는 경우에 RestTemplate#getForObject 에서는 기본적으로 아래 header 를 이용한다.
Accept : application/json, application/*+json
그래서 getForObject 를 이용해서 만약에 다른 Accept 를 사용하고 싶다면, 다른 함수를 이용해야 한다.(execute, exchange)
getForObject 에서 param 을 주는 방법
ref. 4 를 참고하자. 대략 아래와 같은 방식을 이용한다.
UriComponentsBuilder urlWithoutParam
= UriComponentsBuilder.fromUriString("http://dd.net")
.path("/path1/ddd");
for(Map.Entry<String, Object> e: param.entrySet()){
urlWithoutParam = urlWithoutParam.queryParam(e.getKey(), e.getValue());
}
URI reqUrl = urlWithoutParam.build().toUri();
RestTemplate restTemplate = new RestTemplate();
return restTemplate.getForObject(reqUrl, String.class);
RestTemplate#execute
좀 더 자유로운 Http request 를 위해서 execute 를 사용하게 되었다. 그리고 이 RestTemplate 의 doExecute 에서 Extractor 를 사용하기 때문에 이 녀석만 제대로 맞춰 주면 된다.
protected <T> T doExecute(URI url, HttpMethod method,
RequestCallback requestCallback,
ResponseExtractor<T> responseExtractor)
throws RestClientException {
try {
ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null) {
requestCallback.doWithRequest(request);
}
response = request.execute();
if (!getErrorHandler().hasError(response)) {
logResponseStatus(method, url, response);
}
else {
handleResponseError(method, url, response);
}
if (responseExtractor != null) {
return responseExtractor.extractData(response);
}
Example
// ApiCallResponseExtractor.java
public class ApiCallResponseExtractor extends HttpMessageConverterExtractor<String> {
public ApiCallResponseExtractor (Class<String> responseType,
List<HttpMessageConverter<?>> messageConverters) {
super(responseType, messageConverters);
}
@Override
public String extractData(ClientHttpResponse response) throws IOException {
String result;
if (response.getStatusCode() == HttpStatus.OK) {
Scanner scanner = new java.util.Scanner(response.getBody()).useDelimiter("[\\(\\)]");
scanner.next(); // callback name,
String json = scanner.next();
result = json;
} else {
result = null;
}
return result;
}
}
// MyController.java
final String url = "http://10.10.2.100:8080/portal/customer/getCustomerList?" +
JsonKey.CALLBACK + "={" + JsonKey.CALLBACK + "}" + "&" +
JsonKey.USER_ID + "={" + JsonKey.USER_ID + "}";
Map<String, String> vars = new HashMap<String, String>();
vars.put(JsonKey.CALLBACK, JsonKey.API_CALLBACK_NAME);
vars.put(JsonKey.USER_ID, "test_id");
RestTemplate restTemplate = new RestTemplate();
ResponseExtractor<String> responseExtractor =
new ApiCallResponseExtractor(String.class, restTemplate.getMessageConverters());
String response = restTemplate.execute(url, HttpMethod.GET, null, responseExtractor, vars);
Header field Accept
참고로 execute 를 사용하면 기본 Accept 는 아래를 사용하게 된다.
Accept : text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
RestTemplate 을 이용해서 json request
ref. 7 에 잘 나와 있다.
Reference
- RestTemplate (Spring Framework 4.1.3.RELEASE API)
- http://spring.io/guides/gs/consuming-rest/#initial
- http://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
- android - How to send a getForObject request with parameters Spring MVC - Stack Overflow
- java - Spring RestTemplate postForObject with Header: webservice can't find my header parameters - Stack Overflow
- Sending POST parameters with RestTemplate requests - Spring Forum
- Rest Template Json Request | Spring Tutorials