본문 바로가기
Study/Spring

[스프링] RestTemplate

by 오늘만 사는 여자 2022. 11. 1.
728x90
반응형

스프링 RestTemplate

- RestTemplate란? 

- RestTemplate의 특징

- RestTemplate 동작 원리

- API 호출 클래스 종류

- 지원 메서드

- RestTemplate 사용 방법

· RestTemplate 사용 예시

· 요청 URI 설정 방법

· Body 만들기

· Header 만들기

· Get 방식 예시

· POST 방식 예시

 

 

 

RestTemplate란?

Spring에서 지원하는 객체로 간편하게 Rest 방식 API를 호출할 수 있는 Spring 내장 클래스입니다.

Spring 3.0부터 지원되었고, json, xml 응답을 모두 받을 수 있습니다.

Rest API 서비스를 요청 후 응답 받을 수 있도록 설계되어있으며 HTTP 프로토콜의 메소드(ex. GET, POST, DELETE, PUT)들에 적합한 여러 메소드들을 제공합니다.

※ Spring Framework 5부터는 WebFlux 스택과 함께 Spring은 WebClient 라는 새로운 HTTP 클라이언트를 도입하여 기존의 동기식 API를 제공할 뿐 만 아니라 효율적인 비차단 및 비동기 접근 방식을 지원하여, Spring 5.0 이후 부터는 RestTemplate는 deprecated 되었습니다. (WebClient 사용 지향

 

RestTemplate의 특징

 · Spring 3.0 부터 지원하는 Spring의 HTTP 통신 템플릿

 · HTTP 요청 후 JSON, XML, String 과 같은 응답을 받을 수 있는 템플릿

 · Blocking I/O 기반의 동기방식을 사용하는 템플릿

 · RESTful 형식에 맞추어진 템플릿

 · Header, Content-Tpye등을 설정하여 외부 API 호출

 · Server to Server 통신에 사용

 

RestTemplate 동작 원리

1. 애플리케이션 내부에서 REST API에 요청하기 위해 RestTemplate의 메서드를 호출한다.
2. RestTemplate은 MessageConverter를 이용해 java object를 request body에 담을 message(JSON etc.)로 변환한다. 메시지 형태는 상황에 따라 다름
3. ClientHttpRequestFactory에서 ClientHttpRequest을 받아와 요청을 전달한다.
4. 실질적으로 ClientHttpRequest가 HTTP 통신으로 요청을 수행한다.
5. RestTemplate이 에러핸들링을 한다.
6. ClientHttpResponse에서 응답 데이터를 가져와 오류가 있으면 처리한다.
7. MessageConverter를 이용해 response body의 message를 java object로 변환한다.
8. 결과를 애플리케이션에 돌려준다.
※ RestTemplate은 통신 과정을 ClientHttpRequestFactory(ClientHttpRequest, ClientHttpResponse)에 위임합니다. ClientHttpRequestFactory의 실체는 HttpURLConnection, Apache HttpComponents, HttpClient와 같은 HTTP Client
 

 

 

API 호출 클래스 종류

RestTemplate

Spring 3부터 지원 되었고 REST API 호출이후 응답을 받을 때까지 기다리는 동기방식입니다

 

AsyncRestTemplate

Spring 4에 추가된 비동기 RestTemplate입니다

Spring 5.0에서는 deprecated 되었습니다

 

WebClient

Spring 5에 추가된 논블럭, 리엑티브 웹 클리이언트로 동기, 비동기 방식을 지원합니다.

 

 

지원 메서드

메서드 HTTP 설명
getForObject : Object GET GET 방식 요청으로 결과를 객체로 반환
getForEntity : ResponseEntity GET GET 방식 요청으로 결과를 ResponseEntity로 반환
postForLocation POST POST 방식 요청으로 결과를 헤더에 저장된 URI로 반환
postForObject : Object POST POST 방식 요청으로 결과를 객체로 반환
postForEntity : ResponseEntity POST POST 방식 요청으로 결과를 ResponseEntity로 반환
delete DELETE DELETE 방식 요청으로 메서드 실행
headForHeaders HEADER 헤더의 정보를 얻을 수 있고, HTTP HEAD 메서드 사용
put PUT HTTP PUT 메서드를 실행
patchForObject PATCH HTTP PATCH 메서드를 실행
optionsForAllow OPTIONS 지원하는 HTTP 메서드 조회
exchange : ResponseEntity any 헤더 생성 및 어떤 요청이든 사용 가능
execute any Request/Response 콜백을 수정할 수 있음

 

 

RestTemplate 사용 방법

0. 결과값을 담을 객체를 생성합니다.

1. 타임아웃 설정시 HttpComponentsClientHttpRequestFactory 객체를 생성합니다.

2. RestTemplate 객체를 생성합니다.

3. header 설정을 위해 HttpHeader 클래스를 생성한 후 HttpEntity 객체에 넣어줍니다.

4. 요청 URL을 정의해줍니다.

5. exchange() 메소드로 api를 호출합니다.

6. 요청한 결과를 HashMap에 추가합니다.

 

RestTemplate 사용 전 의존성 추가

RestTemplate을 생성할 때 어떠한 HTTP Client를 사용할 것인지 ClientHttpRequestFactorty를 전달하여 지정할 수 있습니다. 기본 생성자의 경우 내부적으로는 ClientHttpRequestFactory의 구현체인 SimpleClientHttpRequestFactory를 사용하여 초기화 합니다. 이 경우 jdk가 기본으로 제공하는 HttpURLConnection을 통해 ClientHttpRequest 객체를 생성합니다. 만약, apache에서 제공하는 HttpClient를 사용하고 싶다면 HttpComponentsClientHttpRequestFactory를 생성자에 넘겨주면 됩니다. HttpClient 사용을 위해서는 Apache HttpClient 라이브러리를 포함하고 있어야 합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// gradle 이용시
implementation 'org.apache.httpcomponents:httpcore:4.4.15'
implementation 'org.apache.httpcomponents:httpclient:4.5.13'
 
// maven 이용시
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpcore</artifactId>
    <version>4.4.15</version>
</dependency>
<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.13</version>
</dependency>
cs
 

 

 

RestTemplate 사용 예시

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class RestAPI {
 
    @GetMapping("")
    public HashMap<String, Object> callAPI(){
 
        // 0. 결과값을 담을 객체를 생성합니다.
        HashMap<String, Object> resultMap = new HashMap<String, Object>();
        try {
            // 1. 타임아웃 설정시 HttpComponentsClientHttpRequestFactory 객체를 생성합니다.
            HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
            factory.setConnectTimeout(5000); // 타임아웃 설정 5초
            factory.setReadTimeout(5000); // 타임아웃 설정 5초
 
            //Apache HttpComponents : 각 호스트(IP와 Port의 조합)당 커넥션 풀에 생성가능한 커넥션 수
            HttpClient HttpClient httpClient = HttpClientBuilder.create()
                                                    .setMaxConnTotal(50)//최대 커넥션 수
                                                    .setMaxConnPerRoute(20).build();
            factory.setHttpClient(httpClient);
 
            // 2. RestTemplate 객체를 생성합니다.
            RestTemplate restTemplate = new RestTemplate(factory);
 
            // 3. header 설정을 위해 HttpHeader 클래스를 생성한 후 HttpEntity 객체에 넣어줍니다.
            HttpHeader header = new HttpHeader();
            HttpEntity<String> entity = new HttpEntity<String>(header);
 
            // 4. 요청 URL을 정의해줍니다.
            String url = "api 요청 URL";
            UriComponents uri = UriComponentsBuilder.fromHttpUrl(url).queryParam("파라미터명", 값).build(false);
 
            // 5. exchange() 메소드로 api를 호출합니다.
            ResponseEntity<Map> response = restTemplate.exchange(uri.toString, HttpMethod.GET, entity, Map.class);
 
            // 6. 요청한 결과를 HashMap에 추가합니다.
            // HTTP Status Code
            resultMap.put("statusCode", response.getStatusCodeValue());
            // 헤더 정보
            resultMap.put("header", response.getHeaders());
            // 반환받은 실제 데이터 정보
            resultMap.put("body", response.getBody());
 
        } catch (Exception e) {
            e.printStackTrace();
        }// end catch
    }//callAPI
}//class
cs
 

 

 

 

요청 URI 설정 방법

 · String 변수 사용, StringBuffer 객체 사용, URI 객체 사용, UriComponents 객체 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
 * String 변수 사용하여 만들기
 */
// 1. 요청 URL
String url = "요청 URL";
 
// 2. 쿼리스트링 추가
url = url + "?파라미터명=" + 값;
url = url + "&파라미터명=" + 값;
 
/**
 * StringBuffer 객체 사용하여 만들기
 * urlBuffer.toString() 으로 사용
 */
StringBuffer urlBuffer = new StringBuffer();
urlBuffer.append("요청 URL")
        .append("?파라미터명=")
        .append(값)
        .append("&파라미터명=")
        .append(값);
 
/**
 * URI 객체 사용하여 만들기 (정적 파라미터 설정)
 * uri.toString() 으로 사용
 */
// 1. 요청 URL 및 쿼리스트링 추가
URI uri = UriComponentsBuilder.fromHttpUrl("요청 URL")
                .queryParams("파라미터명", 값)
                .queryParams("파라미터명", 값)
                .queryParams("파라미터명", URLEncoder.encode(값, "UTF-8"))
                .build();
 
/**
 * UriComponents 객체 사용하여 만들기
 * uriComponenets.toUriString() 으로 사용
 */
// 1. 요청 URL 및 쿼리스트링 추가
UriComponents uriComponents = UriComponentsBuilder.newInstance()
                                    .path("요청 URL")
                                    .queryParam("파라미터명", 값)
                                    .queryParam("파라미터명", 값)
                                    .build();
 
/**
 * UriComponents 객체 사용하여 만들기 (동적 주소 사용 : pathVariable)
 * uriComponenets.toUriString() 으로 사용
 */
// 1. 요청 URL 및 쿼리스트링 추가
UriComponents uriComponents = UriComponentsBuilder.newInstance()
                                    .scheme("http")
                                    .host("요청 URL")
                                    .path("/{language}/{type}")    // PathVariable 사용시
                                    .queryParam("파라미터명", 값)
                                    .queryParam("파라미터명", 값)
                                    .build()
                                    .expand("java""example")
                                    .encode();
 
cs

 

 

 

 

 

 

Header 만들기

 · Header는 Spring Framework에서 제공하는 HttpHeaders 클래스에 추가합니다.

 · 만들어진 Header는 Spring Framework에서 제공하는 HttpEntity 클래스에 추가하여 사용합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 1. HttpHeaders 객체 생성
HttpHeaders headers = new HttpHeaders();
 
// 2. 헤더 설정 : ContentType, Accept 설정
headers.setContentType(new MediaType("application","json",Charset.forName("UTF-8")));
headers.setAccept(Arrays.asList(new MediaType[] { MediaType.APPLICATION_JSON }));
 
 
// 3. 헤더 설정 : Key, Value 쌍으로 설정
headers.set("헤더이름""값");
 
// HTTP 요청할 떄 생성한 Header 설정
ResponseEntity<String> responseEntity = restTemplate.exchange("요청 URL"
                                    , HttpMethod.GET, new HttpEntity<>(headers), String.class);
cs

 

Body 만들기

 · Body는 보통 key, value의 쌍으로 이루어지기 때문에 Java에서 제공해주는 MultiValueMap 타입을 사용합니다.

 · 만들어진 Body는 Spring Framework에서 제공하는 HttpEntity 클래스에 추가하여 사용합니다. 

1
2
3
4
5
6
7
8
9
10
11
12
// 1. MultiValueMap 객체 생성
MultiValueMap<StringString> body = new LinkedMultiValueMap<StringString>();
 
// 2. body : 요청 파라미터 설정
body.add("키""값");
 
// 3. 만들어진 header와 body를 가진 HttpEntity 객체 생성
HttpEntity<MultiValueMap<StringString>> entity = new HttpEntity<>(body, headers);
 
// HTTP 요청
ResponseEntity<String> response = restTemplate.exchange("요청 URL"
                                , HttpMethod.GET, entity, String.class);
cs

 

 


Get 방식 예시

 · getForEntity("요청 URL", 응답내용 매핑 객체)

 · exchange("요청 URL", HttpMethod.GET, 응답내용 매핑 객체)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 타임아웃 설정
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 타임아웃 설정 5초
factory.setReadTimeout(5000); // 타임아웃 설정 5초
 
// RestTemplate 객체 생성
RestTemplate restTemplate = new RestTemplate(factory);
 
// 요청 URL 및 쿼리스트링 설정
URI url = UriComponentsBuilder.fromHttpUrl("요청 URL")
                .queryParams("파라미터명", 값)
                .queryParams("파라미터명", 값)
                .queryParams("파라미터명", URLEncoder.encode(값, "UTF-8"))
                .build();
 
// HTTP GET 요청
RestTemplate response = restTemplate.exchange(url.toString(), HttpMethod.GET, entity, String.class);
 
// HTTP GET 요청에 대한 응답 확인
System.out.println("status : " + response.getStatusCode());
System.out.println("body : " + response.getBody());
cs

 

 

 

Post 방식 예시

 · postForEntity("요청 URL", 응답내용 매핑 객체)

 · exchange("요청 URL", HttpMethod.POST, 응답내용 매핑 객체)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 타임아웃 설정
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setConnectTimeout(5000); // 타임아웃 설정 5초
factory.setReadTimeout(5000); // 타임아웃 설정 5초
 
// RestTemplate 객체 생성
RestTemplate restTemplate = new RestTemplate(factory);
 
// Header 및 Body 설정
HttpHeader headers = new HttpHeader();
headers.set("헤더이름""값")
MultiValueMap<StringString> body = new LinkedMultiValueMap<StringString>();
body.add("키""값");
 
// 설정한 Header와 Body를 가진 HttpEntity 객체 생성
HttpEntity<MultiValueMap<StringString>> entity = new HttpEntity<>(body, headers);
 
// HTTP POST 요청
RestTemplate response = restTemplate.exchange("요청 URL", HttpMethod.POST, entity, String.class);
 
// HTTP POST 요청에 대한 응답 확인
System.out.println("status : " + response.getStatusCode());
System.out.println("body : " + response.getBody());
cs

 

 

RestTemplate Builder 유틸

Builder 패턴을 이용하여 RestTemplate로 HTTP 요청을 할 수 있도록 만든 Util 클래스

 · HTTP 요청 후 status, header, body를 key로 가진 HashMap<String, Object> 형태로 반환

 

사용 방법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// GET 요청
HashMap<String, Object> result = new HttpUtil()
        .url("https://www.naver.com")
        .method("get")
        .queryString("파라미터명""값")
        .build();
 
// GET 요청 결과
System.out.println(result.get("status").toString());
System.out.println(result.get("header").toString());
System.out.println(result.get("body").toString());
 
// POST 요청
HashMap<String, Object> result = new HttpUtil()
        .url("https://www.naver.com")
        .method("post")
        .contentType("application""json""UTF-8")
        .header("헤더이름""값")
        .body("파라미터명""값")
        .build();
 
// POST 요청 결과
System.out.println(result.get("status").toString());
System.out.println(result.get("header").toString());
System.out.println(result.get("body").toString());
cs
 
 

Util 클래스

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package org.example.common.util;
 
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
 
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
 
public class HttpUtil {
 
    // 헤더
    private HttpHeaders headers;
    // 요청 바디 : <Key, Value> 쌍
    private MultiValueMap<StringString> body;
    // 타임아웃
    private HttpComponentsClientHttpRequestFactory factory;
    // 요청 URL
    private StringBuilder urlBuilder;
    private boolean queryStringToken;
    private String url;
    // 요청 방식
    private String method;
 
    public HttpUtil(){
        this.headers = new HttpHeaders();
        this.factory = new HttpComponentsClientHttpRequestFactory();
        this.factory.setConnectTimeout(5000);
        this.factory.setReadTimeout(5000);
        this.body = new LinkedMultiValueMap<StringString>();
        this.queryStringToken = true;
    }
 
    /**
     * content-type 설정 : new MediaType 설정 값
     *
     * @param type
     * @param subType
     * @param charSet
     * @return
     */
    public HttpUtil contentType(String type, String subType, String charSet){
        this.headers.setContentType(new MediaType(type, subType, Charset.forName(charSet)));
        return this;
    }
 
    /**
     * connect-timeout 설정<br>
     * default : 5초
     *
     * @param time
     * @return
     */
    public HttpUtil connectTimeout(int time){
        this.factory.setConnectTimeout(time);
        return this;
    }
 
    /**
     * read-timeout 설정<br>
     * default : 5초
     *
     * @param time
     * @return
     */
    public HttpUtil readTimeout(int time){
        this.factory.setReadTimeout(time);
        return this;
    }
 
    /**
     * 요청 URL 설정
     *
     * @param url
     * @return
     */
    public HttpUtil url(String url) {
        this.urlBuilder = new StringBuilder();
        urlBuilder.append(url);
        return this;
    }
 
    /**
     * 쿼리스트링 설정
     *
     * @param name
     * @param value
     * @return
     */
    public HttpUtil queryString(String name, String value) {
        Assert.notNull(urlBuilder, "url 미입력");
 
        if(queryStringToken) {
            urlBuilder.append("?")
                    .append(name)
                    .append("=")
                    .append(value);
            queryStringToken = false;
        } else {
            urlBuilder.append("&")
                    .append(name)
                    .append("=")
                    .append(value);
        }
 
        return this;
    }
 
    /**
     * 요청 방식 설정(get, post)
     *
     * @param method
     * @return
     */
    public HttpUtil method(String method) {
        this.method = method.toUpperCase();
        return this;
    }
 
    /**
     * 요청 헤더 설정
     *
     * @param name
     * @param value
     * @return
     */
    public HttpUtil header(String name, String value){
        headers.set(name, value);
        return this;
    }
 
    /**
     * body 요청 파라미터 설정 : key, value
     *
     * @param key
     * @param value
     * @return
     */
    public HttpUtil body(String key, String value){
        this.body.add(key, value);
        return this;
    }
 
    /**
     * body 요청 파라미터 설정 : map
     *
     * @param params
     * @return
     */
    public HttpUtil body(HashMap<String, Object> params){
        Iterator<String> itr = params.keySet().iterator();
        while(itr.hasNext()){
            String key = itr.next();
            body.add(key, (String)params.get(key));
        }
        return this;
    }
 
    /**
     * HTTP 요청 후 결과 반환(status, header, body)
     *
     * @return
     */
    public HashMap<String, Object> build(){
        HashMap<String, Object> result = new HashMap<>();
 
        RestTemplate restTemplate = new RestTemplate(factory);
        HttpEntity<MultiValueMap<StringString>> entity = new HttpEntity<>(body, headers);
        url = urlBuilder.toString();
 
        ResponseEntity<String> response = null;
        if ("GET".equals(method)){
            response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
        } else if("POST".equals(method)) {
            response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
        }
 
        result.put("status", response.getStatusCode());
        result.put("header", response.getHeaders());
        result.put("body", response.getBody());
 
        return result;
    }
}
cs

[출처] [Spring]스프링 RestTemplate|작성자 로그

728x90
반응형

댓글