通用上传组件(ajaxFileUpload)

通用上传组件(单文件上传、HTML5批量文件上传)

适用场景:通用上传组件使用频次最高,大多数时候你需要使用它。

基本功能:可实现文件上传、结果回显。(本组件自身不能浏览曾经上传的图片)。

两次提交:一个表单有三个字段:姓名、年龄、照片,照片单独提交一次,把图片在服务端的存储路径返回,放在hidden控件中,与姓名、年龄再一次提交。

原理:ajaxFileUpload是一个Jquery插件,ajax不具备上传文件的能力,ajaxFileUpload通过使用js动态的创建一个隐藏iframe和上传表单实现了异步上传,并监听iframe的加载事件来接收返回数据。提供了近似于ajax的异步操作体验。

多文件上传:使用multiple属性可实现多文件上传,<input type="file" name="img" multiple="multiple" />  multiple 属性是 HTML5 中的新属性,浏览器要支持HTML5才可以,使用有局限。

相册上传组件(批量文件上传)

ajaxFileUpload只提供客户端,要自己开发服务端。

目的:

1.AjaxFileUpload进行上传,简单的上传,切图,验证大小,验证格式要求,一个jsp页面可以满足多个上传控件。

2.可以删除图片进行重新上上传

前提:

为了使去除图片x的位置能显示正确的位置需添加样式(static工程已经加入样式)

