Как переместить большие файлы с помощью RestTemplate?
У меня есть вызов веб-службы, через который можно загружать zip файлы. Затем файлы пересылаются в другую службу для хранения, распаковки и т.д.
Пока файл хранится в файловой системе, создается файл FileSystemResource.
Resource zipFile = new FileSystemResource(tempFile.getAbsolutePath());
Я мог бы использовать ByteStreamResource, чтобы сэкономить время (сохранение файла на диске не требуется перед пересылкой), но для этого мне нужно построить массив байтов. В случае больших файлов я получу ошибку "OutOfMemory: java heap space".
ByteArrayResource r = new ByteArrayResource(inputStream.getBytes());
Любые решения для пересылки файлов без получения ошибки OutOfMemory с помощью RestTemplate?
Ответы
Ответ 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 выше)