页面:这个页面我用的是原生的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/