복붙노트

[SPRING] RestTemplate으로 큰 파일을 전달하는 방법?

SPRING

RestTemplate으로 큰 파일을 전달하는 방법?

zip 파일을 업로드 할 수있는 웹 서비스 호출이 있습니다. 그런 다음 파일을 저장, 압축 해제 등을 위해 다른 서비스로 전달합니다. 지금은 파일이 파일 시스템에 저장되고 FileSystemResource가 작성됩니다.

Resource zipFile = new FileSystemResource(tempFile.getAbsolutePath());

ByteStreamResource를 사용하여 시간을 절약 할 수 있지만 (디스크에 파일을 저장할 때는 전달할 필요가 없습니다) 바이트 배열을 만들어야합니다. 큰 파일의 경우 "OutOfMemory : java heap space"오류가 발생합니다.

ByteArrayResource r = new ByteArrayResource(inputStream.getBytes());

RestTemplate을 사용하여 OutOfMemory 오류가 발생하지 않고 파일을 전달하는 모든 솔루션?

해결법

  1. ==============================

    1.이러한 종류의 하위 수준 작업에 대해 execute를 사용할 수 있습니다. 이 스 니펫에서는 Commons IO의 복사 방법을 사용하여 입력 스트림을 복사했습니다. 기대하는 응답의 종류에 맞게 HttpMessageConverterExtractor를 사용자 정의해야합니다.

    이러한 종류의 하위 수준 작업에 대해 execute를 사용할 수 있습니다. 이 스 니펫에서는 Commons IO의 복사 방법을 사용하여 입력 스트림을 복사했습니다. 기대하는 응답의 종류에 맞게 HttpMessageConverterExtractor를 사용자 정의해야합니다.

    final InputStream fis = new FileInputStream(new File("c:\\autoexec.bat")); // or whatever
    final RequestCallback requestCallback = new RequestCallback() {
         @Override
        public void doWithRequest(final ClientHttpRequest request) throws IOException {
            request.getHeaders().add("Content-type", "application/octet-stream");
            IOUtils.copy(fis, request.getBody());
         }
    };
    final RestTemplate restTemplate = new RestTemplate();
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);     
    restTemplate.setRequestFactory(requestFactory);     
    final HttpMessageConverterExtractor<String> responseExtractor =
        new HttpMessageConverterExtractor<String>(String.class, restTemplate.getMessageConverters());
    restTemplate.execute("http://localhost:4000", HttpMethod.POST, requestCallback, responseExtractor);
    

    (Baz에게 setBufferRequestBody (false)를 호출해야한다는 점을 지적 해 주시거나 포인트를 무효화 할 것입니다)

  2. ==============================

    2.위의 대답에는 불필요한 코드가 있다고 생각합니다. 익명의 RequestCallback 내부 클래스를 만들 필요가 없으며 Apache에서 IOUtils를 사용할 필요가 없습니다.

    위의 대답에는 불필요한 코드가 있다고 생각합니다. 익명의 RequestCallback 내부 클래스를 만들 필요가 없으며 Apache에서 IOUtils를 사용할 필요가 없습니다.

    나는 너와 비슷한 해결책을 찾기 위해 약간의 시간을 보냈다. 그리고 이것은 내가 생각해 낸 것이다.

    Spring Resource Interface와 RestTemplate을 사용하면 훨씬 간단하게 목표를 달성 할 수 있습니다.

    RestTemplate restTemplate = new RestTemplate();
    
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);
    restTemplate.setRequestFactory(requestFactory);
    
    File file = new File("/whatever");
    
    HttpEntity<FileSystemResource> requestEntity = new HttpEntity<>(new FileSystemResource(file));
    ResponseEntity e = restTemplate.exchange("http://localhost:4000", HttpMethod.POST, requestEntity, Map.class);
    

    (이 예제에서는 POSTing 할 곳의 응답을 JSON이라고 가정하지만 반환 유형 클래스 ...를 위의 Map.class로 변경하여 쉽게 변경할 수 있습니다)

  3. ==============================

    3.당신이 정말로 필요로하는 @ artbristol의 대답의 유일한 부분은 이것 (RestTemplate Spring 빈으로 설정할 수있다)이다.

    당신이 정말로 필요로하는 @ artbristol의 대답의 유일한 부분은 이것 (RestTemplate Spring 빈으로 설정할 수있다)이다.

    final RestTemplate restTemplate = new RestTemplate();
    SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
    requestFactory.setBufferRequestBody(false);     
    restTemplate.setRequestFactory(requestFactory);     
    

    그 후, 필자는 요청 본문으로 FileSystemResource를 사용하는 것이 올바른 일을 할 것이라고 생각합니다.

    나는 또한 이미 InputStreamResource를이 방법으로 성공적으로 사용했다. 이미 데이터를 InputStream으로 가지고 있고 여러 번 소비 할 필요가없는 경우이다.

    필자의 경우 파일을 gzip으로 압축하여 InputStreamResource에 GZipInputStream을 래핑했습니다.

  4. from https://stackoverflow.com/questions/15781885/how-to-forward-large-files-with-resttemplate by cc-by-sa and MIT license