样式
/* 上传 */
.uploadCloseBtn{width: 16px;height: 16px;border: 0px solid #d7d7d7;border-radius:9px;text-align: center;
line-height: 15px;position: absolute;left: 91px;top:-6px;background: #ffffff;cursor: pointer;}
.uploadImgDiv{position: relative;margin-top: 10px;}


步骤:

1.上传界面需要引用:

<script type="text/javascript" src="${ctxStatic}/ajaxfileupload/ajaxfileupload.js"></script>

<script type="text/javascript" src="${ctxStatic}/fdp/upload.js"></script>

2.注意:

页面的样式可以按照各自页面的样式进行控制,下面实例没有那么死,可以随意变动

3.上传jsp详解(jsp):

jsp页面的属性(jsp详解)
  • aaa --》为第6行suffix属性的值,用于在一个页面中,区分多个上传控件
  • bbb --》0代表上传第1张,1代表 2张,3代表 2张...
行号 必填属性 目的 用法
4

class=“existSize_aaa”

value="已上传图片数量"

为了上传的时候知道还可以上传多少张图片,删除的动态控制

一个上传控件一个 input

5

上传控件需要添加这几个属性,id,name,type,thumbnail,tokenPath,suffix,allowType,fileSize,class, imageCount , multiple 在上传控件的位置

  • id                     默认:fileUpload_xxx        xxx为属性suffix的值,用于在一个页面中区分多个上传控件
  • name               默认: fileUpload(不可更改,这个服务端接受表单上传控件名)
  • type                 默认:file(不可更改)
  • thumbnail       上传图片的切图尺寸 (事例:100x100)
  • tokenPath       获取token(令牌)的地址,(示例:管理后台:${ctxa}/sys/sysToken/ getToken . do   商家中心:${ctxs}/sys/sysToken/getToken . htm)
  • suffix               id的后缀名
  • allowType 允许每个上传文件的扩展名,多个扩展名以逗号隔开
  • fileSize           允许 每个文件的上传大小限制(单位为byte)
  • class               默认:fileUploadClass (用于绑定事件)
  • imageCount   上传图片数量(如果不添加,默认为1;如果上传n张图片, 必须 添加本属性,值为n)
  • multiple          如果一次需要上传多个文件 必须 需要添加,如果上传一张图片不需要添加
上传控件 一个上传控件一个 input
6 class=“result_aaa”

服务器响应失败时给的错误提示

一个上传控件一个 div
7

class="uploadImgDiv"

id="img_aaa_bbb"

style="${not empty memberUser.headPicPath?'':'display:none;'}"--》判断当前图片有没有地址,如果没有隐藏起来

如果一个控件上传多张图片需要

7-14行进行复制多个, 改变bbb的值

8

class="imgPath"

name="headPicPath" --》表单的name属性

value="${memberUser.headPicPath}"--》图片地址

隐藏域为了存放上传图片的存储地址
9

class="result"

服务器响应成功时的给的提示

如果一个控件上传多张图片需要

7-14行进行复制多个,改变bbb的值

10

class="preview"

src="${ctxfs}${memberUser.headPicPath}@!100x100"--》图片地址

style="${not empty memberUser.headPicPath?'':'display:none;'}"--》 判断当前图片有没有地址,如果没有隐藏起来

img标签显示图片

如果一个控件上传多张图片需要

7-14行进行复制多个,改变bbb的值

11

class="uploadCloseBtn”

删除的图片div

如果删除按钮的x样式位置不对写这个样式进行调节style="left: 70px;top:14px;"

如果一个控件上传多张图片需要

7-14行进行复制多个,改变bbb的值

jsp上传实例
<div class="form-group">
	<label class="control-label col-sm-2" for="inputSuccess"> 会员头像&nbsp;:</label>
	<div class="col-sm-5">
		<input type="hidden" class="existSize_headPicPath" value="${not empty memberUser.headPicPath?'1':'0'}"/>
		<input id="fileUpload_headPicPath" name="fileUpload" type="file" thumbnail="100x100" tokenPath="${ctxa}/sys/sysToken/getToken.do" suffix="headPicPath" allowType="jpg,jpeg,png,bmp" fileSize="5242880" class="fileUploadClass"/>
		<div class="result_headPicPath"></div>
		<div class="uploadImgDiv" id="img_headPicPath_0" style="${not empty memberUser.headPicPath?'':'display:none;'}">
			<input type="hidden" class="imgPath" name="headPicPath" value="${memberUser.headPicPath}"/>
			<div class="result"></div>
			<img class="preview" src="${ctxfs}${memberUser.headPicPath}@!100x100" style="${not empty memberUser.headPicPath?'':'display:none;'}"/>
			<div class="uploadCloseBtn">
				<img alt="" src="${ctxStatic}/images/close.gif"/>
			</div>
		</div>
	</div>
	<div class="col-sm-5">
		<p class="help-block">会员头像尺寸要求宽度为120像素、高度为120像素,比例为1:1的图片;支持格式jpg,png。<p>
	</div>
</div>
upload.js
//文件异步上传
$(function(){
	//初始化、验证、取token
	function init() {
		var suffix = $(this).attr("suffix"); 						//获取id上传的后缀名
		if(suffix==null || suffix=='' || suffix==undefined){
			fdp.msg('缺少参数:后缀');
			return false;
		}
		var allowType = $(this).attr("allowType");					//获取上传文件的扩展名
		if(allowType==null || allowType=='' || allowType==undefined){
			fdp.msg('缺少参数:扩展名');
			return false;
		}
		var fileSize = $(this).attr("fileSize");					//获取上传的文件上传大小
		if(fileSize==null || fileSize=='' || fileSize==undefined){
			fdp.msg('缺少参数:文件大小');
			return false;
		}
		var tokenPath = $(this).attr("tokenPath");					//获取token的地址
		if(tokenPath==null || tokenPath=='' || tokenPath==undefined){
			fdp.msg('缺少参数:获取token地址');
			return false;
		}
		var thumbnail = $(this).attr("thumbnail");					//截取图片大小
		if(thumbnail==null || thumbnail=='' || thumbnail==undefined){
			fdp.msg('缺少参数:截图尺寸');
			return false;
		}
		var existSizeSuffix = $(".existSize_"+suffix).val();		//已上传图片数量
		if(existSizeSuffix==null || existSizeSuffix=='' || existSizeSuffix==undefined){
			fdp.msg('缺少参数:已上传图片数量');
			return false;
		}
		var imageCount = $(this).attr("imageCount");				//允许图片数量(上传数量默认为1)
		if(imageCount==null || imageCount=='' || imageCount==undefined){
			imageCount = 1;
		}
		var token=null;							
		$.ajax({													//ajax获取token							
			  type: 'post',
			  url: tokenPath,
			  dataType: 'json',
			  success: function(data){
				  token=data.token;
				  ajaxFileUpload(suffix,allowType,fileSize,thumbnail,existSizeSuffix,imageCount,token);
			  },
			  error: function(data){
				  return false;
			  }
		});
	}
	
	//给file控件挂上传事件
	$('.fileUploadClass').change(init);
	
	//清理input type="file" 的值
	function clearFile(suffix){
		/*var file = $('#fileUpload_'+suffix) 
		file.after(file.clone().val("")); 
		file.remove(); */
	}
	
	function ajaxFileUpload (suffix,allowType,fileSize,thumbnail,existSizeSuffix,imageCount,token){
		$.ajaxFileUpload({
			url : ctxu + "/common/ajaxfileupload.htm?token="+token,	// 默认为post请求
			secureuri : false, 										// 是否启用安全提交,默认为false
			fileElementId:'fileUpload_' + suffix ,					//文件选择框的id属性
			method:'POST',											//文件post提交
			data:{format:'json','__fileUpload':'1'},				//告诉服务器请给我返回json格式的数据,spring mvc内容协商支持本参数
			dataType:'json',										//本组件按什么格式接收服务器返回的数据,可以是json或xml等,空表示直接返回data
			fileSize:fileSize,										//文件大小限制,可选,0 为无限制(IE浏览器不兼容) 
			allowType:allowType,									//可选,限定上传文件的格式
			success : function(data) {
				if(data[0].errMsg){
					$('.result_' + suffix).html(data[0].errMsg);
				}else if(data[0].errorToken!=null || data[0].errorToken!=null || data[0].errorToken!=undefined){
					$('.result_' + suffix).html(data[0].errorToken);
				}else{
					for(var i = 0;i < data.length;i++){
						if(data[i].fileStorageName !=null && data[i].fileStorageName !="" && data[i].fileStorageName !=undefined){
							for(var j = 0;j < imageCount;j++){
								var size = $('.existSize_' + suffix).val();//取已上传图片数量
								size = parseInt(size);
								if(size >= imageCount){
									clearFile(suffix);
									fdp.msg("最多只能上传"+imageCount+"张");
									return;
								}
								var imgpath = $('#img_'+ suffix +'_'+ + j).find(".imgPath").val();
								if(imgpath==null || imgpath=='' || imgpath==undefined){
									$('#img_'+ suffix +'_'+ + j).find(".result").html(data[i].errorMsg);//文件上传后的提示语
									$('#img_'+ suffix +'_'+ + j).find(".preview").attr("src",ctxfs+data[i].fileStorageName+"@!"+thumbnail);//给img标签赋图片地址
									$('#img_'+ suffix +'_'+ + j).find(".imgPath").val(data[i].fileStorageName);//给图片地址隐藏域赋值
									$('#img_'+ suffix +'_'+ + j).find(".preview").css("display","");
									$('#img_'+ suffix +'_'+ + j).css("display","");
									$('.existSize_' + suffix).val(1 + size);//改变已上传图片数量
									break;
								}
							}
						}else{
							$('#img_'+ suffix +'_'+ + j).find(".preview").css("display","");
							$('#img_'+ suffix +'_'+ + j).find(".result").html(data[i].errorMsg);//上传图片的错误提示
						}
					}
				}
				clearFile(suffix); 
			},
			complete:function(){
				//给file控件再次挂上传事件
				$('.fileUploadClass').change(init); 
	        },
			error : function(data) {
				// 服务器响应失败时的处理函数
				$('.result_' + suffix).html('上传失败,请重试!!');	
			}
		});
	}
	
	//移除图片
	$(".uploadCloseBtn").click(function(){
		var attrId = $(this).parent().attr('id');
		var attrIds = attrId.split("_");
		$(this).parent().find(".imgPath").val("");//清除图片地址隐藏域
		var existSize = $('.existSize_' + attrIds[1]).val();
		var size = parseInt(existSize);
		$('.existSize_' + attrIds[1]).val(size-1);//改变已上传图片数量
		$(this).parent().find(".preview").attr("src","");
		$(this).parent().find(".result").html("");
		$(this).parent().css("display","none");
	});
	
});


上传代码(ajaxfileupload.js):

ajaxfileupload.js
 /*
 * ajaxFileUpload.js 无刷新上传图片 jquery 插件,支持 ie6-ie10
 * 依赖:jquery-1.6.1.min.js
 * 主方法:ajaxFileUpload 接受 json 对象参数 
 * 参数说明: 
 * 	  fileElementId:必选,上传文件域ID 
 * 	  url:必选,发送请求的URL字符串 
 * 	  allowType:可选,限定上传文件的格式(.jpg,.bmp,.gif,.png) 
 * 	  fileSize:可选,0 为无限制(IE浏览器不兼容) 
 *    dataType:本组件按什么格式接收服务器返回的数据,可以是json或xml等,空表示直接返回data
 * 	  data:可选,将和文件域一同post的参数(json对象) ,data:{format:'json'},告诉服务器请给我返回json格式的数据
 * 	  其它:$.ajax 的参数均为可选参数 
 * 	  注:如遇到'无法访问'的脚本错误提示则需要在响应流中加一段脚块一同输出:<script ...>document.domain = 'xxx.com';</script> 
 */
jQuery.extend({
	//创建 iframe 元素,接受提交及响应  
	createUploadIframe : function(id, uri) {
		//create frame  
		var frameId = 'jUploadFrame' + id;
		if (window.ActiveXObject) {
			//fix ie9 and ie 10-------------  
			if (jQuery.browser.version == "9.0" || jQuery.browser.version == "10.0") {
				var io = document.createElement('iframe');
				io.id = frameId;
				io.name = frameId;
			} else if (jQuery.browser.version == "6.0" || jQuery.browser.version == "7.0" || jQuery.browser.version == "8.0") {
				var io = document.createElement('<iframe id="' + frameId + '" name="' + frameId + '" />');
				if (typeof uri == 'boolean') {
					io.src = 'javascript:false';
				} else if (typeof uri == 'string') {
					io.src = uri;
				}
			}
		} else {
			var io = document.createElement('iframe');
			io.id = frameId;
			io.name = frameId;
		}
		io.style.position = 'absolute';
		io.style.top = '-1000px';
		io.style.left = '-1000px';
		document.body.appendChild(io);
		return io;
	},
	//创建 from 元素,用于提交的表单  
	createUploadForm : function(id, fileElementId, postData) {
		//create form<span style="white-space:pre">   </span>  
		var formId = 'jUploadForm' + id;
		var fileId = 'jUploadFile' + id;
		var form = $('<form  action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');
		var oldElement = $('#' + fileElementId);
		var newElement = $(oldElement).clone();
		$(oldElement).attr('id', fileId);
		$(oldElement).before(newElement);
		$(oldElement).appendTo(form);
		//添加自定义参数  
		if (postData) {
			//递归遍历JSON所有键值  
			function recurJson(json) {
				for ( var i in json) {
					//alert(i+"="+json[i])  
					$("<input name='" + i + "' id='" + i + "' value='" + json[i] + "' />").appendTo(form);
					if (typeof json[i] == "object") {
						recurJson(json[i]);
					}
				}
			}
			recurJson(postData);
		}
		//set attributes  
		$(form).css('position', 'absolute');
		$(form).css('top', '-1200px');
		$(form).css('left', '-1200px');
		$(form).appendTo('body');
		return form;
	},
	//上传文件  
	//s 参数:json对象  
	ajaxFileUpload : function(s) {
		s = jQuery.extend({
			allowType : "",
			fileSize : 0
		}, jQuery.ajaxSettings, s);
		//文件筛选  
		var fielName = $('#' + s.fileElementId).val();
		var extention = fielName.substring(fielName.lastIndexOf(".") + 1).toLowerCase();
		if (s.allowType && s.allowType.indexOf(extention) < 0) {
//			layer.msg("仅支持 (" + s.allowType + ") 为后缀名的文件!", {
//				icon : 2
//			});
			layer.msg("仅支持 (" + s.allowType + ") 为后缀名的文件!");
			$(".loading").css("display","none");
			return;
		}
		//文件大小限制  
		if (s.fileSize > 0) {
			var fs = 0;
			try {
				if (window.ActiveXObject) {
					//IE浏览器  
					var image = new Image();
					image.dynsrc = fielName;
					fs = image.fileSize;
				} else {
					fs = $('#' + s.fileElementId)[0].files[0].size;
				}
			} catch (e) {
			}
			if (fs > s.fileSize) {
				layer.msg("当前文件大小 (" + (fs/1024/1024).toFixed(2) + "M) 超过允许的限制值 (" + (s.fileSize/1024/1024).toFixed(2) + "M)!");
				//layer.msg("当前文件大小 (" + fs/1024000 + "M) 超过允许的限制值 (" + s.fileSize/1024000 +"M)!", {icon: 2});
				$(".loading").css("display","none");
				return;
			}
		}
		var id = new Date().getTime();
		//创建 form 表单元素  
		var form = jQuery.createUploadForm(id, s.fileElementId, s.data);
		//创建 iframe 贞元素  
		var io = jQuery.createUploadIframe(id, s.secureuri);
		var frameId = 'jUploadFrame' + id;
		var formId = 'jUploadForm' + id;
		//监测是否有新的请求  
		if (s.global && !jQuery.active++) {
			jQuery.event.trigger("ajaxStart"); //触发 AJAX 请求开始时执行函数。Ajax 事件。  
		}
		var requestDone = false;
		//创建请求对象  
		var xml = {};
		if (s.global)
			jQuery.event.trigger("ajaxSend", [ xml, s ]); //触发 AJAX 请求发送前事件  
		//上载完成的回调函数  
		var uploadCallback = function(isTimeout) {
			var io = document.getElementById(frameId);
			try {
				//存在跨域脚本访问问题,如遇到'无法访问'提示则需要在响应流中加一段脚块:<script ...>document.domain = 'xxx.com';</script>  
				if (io.contentWindow) { //兼容各个浏览器,可取得子窗口的 window 对象  
					xml.responseText = io.contentWindow.document.body ? io.contentWindow.document.body.innerHTML : null;
					xml.responseXML = io.contentWindow.document.XMLDocument ? io.contentWindow.document.XMLDocument : io.contentWindow.document;
				} else if (io.contentDocument) { //contentDocument Firefox 支持,> ie8 的ie支持。可取得子窗口的 document 对象。  
					xml.responseText = io.contentDocument.document.body ? io.contentDocument.document.body.innerHTML : null;
					xml.responseXML = io.contentDocument.document.XMLDocument ? io.contentDocument.document.XMLDocument : io.contentDocument.document;
				}
			} catch (e) {
				jQuery.handleErrorExt(s, xml, null, e);
			}
			if (xml || isTimeout == "timeout") {
				requestDone = true;
				var status;
				try {
					status = isTimeout != "timeout" ? "success" : "error";
					// Make sure that the request was successful or notmodified  
					if (status != "error") {
						//处理数据(运行XML通过httpData不管回调)  
						var data = jQuery.uploadHttpData(xml, s.dataType);
						// If a local callback was specified, fire it and pass it the data  
						if (s.success){
							try{
								//调用成功回调函数
								s.success(data, status);
							}catch(e){
								//本组件用户写的成功回调函数发生了异常
								alert("开发者你好,你编写的success函数生成异常,请你自行修复。"+e);
							}
						}
						// Fire the global callback  
						if (s.global)
							jQuery.event.trigger("ajaxSuccess", [ xml, s ]);
					} else
						jQuery.handleErrorExt(s, xml, status);
				} catch (e) {
					status = "error";
					jQuery.handleErrorExt(s, xml, status, e);
				}
				// The request was completed  
				if (s.global)
					jQuery.event.trigger("ajaxComplete", [ xml, s ]);
				// Handle the global AJAX counter  
				if (s.global && !--jQuery.active)
					jQuery.event.trigger("ajaxStop");
				// Process result  
				if (s.complete)
					s.complete(xml, status);
				jQuery(io).unbind();
				setTimeout(function() {
					try {
						$(io).remove();
						$(form).remove();
					} catch (e) {
						jQuery.handleErrorExt(s, xml, null, e);
					}
				}, 100);
				xml = null;
			}
		};
		//超时检查,s.timeout 毫秒后调用 uploadCallback 回调函数提示请求超时  
		if (s.timeout > 0) {
			setTimeout(function() {
				// Check to see if the request is still happening  
				if (!requestDone)
					uploadCallback("timeout");
			}, s.timeout);
		}
		try {
			//设置动态 form 表单的提交参数  
			// var io = $('#' + frameId);  
			var form = $('#' + formId);
			$(form).attr('action', s.url);
			$(form).attr('method', 'POST');
			$(form).attr('target', frameId);
			if (form.encoding) {
				form.encoding = 'multipart/form-data';
			} else {
				form.enctype = 'multipart/form-data';
			}
			$(form).submit();
		} catch (e) {
			jQuery.handleErrorExt(s, xml, null, e);
		}
		//向动态表单的页面加载事件中注册回调函数  
		if (window.attachEvent) {
			document.getElementById(frameId).attachEvent('onload', uploadCallback);
		} else {
			document.getElementById(frameId).addEventListener('load', uploadCallback, false);
		}
		return {
			abort : function() {
			}
		};
	},
	//上传文件  
	uploadHttpData : function(r, type) {
		//alert("type=" + type + ";uploadHttpData" + JSON.stringify(r))  
		var data = !type;
		data = type == "xml" || data ? r.responseXML : r.responseText;
		// If the type is "script", eval it in global context  
		if (type == "script") {
			jQuery.globalEval(data);
		}
		// Get the JavaScript object, if JSON is used.  
		if (type == "json") {
			//alert(data + " " + jQuery.type(data));
			if (jQuery.type(data) === "string") {
				var b1 = data.indexOf(">") != -1;
				var b2 = data.indexOf("<") != -1;
				var b3 = data.toLowerCase().indexOf("pre") != -1;
				if (b1 && b2 && b3) {
					data = jQuery.parseJSON(jQuery(data).text());//去掉<pre>标签,转成json对象
				} else {
					data = jQuery.parseJSON(data);//转成json对象
				}
			}
			//eval("data = " + data);//原始代码
		}
		// evaluate scripts within html  
		if (type == "html") {
			jQuery("<div>").html(data).evalScripts();
		}
		return data;
	},
	handleErrorExt : function(s, xhr, status, e) {
		// If a local callback was specified, fire it  
		if (s.error) {
			s.error.call(s.context || s, xhr, status, e);
		}
		// Fire the global callback  
		if (s.global) {
			(s.context ? jQuery(s.context) : jQuery.event).trigger("ajaxError", [ xhr, s, e ]);
		}
	}
});