如何使用RestTemplate转发大文件?
我有一个web服务调用,通过它可以上传zip文件。这些文件然后被转发到另一个服务进行存储,解压缩等。 现在,文件存储在文件系统中,然后构建FileSystemResource。如何使用RestTemplate转发大文件?
Resource zipFile = new FileSystemResource(tempFile.getAbsolutePath());
我可以用一个ByteStreamResource为了节省时间(磁盘上的文件的保存转发之前没有必要),但我需要建立一个字节数组。在大文件的情况下,我会得到一个“OutOfMemory:java堆空间”错误。
ByteArrayResource r = new ByteArrayResource(inputStream.getBytes());
的任何解决方案,以转发文件没有得到使用RestTemplate的内存不足的错误?
您可以使用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)
或将击败点)
是不是所有的输入流都以这种方式加载到内存中? – Bax
@Bax不,在复制过程中它会被零碎地装入。应该是相当有记忆效率的。 – artbristol
doWithRequest(request)在request.execute()之前被调用,并且在所有流被复制到请求主体之前它不会返回。 cintent被大块复制到身体上,但没有人从它身上消耗掉,它不像管子那样起作用,我是否错过了smth? – Bax
的唯一部分@ artbristol的answer你真正需要的是这样的(你可以设置为RestTemplate
的Spring bean):
final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);
在那之后,我觉得只是使用FileSystemResource
作为您的要求的身体会做正确的事。
我也用这种方式成功地使用了InputStreamResource
,对于已经有数据作为InputStream
并且不需要多次使用它的情况。
在我的情况下,我们gzipped我们的文件,并在InputStreamResource
包装GZipInputStream
。
我认为上面的答案有不必要的代码 - 你不需要创建一个匿名的RequestCallback内部类,并且你不需要使用来自apache的IOUtils。
我花了一点时间研究一个类似的解决方案,以你的,这是我想出了:
你可以实现你的目标,多用the 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);
(这个例子假定从那里你要发布帖子的回应是JSON。但是,这可以很容易地通过改变返回类型类...设置上面Map.class改变)
灿你是否将输入流传递给其他服务?或者您必须将输入流写入文件,然后将文件句柄传递给服务。另外,不确定这与Groovy有何关系? –
我没有找到任何方法来传递输入流。我使用Groovy标签,因为代码是在groovy中(java InputStream没有getBytes方法) –
啊,我是在用Java风格编写时抛出的;-)那么这个其他服务接受了什么呢? –