0

我有一个下载大尺寸 zip 文件的 url。它以流的形式返回响应。虽然文件大小首先返回 200(HTTPSTATUK.OK) 并继续下载。

我必须实现一个新的spring控制器,它通过rest模板调用上面的url。我必须读取rest模板返回的响应并传递给控制器​​。最初我已经以下面的方式实现了

     @GetMapping("/export/downloadFile")
        public ResponseEntity<byte[]> downloadData(Model model,
                                                       @ModelAttribute(EXCEPTION_COLLECTOR) ExceptionCollector exceptionCollector,
                                                       @RequestParam("userName") String userName,
                                                       @RequestParam("startDate") Date startDate,
                                                       @RequestParam("endDate") Date endDate,
                                                       @RequestParam("reason") String reason) {

   URI uri = /building url here/;
    
    return restTemplate.exchange(uri, HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);
    
    }

因为我使用的是 ResponseEntity<byte[]> ,所以休息模板会等到整个文件加载到内存中。所以我经常遇到套接字超时问题。

我们是否有办法将响应作为流读取并返回到控制器。

我发现一些关于 restTemplate.execute 的事情。

restTemplate.execute(uri,HttpMethod.GET,requestCallBack,clientHttpResponse -> {
                File ret = File.createTempFile("download", ".zip",new File("/Users/bokkavijay/Desktop"));
                StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));
                return ret;
            });

上面的代码片段可以将文件复制到我们的本地而不会超时,但这不是我需要的。

我们如何将 clientHttpResponse 中的流通过管道传输到控制器?

4

1 回答 1

0

我找到了工作实现

控制器

    @GetMapping("/readResponseAsStream")
        public ResponseEntity<StreamingResponseBody> downloadAsStream(Model model,HttpServletResponse response) {

             HttpHeaders httpHeaders=new HttpHeaders();
             httpHeaders.add("Transfer-Encoding","chunked");
             httpHeaders.add("Content-Type","x-zip-compressed");
             httpHeaders.add("Content-Disposition", "attachment;filename=sample.zip");

            ServletOutputStream servletOutputStream=response.getOutputStream();

            StreamingResponseBody downloadFile = out -> {
                 

                      RequestCallback requestCallBack=request->{
                            request.getHeaders().add(//Add headers here);
                      };

                      ResponseExtractor<ServletOutputStream> responseExtractor = clientHttpResponse -> {

                              //code snippet if you want to write response stream to HttpServletResponse
                              byte[] buff = new byte[800000];
                              int bytesRead = 0;
                                  while ((bytesRead = clientHttpResponse.getBody().read(buff)) != -1) {
                                    servletOutputStream.write(buff, 0, bytesRead);
                                    }
                              return servletOutputStream;


                              //Incase if you want to copy file to you local
                               File ret = File.createTempFile("download", ".zip",new File("Add Local system directory address here"));
                               StreamUtils.copy(clientHttpResponse.getBody(), new FileOutputStream(ret));

                               //You can copy the the clientHttpResponse.getBody() to ByteArrayInputStream and return
                               // Don't return clientHttpResponse.getBody() directly because rest template will close the inputStream(clientHttpResponse.getBody()) after .execute completed

                               //if you want to write restTemplate.execute in dao layer , pass servletOutputStream as a argument to method

                              };

                   restTemplate.execute(URL_ADDRESS,HttpMethod.GET,requestCallBack,responseExtractor);


            };


            return new ResponseEntity(downloadFile,httpHeaders,HttpStatus.OK);
}

如果您直接将响应写入 HttpServletResponse ,控制器会在我们在浏览器中访问时下载文件

于 2020-10-12T07:02:05.387 回答