頁面:這個頁面我用的是原生的table來產生表格的
//選擇好需要下載的文件后,觸發事件的按鈕
<input type="button" value="批量下載" onclick="batchDownLoad()">
...
<c:forEach items="${list}" var="fileItem">
<tr>
<td>
//后台將文件的服務器路徑傳到這
<input id="filePath" value="${fileItem.filePath}" type="hidden">
//后台將文件的名稱傳到這
<input id="fileName" value="${fileItem.fileName}" type="hidden">
//這個是為了這里沒什么用,不過如果到時候需要定為到這個位置,就可以寫上
<input id="${fileItem.id}" value="${fileItem.id}" type="hidden">
//這是一個選擇需要下載的復選框
<input id="selectIds" value="${fileItem.id}" type="checkbox">
</td>
</tr>
</c:forEach>
...
js部分,這里需要模擬用form表單提交,切記不要用ajax請求,不然瀏覽器就不會接收到后台傳過來的文件流,就不能下載了
function batchDownLoad() {
var selectIds = [];
$("input[name='selectIds']:checked").each(function () {
selectIds.push($(this).val());
});
if (selectIds.length<1){
$("#errorMsg").text("請至少選擇一條信息下載");
return false;
} else {
$("#errorMsg").text("");
}
if (confirm("是否批量下載?")) {
var filePaths = [];
var fileNames = [];
for (var i in selectIds){
var filePath = $("#"+selectIds[i]).parent().find("input:eq(0)").val();
var fileNameTemp = $("#"+selectIds[i]).parent().find("input:eq(1)").val();
var fileName = encodeURIComponent(fileNameTemp);
filePaths.push(filePath);
fileNames.push(fileName);
}
//模擬form表單提交
var url = "${ctx}/commom/fileBatch/fileDownLoadBatch";
var form = $("<form></form>").attr("action",url).attr("method","post");
form.append($("<input></input>").attr("type","hidden").attr("name","fileNames").attr("value",fileNames.toString()));
form.append($("<input></input>").attr("type","hidden").attr("name","filePaths").attr("value",filePaths.toString()));
form.appendTo('body').submit().remove();
}
}
3.后台處理
package com.etc.test;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.sql.Savepoint;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Controller
@RequestMapping(value = "${xxx}/commom/fileBatch")
public class FileDownLoadBatchController {
private final static String ZIP_NAME = "file.zip";//下載的文件壓縮包名稱
@RequestMapping(value = "/fileDownLoadBatch")
public void fileDownLoadBatch(String[] filePaths, String[] fileNames, HttpServletRequest request, HttpServletResponse response){
//下載的文件壓縮包名稱
String tmpFileName = ZIP_NAME;
/*
1.臨時文件的存放位置,這個是對頁面中想要下載的文件,但是該文件服務器中已經不存在了,所以需要創建一個空的文件給用戶,且對該文件提示已經不存在了,還有將所有問價進行打包后的壓縮包存放的臨時位置
2.這個位置最好自己先在項目中臨時創建一個目錄,里面放一份文件,用來提示其他程序員說該目錄不要刪除(放上一份提示的文件還可以在自己測試的時候看該目錄有沒有被編譯出來,因為空的目錄是不會在target中出現的,到時候自己看的時候可能就會被自己誤解了),不過如果你不放的話,可以先判斷下這個目錄是否存在,不存在的話,就創建個.我是在webapp下創建了一個臨時目錄,代碼如下
String filePathTemp = session.getServletContext().getRealPath("/")+"tempDir"
用這個記得在該方法的參數里加上HttpSession session
*/
String filePathTemp = "臨時文件的存放位置,自己設置,記得是服務器的位置";
byte[] buffer = new byte[1024];
try {
//創建臨時壓縮包new FileOutputStream("臨時壓縮包的絕對路徑")
ZipOutputStream out = new ZipOutputStream(new FileOutputStream(filePathTemp+ File.separator+tmpFileName));
//下載的文件集合
for (int i = 0;i<filePaths.length;i++){
String fileName = java.net.URLDecoder.decode(fileNames[i],"UTF-8");
File file = new File(getRealPath(filePaths[i],fileName));
if(file.exists()){//文件存在
FileInputStream fis = new FileInputStream(getRealPath(filePaths[i],fileName));
out.putNextEntry(new ZipEntry(fileName));
//設置壓縮文件內的字符編碼,不然會變成亂碼
out.setEncoding("GBK");
int len;
//讀取需要下載的文件內容,打包到zip文件
while ((len = fis.read(buffer))>0){
out.write(buffer,0,len);
}
out.closeEntry();
fis.close();
}else {//文件不存在
File fileTemp = new File(filePathTemp + File.separator + "文件已被刪除" + fileName);
fileTemp.createNewFile();
FileInputStream fis = new FileInputStream(filePathTemp + File.separator + "文件已被刪除" + fileName);
out.putNextEntry(new ZipEntry("文件已被刪除" + fileName));
//設置壓縮文件內的字符編碼,不然會變成亂碼
out.setEncoding("GBK");
int len;
//讀取需要下載的文件內容,打包到zip文件
while ((len = fis.read(buffer)) > 0){
out.write(buffer,0,len);
}
out.closeEntry();
fis.close();
fileTemp.delete();//清楚臨時創建的文件
}
}
out.close();
//將壓縮包返回給界面和刪除臨時創建的壓縮包.上面的步驟只是將文件打包而已,並沒有傳到瀏覽器,下面的這一步才是向瀏覽器傳輸文件流
SaveAs(filePathTemp+File.separator+tmpFileName,tmpFileName,request,response);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 獲取目標文件的絕對路徑
* @param filePath
* @param fileName
* @return
*/
private String getRealPath(String filePath,String fileName){
return filePath+File.separator+fileName;
}
/**
* 將壓縮包返回給界面和刪除臨時創建的壓縮包
* @param filePath
* @param fileName
* @param request
* @param getResponse
*/
public void SaveAs(String filePath,String fileName,HttpServletRequest request,HttpServletResponse getResponse){
try {
File file = new File(filePath);
//設置交由瀏覽器處理
request.getHeader("User-Agent").toUpperCase();
getResponse.setHeader("Content-Disposition","attachment;filename=\""+new String(fileName.getBytes(),"ISO8859-1")+"\"");
getResponse.setContentType("application/zip");
// 讀取文件
InputStream ins = new FileInputStream(filePath);
// 獲取文件輸出IO流
// 讀取目標文件,通過response將目標文件寫到客戶端
OutputStream outs = getResponse.getOutputStream();
//寫文件
int byteRead = 0;
byte[] buffer = new byte[8192];
//開始向網絡傳輸文件流
while ((byteRead = ins.read(buffer))>0){
outs.write(buffer,0,byteRead);
}
outs.flush();//這里一定要調用flush()方法
ins.close();
outs.close();
//刪除臨時創建的壓縮包
file.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
詳細的配置信息可以參考我寫的這篇文章:http://blog.ncmem.com/wordpress/2019/08/28/net%e6%96%87%e4%bb%b6%e6%89%b9%e9%87%8f%e4%b8%8b%e8%bd%bd/