关于项目:
后端采用SpringMVC框架,前端用到jQuery-1.9.1-min.js、jquery.form.js,可以满足同时上传多个文本内容和多个文件,上传速度快,并且兼容IE8、9,Chrome等主流浏览器。
需求背景:
需要上传多条商品记录,每条记录包含多个文本说明和一个图片文件。
前期思考
上传图片到服务器有两种做法,
一、是把图片转换为Base64字符串,与文本信息一同通过json形式传给后台,后台解析保存图片。
二、利用MultipartFile实现多文件上传
显而易见,转为Base64后图片体积会变大,当上传多张图片时,速度特别缓慢。因此此处讲述的是利用MultipartFile实现多文件上传。
但不管是哪种方式上传图片,我们都是把图片保存入服务器的指定路径,最终存入数据库的只是图片文件的保存路径,而不是图片本身。
<form id="uploadForm" method="post" enctype="multipart/form-data”>
<table>
<tr>
<input type="text" id="text1" name="text"/>
<input type="file" id="file1" name="file"/>
<input type="text" id="text2" name="text"/>
<input type="file" id="file2" name="file"/>
<input type="text" id="text3" name="text"/>
<input type="file" id="file3" name="file"/>
<input type="button" id="submit" value="上传" onclick="uploadSubmit()">
</tr>
</table>
</form>
<script>
function uploadSubmit(){
var formData = new FormData(document.getElementById('uploadForm'));
$.ajax({
url:"uploadFiles",
type:"post",
data:formData,
dataType:"json",
processData:false,//必须要写
contentType:false,//必须要写
success:function(result){
console.log(result);
}
});
}
</script>
这里演示一个文本框对应一个图片文件的示例,可以根据实际需求改动。多文件时,建议name属性一致,后端可以根据相同的name属性获取文件列表
注意:
1、new FormData(document.getElementById(‘uploadForm’) )不能写成new FormData($(“#uploadForm”)) ,jQuery和原生节点在这有所差别。
2、ajax上传时:一定要设置processData:false ,contentType:false,否则会报错:Illegal invocation
由于FormData+ajax的方式并不兼容IE8,故此使用jquery.form方式。只需要引入jquery.form.js文件后,修改 uploadSubmit() 方法
function uploadSubmit(){
$("#uploadForm").ajaxSubmit({
url:"uploadFiles",
type:"post",
dataType:"json",
async:false,
success:function(result){
console.info(result);
}
});
}
但是当使用ajaxSubmit上传文件,后台返回json数据时,IE8会提示要下载json文件。
解决办法:后端不返回’application/json’类型数据,而改返回’text/html’类型给前端。注意把ajax的’dataType:json’属性去掉。
后端使用到MultipartFile需要添加commons-io.jar、commons-fileupload.jar依赖,否则取值为null
并在applicationContext.xml文件进行注册:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize">
<value>10485760value>
property>
<property name="defaultEncoding">
<value>UTF-8value>
property>
bean>
@ResponseBody
@RequestMapping("/uploadFiles")
public String uploadFiles(MultipartFile file,String text,HttpServletRequest request){
try {
//图片保存路径:/tomcat/webapps/项目名/
String sysPath=request.getSession().getServletContext().getRealPath("");
if(file!=null){
//此处是将文本+图片原文件名作为图片的新文件名
String fileName=text+file.getOriginalFilename();
File filePath=new File(sysPath,fileName);
if(!filePath.getParentFile().exists()){
filePath.getParentFile().mkdirs();
}
//System.out.println("文件名:"+fileName+" ----- "+filePath.getPath());
BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(filePath));
out.write(image.getBytes());
out.flush();
out.close();
}else{
return "no file";
}
} catch (FileNotFoundException e) {
}catch(IOException e){
}
return "success";
}
@ResponseBody
@RequestMapping("/uploadFiles")
public String uploadFiles(MultipartFile[] file,String[] text,HttpServletRequest request){
try {
//图片保存路径:/tomcat/webapps/项目名/
String sysPath=request.getSession().getServletContext().getRealPath("");
if(file!=null&&file.length>0){
for(int i=0;i<file.length;i++){
MultipartFile image=file[i];
//此处是将文本+图片原文件名作为图片的新文件名
String fileName=text[i]+image.getOriginalFilename();
File filePath=new File(sysPath,fileName);
if(!filePath.getParentFile().exists()){
filePath.getParentFile().mkdirs();
}
System.out.println("文件名:"+fileName+" ----- "+filePath.getPath());
BufferedOutputStream out=new BufferedOutputStream(new FileOutputStream(filePath));
out.write(image.getBytes());
out.flush();
out.close();
}
}else{
return "failure";
}
} catch (FileNotFoundException e) {
}catch(IOException e){
}
return "success";
}
注意:
1、按照上述文件保存路径是:/tomcat/webapps/项目名/test.jsp ,那么当tomcat服务器重启后,图片将会被清除。因为tomcat重启会重新部署应用。因此建议换一个文件保存路径。
2、当前端没选择文件时(也就是空文件),IE8、9后台接收数据和chrome、IE11等其他浏览器表现不同,会把空文件计入个数,其他浏览器则只会接受非空文件。
因此,后台使用multipartFile.isEmpty( )判断文件是否为空。
自此,文件上传的模块就结束啦。走过很多弯路,之前为了兼容IE8,考虑用base64上传文件,速度非常之慢。但也算是吃一堑长一智。具体用base64怎么上传图片,有空再贴出来吧~