반응형

Spring 에서 제공하는 RestTemplate 을 이용해 File 을 download 할 때 byte로 받게 되면 large file은 out of memory 가 날수 있습니다.

그래서 stream으로 받아서 처리를 해줘야 합니다.


sample code를 공유합니다.


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
 
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
 
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.protocol.HttpContext;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.FormHttpMessageConverter;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RequestCallback;
import org.springframework.web.client.ResponseExtractor;
import org.springframework.web.client.RestTemplate;
 
public class HttpUtil {
  public static void downloadPost(String url, String destPath, MultiValueMap<String, Object> parts, RestTemplate restOperations) {
    HttpHeaders headers = HttpUtil.getHeaders();
 
    // Optional Accept header
    RequestCallback requestCallback = request -> {
      request.getHeaders().addAll(headers);
      request.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM, MediaType.ALL));
      FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();
      formHttpMessageConverter.setCharset(Charset.forName("EUC-KR"));
      formHttpMessageConverter.write(parts, MediaType.APPLICATION_FORM_URLENCODED, request);
    };
 
    // Streams the response instead of loading it all in memory
    ResponseExtractor<Void> responseExtractor = response -> {
      // Here I write the response to a file but do what you like
      String filename = response.getHeaders().getContentDisposition().getFilename();
      Path path = Paths.get(destPath + "/" + filename);
      Files.copy(response.getBody(), path);
      return null;
    };
 
    restOperations.execute(URI.create(url), HttpMethod.POST, requestCallback, responseExtractor);
  }
 
  public static RestTemplate getRestTemplate(final HttpClientContext context) {
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
    factory.setReadTimeout(5000); // milliseconds
    RestTemplate restOperations = new RestTemplate(factory);
    restOperations.setRequestFactory(new HttpComponentsClientHttpRequestFactory() {
      @Override
      protected HttpContext createHttpContext(HttpMethod httpMethod, URI uri) {
        if (context.getAttribute(HttpClientContext.COOKIE_STORE) == null) {
          context.setAttribute(HttpClientContext.COOKIE_STORE, new BasicCookieStore());
          Builder builder = RequestConfig.custom().setRedirectsEnabled(false);
          context.setRequestConfig(builder.build());
        }
        return context;
      }
    });
 
    return restOperations;
  }
 
  public static HttpHeaders getHeaders() {
    HttpHeaders headers = new HttpHeaders();
    headers.set("Accept-Encoding""gzip, deflate, sdch");
    return headers;
  }
 
}
 


Dependency

1
2
3
4
5
6
7
8
9
    <!-- http client -->
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>


반응형

+ Recent posts