需求來源是這樣的:上傳一個很大的excel文件到server, server會解析這個excel, 然后一條一條的插入到數據庫,整個過程要耗費很長時間,因此當用戶點擊上傳之后,需要顯示一個進度條,并且能夠根據后臺的接收的數據量和處理的進度及時更新進度條。
分析:后臺需要兩個組件,uploadController.jsp用來接收并且處理數據,它會動態的把進度信息放到session,另一個組件processController.jsp用來更新進度條;當用戶點“上傳”之后,form被提交給uploadController.jsp,同時用js啟動一個ajax請求到processController.jsp,ajax用獲得的進度百分比更新進度條的顯示進度,而且這個過程每秒重復一次;這就是本例的基本工作原理。
現在的問題是server接收數據的時候怎么知道接收的數據占總數據的多少? 如果我們從頭自己寫一個文件上傳組件,那這個問題很好解決,關鍵是很多時候我們都是用的成熟的組件,比如apache commons fileupload; 比較幸運的是,apache早就想到了這個問題,所以預留了接口可以用來獲取接收數據的百分比;因此我就用apache commons fileupload來接收上傳文件。
uploadController.jsp:
- <%@?page?language="java"?import="java.util.*,?java.io.*,?org.apache.commons.fileupload.*,?org.apache.commons.fileupload.disk.DiskFileItemFactory,?org.apache.commons.fileupload.servlet.ServletFileUpload"?pageEncoding="utf-8"%>??
- <%??
- //注意上面的import的jar包是必須的 ??
- //下面是使用apache?commons?fileupload接收上傳文件; ??
- FileItemFactory?factory?=?new?DiskFileItemFactory();??
- ServletFileUpload?upload?=?new?ServletFileUpload(factory);??
- //因為內部類無法引用request,所以要實現一個。 ??
- class?MyProgressListener?implements?ProgressListener{??
- ????private?HttpServletRequest?request?=?null;??
- ????MyProgressListener(HttpServletRequest?request){??
- ????????this.request?=?request;??
- ????}??
- ????public?void?update(long?pBytesRead,?long?pContentLength,?int?pItems)?{??
- ????????double?percentage?=?((double)pBytesRead/(double)pContentLength);??
- ????????//上傳的進度保存到session,以便processController.jsp使用 ??
- ????????request.getSession().setAttribute("uploadPercentage",?percentage);??
- ????}??
- }??
- upload.setProgressListener(new?MyProgressListener(request));??
- List?items?=?upload.parseRequest(request);??
- Iterator?iter?=?items.iterator();??
- while?(iter.hasNext())?{??
- ????FileItem?item?=?(FileItem)?iter.next();??
- ????if?(item.isFormField()){??
- ??????????
- ????}?else?{??
- ????????//String?fieldName?=?item.getFieldName(); ??
- ????????String?fileName?=?item.getName();??
- ????????//String?contentType?=?item.getContentType(); ??
- ???????System.out.println();??
- ????????boolean?isInMemory?=?item.isInMemory();??
- ????????long?sizeInBytes?=?item.getSize();??
- ????????File?uploadedFile?=?new?File("c://"?+?System.currentTimeMillis()?+?fileName.substring(fileName.lastIndexOf(".")));??
- ????????item.write(uploadedFile);??
- ????}??
- }??
- out.write("{success:true,msg:'保存上傳文件數據并分析Excel成功!'}");??
- out.flush();??
- %>??
processController.jsp:
- <%@?page?language="java"?import="java.util.*"?contentType?=?"text/html;charset=UTF-8"?pageEncoding="utf-8"%>??
- <%??
- ????//注意上面的抬頭是必須的。否則會有ajax亂碼問題。 ??
- ????//從session取出uploadPercentage并送回瀏覽器 ??
- ????Object?percent?=?request.getSession().getAttribute("uploadPercentage");??
- ????String?msg?=?"";??
- ????double?d?=?0;??
- ????if(percent==null){??
- ????????d?=?0;??
- ????}??
- ????else{??
- ????????d?=?(Double)percent;??
- ????????//System.out.println("+++++++processController:?"?+?d); ??
- ????}??
- ????if(d<1){??
- ????//d<1代表正在上傳, ??
- ????????msg?=?"正在上傳文件...";??
- ????????out.write("{success:true,?msg:?'"+msg+"',?percentage:'"?+?d?+?"',?finished:?false}");??
- ????}??
- ????else?if(d>=1){??
- ????????//d>1?代表上傳已經結束,開始處理分析excel, ??
- ????????//本例只是模擬處理excel,在session中放置一個processExcelPercentage,代表分析excel的進度。 ??
- ????????msg?=?"正在分析處理Excel...";??
- ????????String?finished?=?"false";??
- ????????double?processExcelPercentage?=?0.0;??
- ????????Object?o?=?request.getSession().getAttribute("processExcelPercentage");??
- ????????if(o==null){??
- ????????????processExcelPercentage?=?0.0;??
- ????????????request.getSession().setAttribute("processExcelPercentage",?0.0);??
- ??????????????
- ????????}??
- ????????else{??
- ????????????//模擬處理excel,百分比每次遞增0.1? ??
- ????????????processExcelPercentage?=?(Double)o?+?0.1;??
- ????????????request.getSession().setAttribute("processExcelPercentage",?processExcelPercentage);??
- ????????????if(processExcelPercentage>=1){??
- ????????????????//當processExcelPercentage>1代表excel分析完畢。 ??
- ????????????????request.getSession().removeAttribute("uploadPercentage");??
- ????????????????request.getSession().removeAttribute("processExcelPercentage");??
- ????????????????//客戶端判斷是否結束的標志 ??
- ????????????????finished?=?"true";??
- ????????????}??
- ????????}??
- ????????out.write("{success:true,?msg:?'"+msg+"',?percentage:'"?+?processExcelPercentage?+?"',?finished:?"+?finished?+"}");??
- ????????//注意返回的數據,success代表狀態 ??
- ????????//percentage是百分比 ??
- ????????//finished代表整個過程是否結束。 ??
- ????}??
- ????out.flush();??
- %>??
表單頁面upload.html:
- <html>??
- ????<head>??
- ????????<meta?http-equiv="Content-Type"?content="text/html;?charset=utf-8"?/>??
- ????????<title>File?Upload?Field?Example</title>??
- ????????<link?rel="stylesheet"?type="text/css"??
- ????????????href="ext/resources/css/ext-all.css"?/>??
- ????????<script?type="text/javascript"?src="ext/adapter/ext/ext-base.js">?</script>??
- ????????<script?type="text/javascript"?src="ext/ext-all.js">?</script>??
- ????????<style>??
- </style>??
- ????</head>??
- ????<body>??
- ????????<a?href="http://blog.csdn.net/sunxing007">sunxing007</a>??
- ????????<div?id="form"></div>??
- ????</body>??
- ????<script>??
- var?fm?=?new?Ext.FormPanel({??
- ????title:?'上傳excel文件',??
- ????url:'uploadController.jsp?t='?+?new?Date(),??
- ????autoScroll:true,??
- ????applyTo:?'form',??
- ????height:?120,??
- ????width:?500,??
- ????frame:false,??
- ????fileUpload:?true,??
- ????defaultType:'textfield',??
- ????labelWidth:200,??
- ????items:[{??
- ????????xtype:'field',??
- ????????fieldLabel:'請選擇要上傳的Excel文件?',??
- ????????allowBlank:false,??
- ????????inputType:'file',??
- ????????name:'file'??
- ????}],??
- ????buttons:?[{??
- ????????text:?'開始上傳',??
- ????????handler:?function(){??
- ????????????//點擊'開始上傳'之后,將由這個function來處理。??
- ????????????if(fm.form.isValid()){//驗證form,?本例略掉了??
- ????????????//顯示進度條??
- ????????????????Ext.MessageBox.show({???
- ????????????????????title:?'正在上傳文件',???
- ????????????????????//msg:?'Processing...',???
- ????????????????????width:240,???
- ????????????????????progress:true,???
- ????????????????????closable:false,???
- ????????????????????buttons:{cancel:'Cancel'}???
- ????????????????});???
- ????????????????//form提交??
- ????????fm.getForm().submit();??
- ????????//設置一個定時器,每500毫秒向processController發送一次ajax請求??
- ????????????var?i?=?0;??
- ????????????var?timer?=?setInterval(function(){??
- ????????????????????//請求事例??
- ??????????????????Ext.Ajax.request({??
- ??????????????????//下面的url的寫法很關鍵,我為了這個調試了好半天??
- ??????????????????//以后凡是在ajax的請求的url上面都要帶上日期戳,??
- ??????????????????//否則極有可能每次出現的數據都是一樣的,??
- ??????????????????//這和瀏覽器緩存有關??
- ????????????????????????url:?'processController.jsp?t='?+?new?Date(),??
- ????????????????????????method:?'get',??
- ????????????????????????//處理ajax的返回數據??
- ????????????????????????success:?function(response,?options){??
- ????????????????????????????status?=?response.responseText?+?"?"?+?i++;??
- ????????????????????????????var?obj?=?Ext.util.JSON.decode(response.responseText);??
- ????????????????????????????if(obj.success!=false){??
- ????????????????????????????????if(obj.finished){??
- ????????????????????????????????????clearInterval(timer);?????
- ????????????????????????????????????//status?=?response.responseText;??
- ????????????????????????????????????Ext.MessageBox.updateProgress(1,?'finished',?'finished');??
- ????????????????????????????????????Ext.MessageBox.hide();??
- ????????????????????????????????}??
- ????????????????????????????????else{??
- ????????????????????????????????????Ext.MessageBox.updateProgress(obj.percentage,?obj.msg);???
- ????????????????????????????????}??
- ????????????????????????????}??
- ????????????????????????},??
- ????????????????????????failure:?function(){??
- ????????????????????????????clearInterval(timer);??
- ????????????????????????????Ext.Msg.alert('錯誤',?'發生錯誤了。');??
- ????????????????????????}???
- ????????????????????});??
- ????????????},?500);??
- ??????????????????
- ????????????}??
- ????????????else{??
- ????????????????Ext.Msg.alert("消息","請先選擇Excel文件再上傳.");??
- ????????????}??
- ????????}???
- ????}]??
- });??
- </script>??
- </html>??
把這三個文件放到tomcat/webapps/ROOT/, 同時把ext的主要文件也放到這里,啟動tomcat即可測試:http://localhost:8080/upload.html
我的資源里面有完整的示例文件:http://download.csdn.net/detail/hanghangaidoudou/4987201, 下載zip文件之后解壓到tomcat/webapps/ROOT/即可測試。
最后需要特別提醒,因為用到了apache 的fileUpload組件,因此,需要把common-fileupload.jar放到ROOT/WEB-INF/lib下。