我看了很多網上的demo,先生成ZIP壓縮文件,然后再下載。
我這里是生成ZIP文件流 進行下載。(核心代碼沒多少,就是一些業務代碼)
@RequestMapping(value = "/")
public ResponseEntity<byte[]> downloadInterviewFile() throws Exception {
// 根據面試官主鍵編碼 下載文件
List<InterviewFile> interviewFiles = this.interviewFileService.getAll(interviewfile);
ByteArrayOutputStream byteOutPutStream = null;
if (!interviewFiles.isEmpty()) {
//單個文件名稱
String interviewFileName = "";
//文件后綴
String fileNameSuffix = "";
//創建一個集合用於 壓縮打包的參數
List<Map<String, String>> parms = new ArrayList<>();
//創建一個map集合
Map<String, String> fileMaps =null;
//得到存儲文件盤符 例 D:
String root = properties.getValue("upload.root");
//創建一個字節輸出流
byteOutPutStream = new ByteArrayOutputStream();
for (InterviewFile file : interviewFiles) {
fileMaps = new HashMap<>();
interviewFileName = file.getFileName();
fileNameSuffix = file.getFileSuffix();
//將單個存儲路徑放入
fileMaps.put("filePath", root.concat(file.getFilePath()));
//將單個文件名放入
fileMaps.put("fileName", interviewFileName.concat("." + fileNameSuffix));
//放入集合
parms.add(fileMaps);
}
//壓縮文件
FileUtils.batchFileToZIP(parms, byteOutPutStream);
}
HttpHeaders headers = new HttpHeaders();
String fileName = null;
try {
fileName = new String("附件.zip".getBytes("UTF-8"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", fileName);// 文件名稱
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(byteOutPutStream.toByteArray(), headers, HttpStatus.CREATED);
return responseEntity;
}

工具類
@RequestMapping(value = "/")
public ResponseEntity<byte[]> downloadInterviewFile() throws Exception {
// 根據面試官主鍵編碼 下載文件
List<InterviewFile> interviewFiles = this.interviewFileService.getAll(interviewfile);
ByteArrayOutputStream byteOutPutStream = null;
if (!interviewFiles.isEmpty()) {
//單個文件名稱
String interviewFileName = "";
//文件后綴
String fileNameSuffix = "";
//創建一個集合用於 壓縮打包的參數
List<Map<String, String>> parms = new ArrayList<>();
//創建一個map集合
Map<String, String> fileMaps =null;
//得到存儲文件盤符 例 D:
String root = properties.getValue("upload.root");
//創建一個字節輸出流
byteOutPutStream = new ByteArrayOutputStream();
for (InterviewFile file : interviewFiles) {
fileMaps = new HashMap<>();
interviewFileName = file.getFileName();
fileNameSuffix = file.getFileSuffix();
//將單個存儲路徑放入
fileMaps.put("filePath", root.concat(file.getFilePath()));
//將單個文件名放入
fileMaps.put("fileName", interviewFileName.concat("." + fileNameSuffix));
//放入集合
parms.add(fileMaps);
}
//壓縮文件
FileUtils.batchFileToZIP(parms, byteOutPutStream);
}
HttpHeaders headers = new HttpHeaders();
String fileName = null;
try {
fileName = new String("附件.zip".getBytes("UTF-8"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", fileName);// 文件名稱
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(byteOutPutStream.toByteArray(), headers, HttpStatus.CREATED);
return responseEntity;
}

調用看不懂?那來個簡單粗暴的
@RequestMapping(value = "/")
public ResponseEntity<byte[]> downloadInterviewFile() throws Exception {
// ---------------------------壓縮文件處理-------------------------------
ByteArrayOutputStream byteOutPutStream = new ByteArrayOutputStream();
// 創建一個集合用於 壓縮打包的參數
List<Map<String, String>> parms = new ArrayList<>();
// 創建一個map集合
Map<String, String> fileMaps = new HashMap<>();
fileMaps.put("filePath", "D:/文件路徑");
fileMaps.put("fileName", "HRM-Package.txt");
Map<String, String> fileMaps1 = new HashMap<>();
fileMaps1.put("filePath", "D:/文件路徑1");
fileMaps1.put("fileName", "java.txt");
// 放入集合
parms.add(fileMaps);
parms.add(fileMaps1);
// 壓縮文件
FileUtils.batchFileToZIP(parms, byteOutPutStream);
// ---------------------------壓縮文件處理-------------------------------
HttpHeaders headers = new HttpHeaders();
String fileName = null;
try {
fileName = new String("附件.zip".getBytes("UTF-8"), "ISO-8859-1");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
headers.setContentDispositionFormData("attachment", fileName);// 文件名稱
ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(byteOutPutStream.toByteArray(), headers,
HttpStatus.CREATED);
return responseEntity;
}

結果:
======================我是分割線======================
這個例子給我了我很大的幫助,因為他是利用ResponseEntity進行下載的,這個下載工具類很好,但是網上一般的例子是基於File的而不是基於byte[]數組的,我的文件是存到數據庫中的,文件是用byte[]數組存儲的,程序猿一定要深刻理解ZipOutputStream在壓縮中的處理關鍵,話不多說,我直接上我改造的代碼工具類
注:FileBank類只有兩個屬性fileName、fileBlob
public class ZipDownloadUtils {
/**
* 文件批量壓縮
*
* @param parms
*/
public static void batchFileToZIP(List<FileBank> parms, ByteArrayOutputStream byteOutPutStream) { ZipOutputStream zipOut = new ZipOutputStream(byteOutPutStream); try { for (FileBank value : parms) { // 使用指定名稱創建新的 ZIP 條目 (通俗點就是文件名) ZipEntry zipEntry = new ZipEntry(value.getFileName()); // 開始寫入新的 ZIP 文件條目並將流定位到條目數據的開始處 zipOut.putNextEntry(zipEntry); //直接寫入到壓縮輸出流中即可 zipOut.write(value.getFileBlob()); zipOut.closeEntry(); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { try { zipOut.close(); } catch (IOException e) { e.printStackTrace(); } } } /** * ResponseEntity下載文件 * * @param fileName * @param byteOutPutStream */ public static ResponseEntity<byte[]> downloadZIP(String fileName, ByteArrayOutputStream byteOutPutStream) { //下載文件 //String fileName = "批量下載【備案材料】.zip"; HttpHeaders headers = new HttpHeaders(); try { fileName = new String("附件.zip".getBytes("UTF-8"), "ISO-8859-1"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } headers.setContentType(MediaType.APPLICATION_OCTET_STREAM); headers.setContentDispositionFormData("attachment", fileName);// 文件名稱 ResponseEntity<byte[]> responseEntity = new ResponseEntity<byte[]>(byteOutPutStream.toByteArray(), headers, HttpStatus.CREATED); return responseEntity; } }

Controller中代碼很簡單:
//壓縮文件
ByteArrayOutputStream byteOutPutStream = new ByteArrayOutputStream();
ZipDownloadUtils.batchFileToZIP(dataList, byteOutPutStream); //dataList是一個List<FileBank> //下載文件 String fileName = "批量下載【備案材料】.zip"; return ZipDownloadUtils.downloadZIP(fileName, byteOutPutStream);

最后:之所以總結這篇筆記是因為想要用最優雅的代碼完成一個文件壓縮下載的功能,網上很多用HttpServletResponse原生下載的例子,實在接受不了這么丑陋的代碼(可讀性奇差,不好維護和修改,通用性很差,代碼量太大,等等各種問題不一而足),故而記下此文,即完成了任務又優雅(一個不追求優雅代碼的程序員不是好程序員!!!)的實現了,終於可以安心睡覺了……
===============================================================================