Java 如何使用RestTemplate转发大文件?
我有一个web服务调用,通过它可以上传zip文件。然后,这些文件被转发到另一个服务进行存储、解压缩等。 现在,文件存储在文件系统上,然后构建一个FileSystemResourceJava 如何使用RestTemplate转发大文件?,java,spring,groovy,resttemplate,Java,Spring,Groovy,Resttemplate,我有一个web服务调用,通过它可以上传zip文件。然后,这些文件被转发到另一个服务进行存储、解压缩等。 现在,文件存储在文件系统上,然后构建一个FileSystemResource Resource zipFile = new FileSystemResource(tempFile.getAbsolutePath()); 我可以使用ByTestStreamResource来节省时间(在转发之前不需要在磁盘上保存文件),但为此我需要构建一个字节数组。对于大文件,我将得到一个“OutOfMemor
Resource zipFile = new FileSystemResource(tempFile.getAbsolutePath());
我可以使用ByTestStreamResource来节省时间(在转发之前不需要在磁盘上保存文件),但为此我需要构建一个字节数组。对于大文件,我将得到一个“OutOfMemory:java堆空间”错误
使用RestTemplate转发文件而不出现OutOfMemory错误的任何解决方案 编辑:其他答案更好(使用
资源
)
我原来的答覆是:
对于这种低级操作,可以使用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);
final InputStream fis=新文件InputStream(新文件(“c:\\autoexec.bat”);//或者别的什么
final RequestCallback RequestCallback=new RequestCallback(){
@凌驾
public void doWithRequest(最终ClientHttpRequest请求)引发IOException{
request.getHeaders().add(“内容类型”、“应用程序/八位字节流”);
copy(fis,request.getBody());
}
};
最终RestTemplate RestTemplate=新RestTemplate();
SimpleClientHttpRequestFactory requestFactory=新的SimpleClientHttpRequestFactory();
requestFactory.setBufferreRequestBody(false);
setRequestFactory(requestFactory);
最终HttpMessageConverterExtractor响应Extractor=
新的HttpMessageConverterExtractor(String.class,restTemplate.getMessageConverters());
restTemplate.execute(“http://localhost:4000,HttpMethod.POST,requestCallback,responseExtractor);
(感谢Baz指出您需要调用
setBufferreRequestBody(false)
,否则它将无法解决问题)您真正需要的@artbristol的唯一部分是这个(您可以将其设置为RestTemplate
Springbean):
在这之后,我认为仅仅使用文件系统资源作为请求主体将做正确的事情
我还以这种方式成功地使用了InputStreamResource
,用于您已经将数据作为InputStream
使用,并且不需要多次使用它的情况
在我的例子中,我们已经gzip了我们的文件,并将一个gzip输入流
包装在InputStreamResource
中,我认为上面的答案有不必要的代码-您不需要创建匿名RequestCallback内部类,也不需要使用apache中的IOUtils
我花了一点时间研究了一个类似于您的解决方案,这就是我想到的:
通过使用和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);
RestTemplate RestTemplate=new RestTemplate();
SimpleClientHttpRequestFactory requestFactory=新的SimpleClientHttpRequestFactory();
requestFactory.setBufferreRequestBody(false);
setRequestFactory(requestFactory);
File File=新文件(“/whatever”);
HttpEntity requestEntity=新HttpEntity(新文件系统资源(文件));
ResponseEntity e=restTemplate.exchange(“http://localhost:4000,HttpMethod.POST,requestEntity,Map.class);
(本例假设您发布到的响应是JSON。但是,可以通过更改返回类型class…设置为上面的Map.class来轻松更改)您不能将inputstream传递给其他服务吗?或者,您必须将inputstream写入文件,然后将文件句柄传递给服务。另外,我不确定这与Groovy有什么关系?我没有找到任何方法只传递输入流。我使用Groovy标记是因为代码在Groovy中(java InputStream没有getBytes方法)啊,我是在您以非常java风格编写它时抛出的;-)那么,这个其他服务接受什么呢?我不提供这个答案,因为它的范围比您的问题的答案要大一些,但是您是否考虑过针对这个问题的Spring集成?您基本上看到的是一种声明检查模式,带有web服务和REST适配器。通过SI框架,您可以完成许多工作。输入流不是这样加载到内存中的吗?@Bax否,复制时会逐段加载。应该非常节省内存。@BaxdoWithRequest
在匿名类中;它以前定义过,但在执行(它是回调)找到某种解决方案之前不会被调用,使用*ClientHttpRequestFactory#setBufferRequestBody(false)依次生成*StreamingClientHttpRequest,在调用getBody()时打开连接。啊。。。autoexec.bat。谢谢你的回忆
final RestTemplate restTemplate = new RestTemplate();
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setBufferRequestBody(false);
restTemplate.setRequestFactory(requestFactory);
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);