我有一个可以上传zip文件的Web服务调用。然后将文件转发到另一个服务以进行存储,解压缩等。 现在文件存储在文件系统中,然后构建FileSystemResource。
Resource zipFile = new FileSystemResource(tempFile.getAbsolutePath());
我可以使用ByteStreamResource以节省时间(在转发之前不需要在磁盘上保存文件)但是为此我需要构建一个字节数组。如果是大文件,我将收到“OutOfMemory:java heap space”错误。
ByteArrayResource r = new ByteArrayResource(inputStream.getBytes());
使用RestTemplate转发文件而不会出现OutOfMemory错误的任何解决方案?
答案 0 :(得分:37)
您可以使用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);
(感谢Baz指出你需要致电setBufferRequestBody(false)
或者它会打败这一点)
答案 1 :(得分:15)
我认为上面的答案有不必要的代码 - 你不需要创建一个匿名的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");
HttpEntity<FileSystemResource> requestEntity = new HttpEntity<>(new FileSystemResource(file));
ResponseEntity e = restTemplate.exchange("http://localhost:4000", HttpMethod.POST, requestEntity, Map.class);
(这个例子假设你要POST的地方的响应是JSON。但是,这可以通过改变返回类型类...上面设置为Map.class来轻松改变)
答案 2 :(得分:13)
你真正需要的@ artbristol answer的唯一部分就是这个(你可以设置为RestTemplate
Spring bean):
final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);
之后,我认为只需使用FileSystemResource
作为您的请求主体即可。
我也已成功使用InputStreamResource
这种情况,因为您已将数据作为InputStream
并且不需要多次使用它。
在我的情况下,我们已经压缩了我们的文件并将GZipInputStream
包裹在InputStreamResource
中。