我想创建包含我从后端收到的压缩文件的.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<File> 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文件
我不知道我还能做什么。我也尝试用以下内容替换ByteArrayOuputStream:
OutputStream outputStream = response.getOutputStream();
并将方法设置为 void ,因此它不返回任何内容,但是它创建了.zip文件,它被损坏了?
在解压缩 test.zip 后,在我的Macbook上,我收到了 test.zip.cpgz ,这又给了我test.zip文件等等。
在Windows上,.zip文件已损坏,因为我说并且甚至无法打开它。
我还想,自动删除.html扩展名将是最佳选择,但如何? 希望它没有像看起来那么难:)谢谢
答案 0 :(得分:26)
似乎已经解决了。我换了:
response.setContentType("application/zip");
使用:
@RequestMapping(value = "/zip", produces="application/zip")
现在我变得清晰,漂亮.zip文件:)
如果你们中的任何人有更好或更快的主张,或者只是想提出一些建议,那么请继续,我很好奇。
答案 1 :(得分:21)
@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();
}
答案 2 :(得分:2)
我正在使用REST Web Service
Spring Boot
我设计的端点始终返回ResponseEntity
,无论是JSON
还是PDF
还是ZIP
我提出了以下解决方案,该问题部分受到denov's answer
在此问题以及另一个question的启发,我在其中学习了如何将ZipOutputStream
转换为byte[]
的顺序将其作为端点的输出提供给ResponseEntity
。
无论如何,我创建了一个简单的实用工具类,其中包含pdf
和zip
文件下载的两种方法
@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);
}
}
现在,端点可以使用专为ResponseEntity<?>
或byte[]
量身定制的pdf
数据和自定义标头轻松返回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);
}
BinaryOutputWrapper
是我使用POJO
和private byte[] data;
创建的简单不可变org.springframework.http.HttpHeaders headers;
类作为字段,以便返回data
和{{1}来自实用方法。
答案 3 :(得分:-1)
@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();
});
}