Web端的批量下载图片实战
因为客户提需求必须要图片的批量下载功能,只能硬着头皮做,公司还没有前端,好吧…前后端一条龙操作。毕竟第一次做批量下载图片,懵逼在所难免,整整花了3天,走了不少弯路,一定要记录下来。
首先,如何实现批量下载功能。我的第一反应就是,获取一堆Id然后依次下载。
就像这样一个一个点,立马推翻思路。(这就不叫批量操作了)
我试了在后台接收所有要下载的id,然后用for循环。可是前端一下子就收不到这么多图片的二进制流,好吧,又放弃了。
还有使用别人1.写好的插件去用,我在网上搜到一大堆,一是不会用,二是我不想用别人写的东西。
最后终于锁定了用将图片在2.后台打成压缩包的方法。
说说批量下载的原理,这个在网上不好搜。
Java代码
1.从前端获取需要的数据;(可以是唯一标识ID,或者是一个查询条件,反正能让你在后台找到像要的数据就行)
2.生成一组Map,key是文件名,value是文件的二进制数据byte[ ];(byte[ ]是通过文件对象转成数组的)
//自己写一个FileUitl工具类
public static byte[] readToByte(File file) throws IOException {
long length = file.length();
if (length > Integer.MAX_VALUE)
throw new IOException("file too large");
byte[] b = null;
InputStream in = null;
try {
b = new byte[(int) length];
in = new FileInputStream(file);
int offset = 0, nRead = 0;
while (offset < b.length
&& (nRead = in.read(b, offset, b.length - offset)) != -1)
offset += nRead;
} catch (Exception e) {
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {
}
}
return b;
}
//根据code值获取下载的图片
String paras=request.getParameter("codes");
String[] codes=paras.split(",");
//文件名-字节数组的形式
Map<String, byte[]> files = new HashMap<String, byte[]>();
//循环生成key-value
for(int i=0;i<codes.length;i++){
//查询数据库,获得实体
Picture picture =pictureService.queryEntityForUnique(Convert.toMap("code", codes[i]));
String imgType=picture.getPorig().split("\\.")[1];
//获取文件名,key
String packageName=picture.getTi()+"."+imgType;
File file = new File(Profile.path() + File.separator+ picture.getPorig().replace(File.separator, "/"));
//File转byte[ ]
byte[ ] f=FileUitl.readFile(file);
//二进制数据,value
f = FileUtil.readToByte(file);
}
3.通过IO流将压缩包输出到浏览器
//设置下载的压缩包名
String zipName = new Date().getTime() + ".zip";
//根据文件,进行压缩,批量下载
if(files.size() > 0){
downloadBatchByFile(response, files, zipName);
}
4.生成压缩文件的方法
/**
* 根据文件,进行压缩,批量下载
* @param response
* @param files
* @throws Exception
*/
private void downloadBatchByFile(HttpServletResponse response, Map<String, byte[]> files, String zipName){
try{
//设置响应消息头
response.setContentType("application/x-msdownload");
response.setHeader("content-disposition", "attachment;filename="+URLEncoder.encode(zipName, "utf-8"));
//输出、输入流
ZipOutputStream zos = new ZipOutputStream(response.getOutputStream());
BufferedOutputStream bos = new BufferedOutputStream(zos);
for(Entry<String, byte[]> entry : files.entrySet()){
String fileName = entry.getKey(); //每个zip文件名
byte[] file = entry.getValue(); //这个zip文件的字节
BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(file));
zos.putNextEntry(new ZipEntry(fileName));
int len = 0;
byte[] buf = new byte[10 * 1024];
while( (len=bis.read(buf, 0, buf.length)) != -1){
bos.write(buf, 0, len);
}
bis.close();
bos.flush();
}
bos.close();
}catch(Exception e){
e.printStackTrace();
}
}
前端 JQuery
1.通过复选框获取标识;
2.发送请求.
// 全选或反选
var $all = $('input[name="pic-all"]').click(function() {
$item.prop('checked', $(this).is(':checked')).trigger('change');
});
var $item = $('input[name="pic-item"]').click(function() {
if ($item.length == $('input[name="pic-item"]:checked').length)
!$all.is(':checked') && $all.prop('checked', true).trigger('change');
else
$all.is(':checked') && $all.prop('checked', false).trigger('change');
});
$('.btn-imgDownload').click(function() {
// 选择图片
var $picChecked = $('input[name="pic-item"]:checked');
if ($picChecked.length == 0) {
dialog.tips('未选中图片');
return false;
}
// 选择图片代码
var flag = $(this).attr('name'), codes = '';
$picChecked.each(function() {
codes += $(this).val() + ',';
});
/* 批量下载 */
$.ajax({
async:false,
url: 'picture/downloadMany/check.html',
data: 'codes='+codes,
dataType: 'json',
cache: false,
/* beforeSend: function() {
dialog.tips('正在提交...', 60, 'loading.gif');
}, */
success: function(series) {
if (series.status) {
var title = '确认总共消耗 ' + series.msg + ' 点积分下载原图?';
dialog.confirm(title, function() {
// 消耗积分下载
location.href = 'picture/downloadMany.html?codes='+ codes +'&score='+ series.msg ;
});
} else {
dialog.tips(series.msg);
}
}
});
});
效果
通过选择目标,经过后台,前台,最后生成压缩包。