文件上传是一个非常常用的组件,遍布在各种系统中,但是好用的上传组件却很难找到(如果有成熟好用的,请不吝赐教)。
最近,做一个系统,恰好修改了三个版本的文件上传,纯web实现,没有flash其他技术。这里整理出来,分享给大家。如果高手有发现问题,尽情喷,也欢迎大家一起探讨。
文件上传中的问题
文件上传本来只是html提供的一个简单组件,直接可以伴随form的提交上传到服务器,但是,我们实际的应用中,经常会遇到一个表单中有许多的文件上传,这个时候如果和表单的属性类字段一起提交,会造成页面长时间没相应,这会带来非常差的用户体验,用户可能会以为服务器无响应,中途刷新页面,造成很多无端的服务器负载。
如何解决这个问题那,一般是这样处理,给文件上传组件添加一个上传按钮,每次单击按钮,就创建一个隐藏的form和一个隐藏iframe,并且form的target指向iframe。把文件上传组件挪动隐藏form中去提交。然后,判断iframe的返回内容。这个也是我这里所说三剑客共同的处理方式。
后台文件存储
本文主要来说明,上传文件在服务器后台也已文件的方式来独立存储的解决方法。文件存储成功后,会返回后台存储的路径信息,作为前台页面的字段值。
下面先把图给上来(有图有真像~_~)
初始时界面:
上传成功后界面:
大概就是上面的效果了,下面开始粘贴代码。
代码
html代码:
<table>
<tr>
<th>样例数据</th>
<td><!-- 只要在一个标签中即可,其他无限制 -->
<input type="file" name="upfile" />
<input type="button" classify="exampleDataFile" action="mvc/attachment/add" value="上传" style=""/>
<input type="button" name="reUpload" value="重新上传" style="display:none;"/>
<font color="red">*</font>
<input type="hidden" id="exampleDataFile" name="exampleDataFile" value="" />
</td>
</tr>
</table>
JavaScript代码:(补充一句,本来打算clone的形式,但是发现file复制后原来的选择就变空了)
//upload file
if($("input[action]").length>0){
$('body').append('<div id="hdiv" style="display:none;"></div>');
}
$("input[action]").click(function(){
//anchor
var btn=$(this);
var uploadFile=btn.siblings('input[type=file]');
//非空判断
if(!uploadFile.val()){
alert("请选择要上传的文件,然后点击上传!");
return false;
}
//第一次时候,form和iframe都需要插入
if($('#f'+btn.attr('classify')).length<=0){
//拼接出文件提交节点
var hForm='<form method="post" enctype="multipart/form-data" action="'+btn.attr('action')+'" id="f'+btn.attr('classify')
+'" name="f'+btn.attr('classify')+'" target="t'+btn.attr('classify')+'">'
+'<input type="hidden" name="classify" value="'+btn.attr('classify')+'" />'
+'</form>';
//拼接出target iframe
var hFrame='<iframe name="t'+btn.attr('classify')+'" id="t'+btn.attr('classify')+'"></iframe>';
//添加到文档中
$('#hdiv').append(hForm).append(hFrame);
}
//上传组件移动到form下
uploadFile.appendTo($('#f'+btn.attr('classify')));
$('#f'+btn.attr('classify')).submit();
//上传成功后标识
$('#t'+btn.attr('classify')).on('load',function(){
var result=this.contentWindow.result;
//把上传组件放回
uploadFile.insertBefore(btn);
if(!result){
alert("上传后台错误,请刷新页面重试,如依旧报错,请联系管理员!");
return ;
}
if(result.result=='success'){
btn.siblings('input[name="reUpload"]').show();
btn.siblings('input[type="hidden"]').val(result.filePath);
//隐藏原来的控件
btn.hide();
uploadFile.val('').attr('src','');
uploadFile.hide();
//提示信息
btn.siblings('font').html('已上传,文件路径:'+result.filePath);
}else{
alert("上传失败,"+result.message);
}
});
});
//reUpload绑定事件
$('input[name="reUpload"]').click(function(){
var btn=$(this).siblings('input[action]');
var uploadFile=$(this).siblings('input[type=file]');
uploadFile.val('').show();
$(this).hide();
btn.show();
});
后台,我这边是用Java+springMvc,其他的都是类似的,举一反三吧
/**
* 存放目录形式的上传文件
* @param request
* @param classify
* @param upfile
* @return
*/
@RequestMapping(value="/add", method = RequestMethod.POST)
public String add(HttpServletRequest request, @RequestParam("classify") String classify,
@RequestParam("upfile") MultipartFile upfile){
String saveName=StringUtils.genUploadFileName(classify, StringUtils.getExtention(upfile.getOriginalFilename()));
String savePath=request.getSession().getServletContext().getRealPath("/upload")
+"/"+DateUtil.getCurrent(DateUtil.FULL_DATE_PURE)+"/";
// System.out.println("--->"+upfile.getOriginalFilename());
//如果目录不存在则创建目录
File dir=new File(savePath);
if(!dir.exists()){
dir.mkdir();
}
//保存文件
try {
upfile.transferTo(new File(savePath+saveName));
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
//成功后返回内容
request.setAttribute("result", "success");
request.setAttribute("message", "上传成功");
request.setAttribute("filePath", "upload/"+DateUtil.getCurrent(DateUtil.FULL_DATE_PURE)+"/"+saveName);
return "uploadResult";
}
后台返回结果页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<base href="<%=basePath%>">
<script type="text/javascript">
result={
"result": '${result}',
"message": '${message}',
"filePath": '${filePath}'
}
</script>
</head>
<body>
</body>
</html>
上面的代码就javascript比较麻烦,其他的都很容易看懂,javascript的原理其实上面都有说明了,也不可能逐行说明,请自行阅读定制。