base64图片打成Zip包上传,以及服务端解压的简单实现
1、前言
上传图片一般采用异步上传的方式,但是异步上传带来不好的地方,就如果图片有改变或者删除,图片服务器端就会造成浪费。所以有时候就会和参数同步提交。笔者喜欢base64图片一起上传,但是图片过多时就会出现数据丢失等异常。因为tomcat的post请求默认是2M的长度限制。
2、解决办法
有两种:
① 修改tomcat的servel.xml的配置文件,设置 maxPostSize=“-1”,来取消post请求参数的限制
② 图片压缩层Zip文件,作为一个文件上传。(今天记录一下后者的简单编写)
3、依赖坐标
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.9.4</version>
</dependency>
这个依赖有点“重”,也可以选择其他第三方插件
4、上代码
@RequestMapping("/upload")
@ResponseBody
public JsonResult upload(@RequestParam("zipFile")MultipartFile zipFile) throws IOException{
// 获取上传的文件
CommonsMultipartFile commonsMultipartFile = (CommonsMultipartFile)zipFile;
/* // 将CommonsMultipartFile转化成java.io.File。 这里转化还可以使用tranferTo方法 DiskFileItem fileItem = (DiskFileItem)commonsMultipartFile.getFileItem(); // 生成的文件一般会存在内存中,超过阈值,会生成临时文件,文件不用时会自动删除,详见FileItemFfactory File file = fileItem.getStoreLocation(); */
// 上面的方法应用中可能会稍有问题,文件可能过早删除,导致找不到临时文件,故需要手动创建临时文件
// 创建临时文件夹
String rootPath = session.getServletContext().getRealPath("/");
File temDir = new File(rootPath + File.separator + UUID.randomUUID().toString().replaceAll("-", ""));
if(!temDir.exists()){
temDir.mkdirs();
}
File tempZip = new File(temDir, System.currentTimeMillis()+".tmp");
commonsMultipartFile .transferTo(tempZip);
// 这里的ZipFile为: org.apache.tools.zip.ZipFile jdk自带的ZipFile没有getEntries方法
ZipFile zipFile = new ZipFile(file);
Enumeration<ZipEntry> entries = zipFile.getEntries();
while(entries.hasMoreElements()){
ZipEntry zipEntry = entries.nextElement();
InputStream is = zipFile.getInputStream(zipEntry);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 使用IOUtils工具类
org.apache.commons.io.IOUtils.copy(is, bos);
is.close();
bos.close();
// 文件上传
String uploadFile = dfsService.uploadFile(bos.toByteArray(), zipEntry.getName());
System.out.println(uploadFile);
}
// 删除临时文件和文件夹
zipFile.close(); //zipFile是流文件,必须关闭才能删除文件和文件夹
if (tempZip != null) {
tempZip.delete();
}
temDir.delete();
return new JsonResult(true);
}
本文值只做了简单的实现,实际应用需要多种校验。
5、前端页面压缩的代码
使用zip包上传是为了减少传输的数量,这里使用jsZip这个前端工具实现打包,最终以二进制流的方式上传。
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>测试JSZIP</title>
</head>
<body>
<input type="file" id="file"/>
<img src="" id="image">
</body>
<script type="text/javascript" src="js/jquery-1.9.1.min.js"></script>
<script type="text/javascript" src="js/jszip.js"></script>
<script type="text/javascript" src="js/cropper.js"></script>
<script type="text/javascript" src="https://cdn.bootcss.com/FileSaver.js/2014-11-29/FileSaver.js"></script>
<script type="text/javascript">
$(function() {
$("#file").change(function () {
var file = this.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
var base64 = "";
reader.onload = function () {
var imgData = this.result;
$("#image").attr("src", imgData);
var zip = new JSZip();
// 向zip文件中添加图片,可以添加多个文件或者图片,此处以图片为例
// base64图片需要去掉base64图片标识
zip.file("car.jpg", imgData.substring(imgData.indexOf(",") + 1), {base64: true});
zip.generateAsync({
type: "blob", // 压缩类型
compression: "DEFLATE", // STORE:默认不压缩 DEFLATE:需要压缩
compressionOptions: {
level: 9 // 压缩等级1~9 1压缩速度最快,9最优压缩方式
// [使用一张图片测试之后1和9压缩的力度不大,相差100字节左右]
}
})
.then(function (content) {
// 压缩的结果为blob类型(二进制流),可用作文件上传
console.info(content);
// 直接在浏览器打成car.zip包并下载,saveAs依赖的js是FileSaver.js
saveAs(content, "car.zip");
});
}
});
});
</script>
</html>
6、注意事项
- 单张图片上传,ajax使用FormData以Blob或者File(Blob的更具体的实现)的形式,上传的时候会以binary(二进制字节流)的形式上传,使用MultipartFile对象接收,没有问题。
- 如果多张图片使用Blob[]上传,传递的参数会你变成[Object blob],后台无法使用MultipartFile接收参数,使用时注意!
7、参考文档
jsZip官方文档:JSZip
-- END