Spring REST – 创建.zip文件并将其发送到客户端

我想创建包含我从后端收到的压缩文件的.zip文件,然后将此文件发送给用户。 2天我一直在寻找答案,找不到合适的解决方案,也许你可以帮助我:)

现在,代码是这样的:(我知道我不应该在spring控制器中完成所有操作,但不关心它,它只是为了测试目的,找到让它工作的方法)

@RequestMapping(value = "/zip") public byte[] zipFiles(HttpServletResponse response) throws IOException{ //setting headers response.setContentType("application/zip"); response.setStatus(HttpServletResponse.SC_OK); response.addHeader("Content-Disposition", "attachment; filename=\"test.zip\""); //creating byteArray stream, make it bufforable and passing this buffor to ZipOutputStream ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(byteArrayOutputStream); ZipOutputStream zipOutputStream = new ZipOutputStream(bufferedOutputStream); //simple file list, just for tests ArrayList files = new ArrayList(2); files.add(new File("README.md")); //packing 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(); } if (zipOutputStream != null) { zipOutputStream.finish(); zipOutputStream.flush(); IOUtils.closeQuietly(zipOutputStream); } IOUtils.closeQuietly(bufferedOutputStream); IOUtils.closeQuietly(byteArrayOutputStream); return byteArrayOutputStream.toByteArray(); } 

但问题是,使用代码,当我输入URL:localhost:8080 / zip我得到文件:test.zip.html而不是.zip文件

当我删除.html扩展名并只留下test.zip时,它会正确打开如何避免返回此.html扩展名? 为什么要添加?

我不知道我还能做什么。 我也尝试用以下方法替换ByteArrayOuputStream:

 OutputStream outputStream = response.getOutputStream(); 

并将该方法设置为void所以它什么都不返回,但是它创建了.zip文件,它被损坏了?

在解压缩test.zip之后我的macbook上我得到了test.zip.cpgz ,它再次给了我test.zip文件等等。

在Windows上,.zip文件被破坏了,因为我说,甚至无法打开它。

我也认为,自动删除.html扩展名将是最佳选择,但如何? 希望它没有像看起来那么难:)谢谢

似乎已经解决了。 我换了:

 response.setContentType("application/zip"); 

有:

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

现在我变得清晰,漂亮.zip文件:)

如果你们中的任何人有更好或更快的主张,或者只是想提出一些建议,那么请继续,我很好奇。

 @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 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(); } 

我正在使用Spring Boot REST Web Service ,我设计了端点以始终返回ResponseEntity无论是JSON还是PDFZIP ,我想出了以下解决方案,这部分灵感来自denov's answer在这个问题中denov's answer以及另一个问题在那里我学习了如何将ZipOutputStream转换为byte[] ,以便将它作为端点的输出提供给ResponseEntity

无论如何,我创建了一个简单的实用程序类,有两种pdfzip文件下载方法

 @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 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); } } 

现在,端点可以使用专门为pdfzip定制的byte[]数据和自定义标头轻松返回ResponseEntity ,如下所示。

 @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); } 

BinaryOutputWrapper是一个简单的不可变POJO类,我用private byte[] data;创建private byte[] data;org.springframework.http.HttpHeaders headers; 作为字段,以便从实用程序方法返回dataheaders