有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何使用RestTemplate转发大文件?

我有一个web服务调用,通过它可以上传zip文件。然后,这些文件被转发到另一个服务进行存储、解压缩等。 文件系统的资源现在存储在文件系统上

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

我可以使用ByTestStreamResource来节省时间(在转发之前不需要在磁盘上保存文件),但为此我需要构建一个字节数组。对于大文件,我将得到一个“OutOfMemory:java堆空间”错误

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

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


共 (3) 个答案

  1. # 1 楼答案

    我认为上面的答案包含了不必要的代码——您不需要创建匿名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);
    

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

  2. # 2 楼答案

    编辑:其他答案更好(使用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),否则它将失败)

  3. # 3 楼答案

    @artbristol的answer中您真正需要的唯一部分是这个(您可以将其设置为RestTemplateSpringbean):

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

    在那之后,我认为仅仅使用FileSystemResource作为请求主体将做正确的事情

    我还以这种方式成功地使用了InputStreamResource,用于您已经将数据作为InputStream使用并且不需要多次使用它的情况

    在我的例子中,我们压缩了文件并将GZipInputStream包装在InputStreamResource