반응형

스프링에서 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. 5ref. 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

  1. RestTemplate (Spring Framework 4.1.3.RELEASE API)
  2. http://spring.io/guides/gs/consuming-rest/#initial
  3. http://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
  4. android - How to send a getForObject request with parameters Spring MVC - Stack Overflow
  5. java - Spring RestTemplate postForObject with Header: webservice can't find my header parameters - Stack Overflow
  6. Sending POST parameters with RestTemplate requests - Spring Forum
  7. Rest Template Json Request | Spring Tutorials


반응형
,