ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] RestTemplate을 편리하게 사용하자 (샘플 포함)
    백엔드/Spring 2022. 6. 12. 19:19

    🚀  들어가면서

    • RestTemplate을 구체화하면서, 편리하게 사용할 수 있도록 만들어보고 싶었다.
    • 통신 사이에 AOP를 구현하여, 요청과 응답의 URI, Body, Param, Header를 로깅하는 기능을 할까 하였지만..
    • RestTemplate에 인터셉터를 추가할 수 있는 함수가 있어서 적절히 사용했다.

    ⚙️ 소스코드

    HttpHeader.java

    • HttpHeader이다. 가변적으로 추가하기 편하게 만들었다.
    • build() 함수를 통해서 호환이 가능한 Apache의 HttpHeaders로 변환이 가능하다.
    @NoArgsConstructor
    @AllArgsConstructor
    public class HttpHeader {
        private MediaType mediaType;
        private Map<String, String> keyValue;
    
        public HttpHeader(MediaType mediaType){
            this.mediaType = mediaType;
            this.keyValue = new HashMap<String, String>();
        }
    
        public void addHeader(String key, String value){
            this.keyValue.put(key, value);
        }
    
        public void addHeader(Map<String, String> newKeyValue){
            newKeyValue.forEach(
                    (key, value) -> this.keyValue.merge(key, value, (v1, v2) -> v2)
            );
        }
    
        public HttpHeaders build(){
            HttpHeaders build = new HttpHeaders();
            this.keyValue.forEach(build::add);
            return build;
        }
    }

     

    RestHttpClient.java

    • Http 통신에 필요한 정보를 담는 클래스이다.
    • 가변적으로 바디와 쿼리스트링을 담을 수 있도록 하였다.
    • 메소드 별로 필요한 정보가 다르기 때문에, 여러 생성자를 만들었다.
    @Getter
    public class RestHttpClient {
        private HttpMethod method;
        private String url;
        private MultiValueMap<String, String> params;
        private HttpHeader headers;
    
        public RestHttpClient(@NonNull HttpMethod method, @NonNull String url){
            this.method = method;
            this.url = url;
        }
    
        public RestHttpClient(@NonNull HttpMethod method, @NonNull String url, MultiValueMap<String, String> params){
            this.method = method;
            this.url = url;
            this.params = params;
        }
    
        public RestHttpClient(@NonNull HttpMethod method, @NonNull String url, HttpHeader headers){
            this.method = method;
            this.url = url;
            this.headers = headers;
        }
    
        public RestHttpClient(@NonNull HttpMethod method, @NonNull String url, MultiValueMap<String, String> params, HttpHeader headers){
            this.method = method;
            this.url = url;
            this.params = params;
            this.headers = headers;
        }
    
        public void addHeader(String key, String value){
            this.getHeaders().addHeader(key, value);
        }
    
        public void addHeader(Map<String, String> newKeyValue){
            this.getHeaders().addHeader(newKeyValue);
        }
    
        public void addParam(String key, String value){
            if(this.params == null)
                this.params = new LinkedMultiValueMap<String, String>();
            this.params.add(key, value);
        }
    
        public HttpEntity<MultiValueMap<String, String>> toEntity(){
            return new HttpEntity<MultiValueMap<String, String>>(this.params, this.headers.build());
        }
    }

     

    RestProvider.java

    • 이 클래스를 통해서, 통신이 가능하다.
    • 외부에서 send() 함수를 조립하여, 응답 객체로 변환이 가능하도록 하였다.
    @Slf4j
    @Component
    @RequiredArgsConstructor
    public class RestProvider {
        private final RestTemplate restTemplate;
    
        public <T> ResponseEntity<T> send(@NonNull HttpMethod httpMethod, String url, Class<T> responseClassType) {
            RestHttpClient client = new RestHttpClient(httpMethod, url);
            return this.send(client, responseClassType);
        }
    
        public <T> ResponseEntity<T> send(@NonNull HttpMethod httpMethod, String url,
                                          HttpHeader headers, Class<T> responseClassType) {
            RestHttpClient client = new RestHttpClient(httpMethod, url, headers);
            return this.send(client, responseClassType);
        }
    
        public <T> ResponseEntity<T> send(@NonNull HttpMethod httpMethod, String url,
                                          MultiValueMap<String, String> params, Class<T> responseClassType) {
            RestHttpClient client = new RestHttpClient(httpMethod, url, params);
            return this.send(client, responseClassType);
        }
    
        public <T> ResponseEntity<T> send(@NonNull HttpMethod httpMethod, String url,
                                          MultiValueMap<String, String> params,
                                          HttpHeader headers, Class<T> responseClassType) {
            RestHttpClient client = new RestHttpClient(httpMethod, url, params, headers);
            return this.send(client, responseClassType);
        }
    
        public <T> ResponseEntity<T> send(RestHttpClient client, Class<T> responseClassType) {
            if (client.getMethod().equals(HttpMethod.GET)) {
                UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(client.getUrl());
                if (client.getParams() != null) client.getParams().forEach(uriBuilder::queryParam);
                return restTemplate.getForEntity(uriBuilder.toUriString(), responseClassType);
            } else if (client.getMethod().equals(HttpMethod.POST)) {
                return restTemplate.postForEntity(client.getUrl(), client.getParams(), responseClassType);
            } else if (client.getMethod().equals(HttpMethod.PUT)) {
                return restTemplate.exchange(client.getUrl(), HttpMethod.PUT, client.toEntity(), responseClassType);
            } else if (client.getMethod().equals(HttpMethod.PATCH)) {
                restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
                return restTemplate.exchange(client.getUrl(), HttpMethod.PATCH, client.toEntity(), responseClassType);
            } else if (client.getMethod().equals(HttpMethod.DELETE)) {
                return restTemplate.exchange(client.getUrl(), HttpMethod.DELETE, client.toEntity(), responseClassType);
            } else {
                log.info("Not yet implement Method : {} ", client.getMethod());
                return null;
            }
        }
    }

     


    🚦샘플 소스

    • 샘플소스 Github 저장소 : https://github.com/rojae/RestTemplate-Demo
    • 사용한 테스트 API : https://jsonplaceholder.typicode.com/
    • Branch v1 : RestProvider 클래스에서 restTemplate을 new 키워드로 생성하여 통신한다. (스프링 Bean 관리 X)
    • Branch v2 : RestProvider 클래스에서 restTemplate을 bean으로 관리한다.
      (/test/RestTemplateTest.java 소스를 봐야한다)
     

    GitHub - rojae/RestTemplate-Demo: Springboot RestTemplate Demo

    Springboot RestTemplate Demo. Contribute to rojae/RestTemplate-Demo development by creating an account on GitHub.

    github.com

     

    JSONPlaceholder - Free Fake REST API

    {JSON} Placeholder Free fake API for testing and prototyping. Powered by JSON Server + LowDB. Tested with XV. As of Oct 2021, serving ~1.7 billion requests each month.

    jsonplaceholder.typicode.com

     

    반응형
Designed by Tistory.