41

我有一个网络服务调用,可以通过它上传 zip 文件。然后将文件转发到另一个服务进行存储、解压缩等。现在文件存储在文件系统上,然后构建 FileSystemResource。

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

我可以使用 ByteStreamResource 来节省时间(在转发之前不需要将文件保存在磁盘上),但为此我需要构建一个字节数组。如果文件很大,我会收到“OutOfMemory : java heap space”错误。

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

使用 RestTemplate 转发文件而不出现 OutOfMemory 错误的任何解决方案?

4

3 回答 3

43

编辑:其他答案更好(使用Resourcehttps://stackoverflow.com/a/36226006/116509

我原来的答案:

您可以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),否则会失败)

于 2013-04-03T10:49:22.697 回答
25

您真正需要的@artbristol答案的唯一部分是(您可以将其设置为RestTemplateSpring bean):

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

在那之后,我认为只使用 aFileSystemResource作为您的请求正文会做正确的事情。

我也InputStreamResource成功地使用了这种方式,对于您已经拥有数据InputStream并且不需要多次使用它的情况。

就我而言,我们已经 gzip 压缩了我们的文件并将 a 包装GZipInputStream在一个InputStreamResource.

于 2015-09-21T14:16:06.603 回答
24

我认为上面的答案有不必要的代码——你不需要创建一个匿名的 RequestCallback 内部类,也不需要使用 apache 的 IOUtils。

我花了一些时间研究与您类似的解决方案,这就是我想出的:

通过使用Spring 资源接口和 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);

(此示例假设您发布到的响应是 JSON。但是,这可以通过更改返回类型类来轻松更改...设置为上面的 Map.class)

于 2016-03-25T18:45:38.437 回答