网站首页 > java教程 正文
一:场景:
项目中需要做批量下载图片的功能。
思路一:后台拿到图片信息再循环的方式,实践后发现行不通,只能下载第一个文件。
原因:当第一次输出流关闭后请求结束,链接关闭,后续的循环已无意义。
思路二:后台不行就在前台进行循环,多次请求。实践后发现还是行不通,仍只能下载一个文件。
原因:没想明白希望大佬看到告知,感谢!
思路三:没办法只能将多个文件压缩后返回,实践成功。
原理:
1.创建压缩流写到服务器上的压缩文件(临时文件)
2.把服务器上要下载的多个文件写入该压缩文件
3.把压缩文件通过输出流传输给客户端(注意:必须在zipoutputstream流关闭后,否则下载下的文件会报不可预料的压缩文件末端)
4.删除服务器上的临时文件
二:遇到的问题:
1.一开始使用ajax请求方式传送请求,即使后台不报错浏览器也没有进行下载操作?
解释:因为response的原因,一般请求浏览器是会处理服务器输出的response,文件的下载是以二进制形式进行的。但是ajax请求只是个“字符型”的请求,即请求的内容是以文本类型存放的。所以虽然可以读取到返回的response,但只是读取而已,是无法执行的,说白点就是js无法调用到浏览器的下载处理机制和程序。
解决:
window.location.href = "/imgUpload/imgdownload?names="+names+"&paths="+paths;
2.使用ajax传输数组到后台时,后台接收到的值为null
解决:添加traditional : true
解释:jQuery需要调用jQuery.param序列化参数,默认traditional为false,就是说jquery会深度序列化参数对象,但servelt api无法处理深度序列化的参数对象,所以通过设置traditional 为true阻止深度序列化。
3.通过window.location.href拼接数组参数时向后台传递会报错。
解决:先对参数进行编码后再传递var paths = encodeURI(encodeURI(imgUrlList));后台配合解码可以获得编码前的内容
后端解码:String realFileName = java.net.URLDecoder.decode(names[i],"UTF-8");
原因:传递的参数中包含特殊的字符,不符合url的规范,所以先对其进行编码。值得一提的是编码后可以直接传递数组。
之后就是后台代码的编写了
4.返回文件名中文乱码。
response.setHeader( "Content-Disposition", "attachment;filename=" + new String( fileName.getBytes("gb2312"), "ISO8859-1" ) );
单文件:
public void downImg(HttpServletResponse response,String filename,String path ){
if (filename != null) {
FileInputStream is = null;
BufferedInputStream bs = null;
OutputStream os = null;
try {
File file = new File(path);
if (file.exists()) {
//设置Headers
response.setHeader("Content-Type","application/octet-stream");
//设置下载的文件的名称-该方式已解决中文乱码问题
response.setHeader("Content-Disposition","attachment;filename=" + new String( filename.getBytes("gb2312"), "ISO8859-1" ));
is = new FileInputStream(file);
bs =new BufferedInputStream(is);
os = response.getOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while((len = bs.read(buffer)) != -1){
os.write(buffer,0,len);
}
}else{
String error = Base64Util.encode("下载的文件资源不存在");
response.sendRedirect("/imgUpload/imgList?error="+error);
}
}catch(IOException ex){
ex.printStackTrace();
}finally {
try{
if(is != null){
is.close();
}
if( bs != null ){
bs.close();
}
if( os != null){
os.flush();
os.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
多文件下载:下载的是zip格式
前段js代码+后端controller代码
/**
* 图片下载
*/
function downloadimg() {
//获取所有被选的图片的名称与绝对路径放入数组
var list = $(".activecheck");
var imgNameList = [];
var imgUrlList = [];
for(var i = 0;i<list.length;i++){
var b = $(list[i].childNodes[2]).attr("data-url");
imgNameList.push(list[i].childNodes[3].innerText);//图片名称
imgUrlList.push(b);//图片绝对路径
}
var paths = encodeURI(encodeURI(imgUrlList));
var names = encodeURI(encodeURI(imgNameList));
//将名称传入后台
window.location.href = "/imgUpload/imgdownload?names="+names+"&paths="+paths;
}
/**
* 下载
* @param response
*/
@RequestMapping(value = "/imgdownload", method = RequestMethod.GET)
public void imgDownload(@SessionAttribute(MyInterceptor.SESSION_KEY) SessionInfo info,HttpServletResponse response,String [] names,String [] paths) {
//存放--服务器上zip文件的目录
String directory = "D:\\repository\\"+info.getName();
File directoryFile=new File(directory);
if(!directoryFile.isDirectory() && !directoryFile.exists()){
directoryFile.mkdirs();
}
//设置最终输出zip文件的目录+文件名
SimpleDateFormat formatter = new SimpleDateFormat("yyyy年MM月dd日HH时mm分ss秒");
String zipFileName = formatter.format(new Date())+".zip";
String strZipPath = directory+"\\"+zipFileName;
ZipOutputStream zipStream = null;
FileInputStream zipSource = null;
BufferedInputStream bufferStream = null;
File zipFile = new File(strZipPath);
try{
//构造最终压缩包的输出流
zipStream = new ZipOutputStream(new FileOutputStream(zipFile));
for (int i = 0; i<paths.length ;i++){
//解码获取真实路径与文件名
String realFileName = java.net.URLDecoder.decode(names[i],"UTF-8");
String realFilePath = java.net.URLDecoder.decode(paths[i],"UTF-8");
File file = new File(realFilePath);
//TODO:未对文件不存在时进行操作,后期优化。
if(file.exists())
{
zipSource = new FileInputStream(file);//将需要压缩的文件格式化为输入流
/**
* 压缩条目不是具体独立的文件,而是压缩包文件列表中的列表项,称为条目,就像索引一样这里的name就是文件名,
* 文件名和之前的重复就会导致文件被覆盖
*/
ZipEntry zipEntry = new ZipEntry(realFileName);//在压缩目录中文件的名字
zipStream.putNextEntry(zipEntry);//定位该压缩条目位置,开始写入文件到压缩包中
bufferStream = new BufferedInputStream(zipSource, 1024 * 10);
int read = 0;
byte[] buf = new byte[1024 * 10];
while((read = bufferStream.read(buf, 0, 1024 * 10)) != -1)
{
zipStream.write(buf, 0, read);
}
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭流
try {
if(null != bufferStream) bufferStream.close();
if(null != zipStream){
zipStream.flush();
zipStream.close();
}
if(null != zipSource) zipSource.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//判断系统压缩文件是否存在:true-把该压缩文件通过流输出给客户端后删除该压缩文件 false-未处理
if(zipFile.exists()){
downImg(response,zipFileName,strZipPath);
zipFile.delete();
}
}
猜你喜欢
- 2024-10-21 Spring WEB工程整合使用FTP,ftp文本文件解析入库,文件上传下载
- 2024-10-21 使用SFTP跟服务器传输文件(怎么用sftp上传文件到服务器)
- 2024-10-21 Ubuntu 下安装 JDK17(ubuntu中安装jdk)
- 2024-10-21 JasperReport生成pdf文件 Java开发pdf文件 pdf文件生成及下载
- 2024-10-21 用JavaEE实现前后台交互的文件上传与下载,适合小白入门练手!
- 2024-10-21 JAVA 大文件上传解决方案(500M以上)
- 2024-10-21 《数据结构与算法分析Java语言描述》PDF文件免费下载
- 2024-10-21 CDH安装系统环境准备——系统版本和安装包下载地址指南
- 2024-10-21 jar文件怎么打开(base.apk.1文件怎么打开)
- 2024-10-21 Java 实现 FastDFS 实现文件的上传、下载、删除
你 发表评论:
欢迎- 07-21如何将 iPhone 中的联系人导出到 Excel/CSV?
- 07-21sql查询的字段数据中有逗号。放到csv文件会分开,如何解决?
- 07-21在 WebAPI 里生成 csv zip 文件(webapi怎么发布在iis上)
- 07-21如何把csv格式转换成Excel格式(csv格式怎么转换)
- 07-21如何将高程导出为XYZ或CSV高程点(如何将高程数据导入cad)
- 07-21使用python把csv汇总成excel(python怎么将csv文件中的列存入列表)
- 07-21解决PHP导出CSV文件中文乱码问题(php导出excel文件)
- 07-21使用vba将Excel 文件转成 CSV 文件
- 最近发表
-
- 如何将 iPhone 中的联系人导出到 Excel/CSV?
- sql查询的字段数据中有逗号。放到csv文件会分开,如何解决?
- 在 WebAPI 里生成 csv zip 文件(webapi怎么发布在iis上)
- 如何把csv格式转换成Excel格式(csv格式怎么转换)
- 如何将高程导出为XYZ或CSV高程点(如何将高程数据导入cad)
- 使用python把csv汇总成excel(python怎么将csv文件中的列存入列表)
- 解决PHP导出CSV文件中文乱码问题(php导出excel文件)
- 使用vba将Excel 文件转成 CSV 文件
- python爬虫25 | 爬取的数据怎么保存?CSV了解一下
- MySQL 导出数据(mysql 导出数据 判断成功)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)