Spring REST - create .zip file and send it to the client

后端 未结 4 935
借酒劲吻你
借酒劲吻你 2020-12-04 21:25

I want to create .zip file that contains my zipped files that I recieve from backend, and then send this file to the user. For 2 days I have been looking for the answer and

相关标签:
4条回答
  • 2020-12-04 22:01

    I am using REST Web Service of Spring Boot and I have designed the endpoints to always return ResponseEntity whether it is JSON or PDF or ZIP and I came up with the following solution which is partially inspired by denov's answer in this question as well as another question where I learned how to convert ZipOutputStream into byte[] in order to feed it to ResponseEntity as output of the endpoint.

    Anyway, I created a simple utility class with two methods for pdf and zip file download

    @Component
    public class FileUtil {
        public BinaryOutputWrapper prepDownloadAsPDF(String filename) throws IOException {
            Path fileLocation = Paths.get(filename);
            byte[] data = Files.readAllBytes(fileLocation);
    
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/pdf"));
            String outputFilename = "output.pdf";
            headers.setContentDispositionFormData(outputFilename, outputFilename);
            headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
    
            return new BinaryOutputWrapper(data, headers); 
        }
    
        public BinaryOutputWrapper prepDownloadAsZIP(List<String> filenames) throws IOException {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType("application/zip"));
            String outputFilename = "output.zip";
            headers.setContentDispositionFormData(outputFilename, outputFilename);
            headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
    
            ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
            ZipOutputStream zipOutputStream = new ZipOutputStream(byteOutputStream);
    
            for(String filename: filenames) {
                File file = new File(filename); 
                zipOutputStream.putNextEntry(new ZipEntry(filename));           
                FileInputStream fileInputStream = new FileInputStream(file);
                IOUtils.copy(fileInputStream, zipOutputStream);
                fileInputStream.close();
                zipOutputStream.closeEntry();
            }           
            zipOutputStream.close();
            return new BinaryOutputWrapper(byteOutputStream.toByteArray(), headers); 
        }
    }
    

    And now the endpoint can easily return ResponseEntity<?> as shown below using the byte[] data and custom headers that is specifically tailored for pdf or zip.

    @GetMapping("/somepath/pdf")
    public ResponseEntity<?> generatePDF() {
        BinaryOutputWrapper output = new BinaryOutputWrapper(); 
        try {
            String inputFile = "sample.pdf"; 
            output = fileUtil.prepDownloadAsPDF(inputFile);
            //or invoke prepDownloadAsZIP(...) with a list of filenames
        } catch (IOException e) {
            e.printStackTrace();
            //Do something when exception is thrown
        } 
        return new ResponseEntity<>(output.getData(), output.getHeaders(), HttpStatus.OK); 
    }
    

    The BinaryOutputWrapper is a simple immutable POJO class I created with private byte[] data; and org.springframework.http.HttpHeaders headers; as fields in order to return both data and headers from utility method.

    0 讨论(0)
  • 2020-12-04 22:22
    @RequestMapping(value="/zip", produces="application/zip")
    public void zipFiles(HttpServletResponse response) throws IOException {
    
        //setting headers  
        response.setStatus(HttpServletResponse.SC_OK);
        response.addHeader("Content-Disposition", "attachment; filename=\"test.zip\"");
    
        ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream());
    
        // create a list to add files to be zipped
        ArrayList<File> files = new ArrayList<>(2);
        files.add(new File("README.md"));
    
        // package files
        for (File file : files) {
            //new zip entry and copying inputstream with file to zipOutputStream, after all closing streams
            zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
            FileInputStream fileInputStream = new FileInputStream(file);
    
            IOUtils.copy(fileInputStream, zipOutputStream);
    
            fileInputStream.close();
            zipOutputStream.closeEntry();
        }    
    
        zipOutputStream.close();
    }
    
    0 讨论(0)
  • 2020-12-04 22:26

    seems to be solved. I replaced:

    response.setContentType("application/zip");
    

    with:

    @RequestMapping(value = "/zip", produces="application/zip")
    

    And now I get clear, beautiful .zip file :)

    If any of you have either better or faster proposition, or just want to give some advice, then go ahead, I am curious.

    0 讨论(0)
  • 2020-12-04 22:26
    @RequestMapping(value="/zip", produces="application/zip")
    public ResponseEntity<StreamingResponseBody> zipFiles() {
        return ResponseEntity
                .ok()
                .header("Content-Disposition", "attachment; filename=\"test.zip\"")
                .body(out -> {
                    var zipOutputStream = new ZipOutputStream(out);
    
                    // create a list to add files to be zipped
                    ArrayList<File> files = new ArrayList<>(2);
                    files.add(new File("README.md"));
    
                    // package files
                    for (File file : files) {
                        //new zip entry and copying inputstream with file to zipOutputStream, after all closing streams
                        zipOutputStream.putNextEntry(new ZipEntry(file.getName()));
                        FileInputStream fileInputStream = new FileInputStream(file);
    
                        IOUtils.copy(fileInputStream, zipOutputStream);
    
                        fileInputStream.close();
                        zipOutputStream.closeEntry();
                    }
    
                    zipOutputStream.close();
                });
    }
    
    0 讨论(0)
提交回复
热议问题