异步的多文件上传和文件存储代码

这一段代码是在工作之余自己练手玩的代码,因为不喜欢引入别人的js,就自己写一个jsp的页面,以后可以重用,界面上是达不到商业软件的标准了,但是功能还是实现了的。


这个异步的多文件上传初衷是为了上传图片,所以有个预览图这一栏。


<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<html>
	<head>
		<!-- 
			这是一个实现了多文件异步上传的html页面,因为用到了FileReader,所以需要对html5的支持
			相对应的浏览器有:
			Firefox (Gecko)	Chrome	Internet Explorer*	Opera*	Safari
			3.6 (1.9.2)	7	10			--	--
			
		 -->
		<meta http-equiv="content-type" content="text/html; charset=utf-8">
		<meta http-equiv="imagetoolbar" content="no">
		<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />
		<meta HTTP-EQUIV="pragma" CONTENT="no-cache">  
		<link href="Resources/axurerppage.css" type="text/css"
			rel="stylesheet">
		<style type="text/css">
			table {
				border-collapse: collapse;
			}
	
			tr,td,th {
				border: 1px solid #000000;
			}
			
			#verUploadTable {
				position: absolute;
				top: 10%;
				left: 15%;
			}
			
			.verUploadTable {
				width: 480px;
			}
			.Bar ,.Bars { 
		    	position: relative; 
		    	width: 400px;
				/* 宽度 */
				border: 1px solid #B1D632; 
				padding: 1px; 
			} 
			.Bar div,.Bars div { 
				display: block; 
				position: relative;
				/* 进度条背景颜色 */ 
				background:#0FF;
				color: #333333;
				height: 20px; 
				/* 高度 */ 
				line-height: 20px;  /* 必须和高度一致,文本才能垂直居中 */ 
			}
			.Bars div{ background:#090} 
			.Bar div span,.Bars div span { 
				position: absolute; 
				width: 400px; 
				/* 宽度 */ 
				text-align: center;
		 		font-weight: bold; 
	 		} 
	 		img{
	 			width:100px;
	 			height: 80px;
	 		}
		</style>

	</head>
	<body>
	<form name="hiddenForm" action="" enctype="multipart/form-data" method="post">
		<!--  <input type="file" id="uFile" style="display:none" οnchange="fileOnchange(this)">-->
		
	</form>
	<input type="hidden" id="uploadBasePath" value="<%=basePath%>">
	<input type="button" value="+添加文件" id="btnUpload" onClick="addFile()">
	<div>
		<div>
		</div>
			
		<div>
			<table id="fileListTable">
				<tr>
					<th width="100px">预览图(上传后)</th>
					<th width="400px">路径</th>
					<th width="250px">文本描述</th>
					<th width="200px">上传进度(已传/总大小)</th>
				</tr>
			</table>
		</div>
		<div>
		
		</div>
	</div>
		<input type="button" value="开始上传" οnclick="filesUpload()" />
	</body>
	<script type="text/javascript">
	//  author jacob_ye 20120924  in insigma
		var index = 1;
		var fileListTable = document.getElementById("fileListTable");
		var hiddenForm = document.hiddenForm;
	   function addFile(){
	   		var file_name = "file" + index;
	   		var input_file = document.createElement("input");
	   		input_file.setAttribute("type", "file");
	   		input_file.setAttribute("size", "50");
	   		input_file.setAttribute("name", file_name);
	   		input_file.setAttribute("hidden", "true");
	   		input_file.setAttribute("style","display:none ;");
	   		input_file.setAttribute("onchange", "fileOnchange(this)");
	   		input_file.setAttribute("accept", "image/*");//加一个文件类型的指定
			hiddenForm.appendChild(input_file);
			input_file.click();
			index =index + 1;
	   }
	   function fileOnchange(uFile){
	   		var fileName = uFile.name;
	   		var tr_file = document.createElement("tr");
	   		var td_file1 = document.createElement("td");//图预览(上传后)
	   		var td_file2 = document.createElement("td");//文件位置
	   		var td_file3 = document.createElement("td");//字节进度
	   		var td_file4 = document.createElement("td");//文本描述
	   		
	   		//创建各种Element
	   		var td1_img_file = document.createElement("img");
	   		
	   		var td2_span = document.createElement("span");
	   		var td2_div_Bar = document.createElement("div");
	   		var td2_div_2 = document.createElement("div");
	   		
	   		var td3_span_loaded = document.createElement("span");
	   		var td3_span_total = document.createElement("span");
	   		
	   		var td4_textarea = document.createElement("textarea");
	   		
	   		//给Element各种setAttribute
	   		td1_img_file.setAttribute("id", fileName+"_Img");
	   		td1_img_file.setAttribute("alt", "图片预览");
	   		td1_img_file.setAttribute("src", "#");
	   		
	   		td2_span.textContent = uFile.value;
	   		td2_div_2.setAttribute("id", fileName+"_path");
	   		td2_div_Bar.setAttribute("class", "Bar");
	   		
	   		td3_span_loaded.setAttribute("id", fileName +"_byteloaded");
	   		td3_span_total.setAttribute("id", fileName + "_bytetotal");
	   		td3_span_total.textContent = uFile.files[0].size;
	   		td3_span_loaded.textContent = "0";
	   		
	   		td4_textarea.setAttribute("id", fileName+"_alt");
	   		td4_textarea.setAttribute("rows", "3");
	   		td4_textarea.setAttribute("cols", "35");
	   		//单元格挂节点
	   		td_file1.appendChild(td1_img_file);
	   		
	   		td2_div_2.appendChild(td2_span);
	   		td2_div_Bar.appendChild(td2_div_2);
	   		td_file2.appendChild(td2_div_Bar);
	   		
	   		td_file3.style.width= "200px;";
	   		td_file3.appendChild(td3_span_loaded);
	   		td_file3.insertAdjacentText("beforeEnd","/");
	   		td_file3.appendChild(td3_span_total);
	   		
	   		td_file4.appendChild(td4_textarea);
	   		
	   		tr_file.appendChild(td_file1);
	   		tr_file.appendChild(td_file2);
	   		tr_file.appendChild(td_file4);
	   		tr_file.appendChild(td_file3);
	   		
	   		fileListTable.appendChild(tr_file);
	   }
	   
	   function filesUpload(){
	   		//getElementsByTagName确保files是[object NodeList]
	   		var input_files = hiddenForm.getElementsByTagName("input");
   			var length = input_files.length;
   			//var afile = input_files[0].files[0];
	   		//alert("go here 3");
	   		if(length > 0){
	   			for(var i=0;i<length;i++){
	   				var file = input_files[i].files[0];
	   				one_file_upload(file,input_files[i].name,input_files[i].value);
	   			}
	   		}else{
   				alert("please choose a file.");
   			}
	   }
	   
	   function one_file_upload(file,fileName,filePath){
		   	 // try sending 
		   	 // FileReader是HTML5的东东,所以需要HTML5的支持
			 var reader = new FileReader(); 
			 var fType = null;
			 //保存只需要读取一次的元素
			 var lodedByteSpan = document.getElementById(fileName+"_byteloaded");
			 var td_file = document.getElementById(fileName+"_path");
			 fType = filePath.substring(filePath.lastIndexOf("."), filePath.length);
			 var byteTotal = file.size;
			 // 这个事件在读取开始时触发
			 reader.onloadstart = function() { 
			 	console.log("onloadstart"); 
			 	document.getElementById(fileName+"_bytetotal").textContent = byteTotal;
			 } ;
			 // 这个事件在读取进行中定时触发
			 reader.onprogress = function(p) { 
				 console.log("onprogress"); 
				 lodedByteSpan.textContent = p.loaded; 
				 processRenderer(p.loaded, byteTotal,td_file);
			 } ;
			
			 // 这个事件在读取成功结束后触发
			 reader.onload = function() { 
			    console.log("load complete"); 
			 } ;
			 reader.onloadend = function() { 
			    	// 这个事件在读取结束后,无论成功或者失败都会触发
					 if (reader.error) { 
					 console.log(reader.error); 
					 } else { 
						 document.getElementById(fileName+"_bytetotal").textContent = file.size; 
						 // 构造 XMLHttpRequest 对象,发送文件 Binary 数据
						 var xhr = getXmlHttp(); 
						 var basePath = document.getElementById("uploadBasePath").value;
						 var imgAlt = document.getElementById(fileName+"_alt").value;
						 xhr.open(/* method */ "POST", 
						 /* target url */ "servlet/ImageServlet?fType="+fType+"&flag=imgUpload&uploadBasePath="+basePath+"&imgAlt="+imgAlt
						 /*, async, default to true */); 
						 xhr.overrideMimeType("application/octet-stream"); 
						 xhr.sendAsBinary(reader.result); 
						 xhr.onreadystatechange = function() { 
							 if (xhr.readyState == 4) { 
								 if (xhr.status == 200) { 
									 console.log("upload complete"); 
									 console.log("response: " + xhr.responseText); 
									 var responseText = xhr.responseText;
										if("false" == responseText){
											alert("上传错误");
										}else{
											//alert(responseText);//从pop框可以看到最后一个file路径返回的responseText返回了多次,为什么?
											document.getElementById(fileName+"_Img").src = responseText;
										}
							 		} 
							 } 
						 };
		 			} 
			 };
			 //try{
			 	//readAsBinaryString的好处是能够一次把一个完整的文件发送回去,缺点是处理大文件时,因为文件都存在浏览器内存中,
			 	//所以会导致大文件下,页面崩溃。所以此方法用来异步提交小文件是可以的。
			 	//QQ邮箱的超大附件做的异步提交,是用到了浏览器插件的支持。
			 	reader.readAsBinaryString(file); 
			 //}catch (err){
			 	//alert( err.description );
			 //}
	   }
	   
	   function getXmlHttp(){
	   		var xmlHttp = null;
	   		if (window.XMLHttpRequest) {
				//针对FirFox,Mozilla,Opera,Safari,IE7,IE8
				xmlHttp = new XMLHttpRequest();
				if (xmlHttp.overrideMimeType) {
					//针对Mozilla不同版本差别
					xmlHttp.overrideMimeType("text/xml");
				}
			} else if (window.ActiveXObject) {
				var activexml = [ "MSXML2.XMLHTTP", "Microsoft.XMLHTTP" ];
				for ( var i = 0; i < activexml.length; i++) {
					try {
						//取出一个空间进行创建,如果创建成功,则终止
						//如果创建失败,回抛出异常,然后继续循环,继续创建
						xmlHttp = new ActiveXObject(activexml[i]);
						break;
					} catch (e) {
	
					}
				}
			}
			return xmlHttp;
	   }
	   
	   function processRenderer(byteLoaded, byteTotal,td_file){
	   		var percent = byteLoaded / byteTotal;
	   		td_file.style.width = parseInt(percent * 100) +"%";
	   		//alert(parseInt(percent * 100) +"%");
	   }
	   
	   	//参考网页  http://royaltutorials.com/object-has-no-method-sendasbinary/
		//大概意思是,chrome浏览器下面的XMLHttpRequest没有sendAsBinary,所以就自己给XMLHttpRequest原型定义一个这样的属性,并且这个属性是一个方法
		if(!XMLHttpRequest.prototype.sendAsBinary){//如果XMLHttpRequest没有sendAsBinary
		  XMLHttpRequest.prototype.sendAsBinary = function(datastr) {
		    function byteValue(x) {
		      return x.charCodeAt(0) & 0xff;
		    }
		    var ords = Array.prototype.map.call(datastr, byteValue);
		    var ui8a = new Uint8Array(ords);
		    this.send(ui8a.buffer);
		  };
		}
</script>
</html>

文件存储的代码写得不好,就贴一部分吧:

/**
	 * 图片上传
	 * @param request
	 * @param response
	 * @throws ServletException
	 * @throws IOException
	 */
	private void imgUpload(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		String fileType = request.getParameter("fType");
		BufferedInputStream fin = new BufferedInputStream(request.getInputStream());
		
		//生成随机文件名
		String fileName = uuid.generate() + fileType;
		
		//path是本地路径
		String path = getURI() + "/uploadFolder/" + fileName;
		
		//uploadBasePath是从前台页面拿到的网页路径
		String uploadBasePath = request.getParameter("uploadBasePath");
		String imgAlt = request.getParameter("imgAlt");
		if(null != uploadBasePath && imgAlt != null){
			//url拼接出来以后是http://xxx.xxx.xxx/smdtx/uploadFolder/xxxx.jpg
			String url = uploadBasePath + "uploadFolder/" + fileName;
			PrintWriter out = response.getWriter();
			if(saveFile(fin,path)){//成功了就返回url给jsp页面
				Image img = new Image();
				img.setUrl(url);
				img.setAlt(imgAlt);
				try{
					imgDao.add(img);
					out.write(url);
					out.flush();
				}catch(Exception e){
					mLog.error(" method imgUpload() catch exception by " + e.getMessage());
					e.printStackTrace();
				}finally{
					if(out != null){
						out.close();
					}
				}
			}else{
				try{
					out.write("false");
					out.flush();
				}catch(Exception e){
					mLog.error(" method imgUpload() catch exception by " + e.getMessage());
					e.printStackTrace();
				}finally{
					if(out != null){
						out.close();
					}
				}
			}
		}
		
	}

/**
	 * 保存文件到本地
	 * @param in 输入流
	 * @param path 保存地址
	 * @return boolean 成功标识 
	 * @throws IOException
	 */
	private boolean saveFile(InputStream in,String path) throws IOException{
		File file = new File(path);
		byte[] buff = new byte[1024];
		int buffLength = -1;
		OutputStream out = null;
		boolean result = false;
		try{
			out = new FileOutputStream(file);
			while((buffLength = in.read(buff)) != -1){
				out.write(buff, 0, buffLength);
			}
			result = true;
		}catch(Exception e){
			mLog.error(" method saveFile() catch exception by " + e.getMessage());
			e.printStackTrace();
		}finally{
			if(out != null){
				out.close();
			}
		}
		return result;
	}

大概就是这个样子。自己有一个疑问,为什么最后一个file路径返回了多次?希望有经验的朋友能够留言解惑。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值