Подтвердить что ты не робот

Как переместить большие файлы с помощью RestTemplate?

У меня есть вызов веб-службы, через который можно загружать zip файлы. Затем файлы пересылаются в другую службу для хранения, распаковки и т.д. Пока файл хранится в файловой системе, создается файл FileSystemResource.

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

Я мог бы использовать ByteStreamResource, чтобы сэкономить время (сохранение файла на диске не требуется перед пересылкой), но для этого мне нужно построить массив байтов. В случае больших файлов я получу ошибку "OutOfMemory: java heap space".

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

Любые решения для пересылки файлов без получения ошибки OutOfMemory с помощью RestTemplate?

4b9b3361

Ответ 1

Вы можете использовать execute для такого рода операций низкого уровня. В этом фрагменте я использовал метод Commons IO copy для копирования входного потока. Вам нужно будет настроить 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);

(Спасибо Базу за указание, что вам нужно позвонить setBufferRequestBody(false) или он победит точку)

Ответ 2

Единственная часть @artbristol answer, которая вам действительно нужна, это то, что вы можете настроить как RestTemplate Spring bean):

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

После этого, я думаю, просто используя FileSystemResource, поскольку тело вашего запроса будет правильно.

Я также успешно использовал InputStreamResource таким образом, для случаев, когда у вас уже есть данные как InputStream и их не нужно потреблять несколько раз.

В моем случае мы имели gzipped наши файлы и завернули a GZipInputStream в InputStreamResource.

Ответ 3

Я думаю, что вышеупомянутый ответ имеет ненужный код - вам не нужно создавать анонимный внутренний класс RequestCallback, и вам не нужно использовать IOUtils из apache.

Я потратил немного времени на изучение аналогичного решения для вас, и это то, что я придумал:

Вы можете значительно упростить свою задачу, используя Spring Resource Interface и RestTemplate.

RestTemplate restTemplate = new RestTemplate();

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

File file = new File('/whatever')

ResponseEntity e = restTemplate.exchange("http://localhost:4000", HttpMethod.POST, new HttpEntity<Resource>(new FileSystemResource(file)), Map.class);

(В этом примере предполагается, что ответ от того, где вы выполняете POSTING, - это JSON. Но это можно легко изменить, изменив класс возвращаемого типа... установите на Map.class выше)