Шаблон rest считывает ответ как поток и передается контроллеру Spring (получить InputStream с шаблоном rest)

У меня есть URL-адрес, по которому загружается zip-файл большого размера. Он возвращает ответ как поток. Хотя размер файла сначала большой, он возвращает 200(HTTPSTATUK.OK) и продолжает загрузку.

Мне нужно реализовать новый контроллер Spring, который вызывает указанный выше URL-адрес через шаблон отдыха. Я должен прочитать ответ, возвращаемый шаблоном отдыха, и перейти к контроллеру. Изначально я реализовал ниже

     @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, шаблон отдыха ожидает, пока весь файл не будет загружен в память. Поэтому очень часто у меня возникает проблема с тайм-аутом сокета.

Есть ли у нас способ прочитать ответ как поток и вернуться к контроллеру.

Я нашел несколько вещей о 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 контроллеру?

1 ответ

Решение

Нашел рабочую реализацию

Контроллер

    @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, контроллер загрузит файл, когда мы получим доступ в браузере.

Другие вопросы по тегам