基於瀏覽器的檔案上傳,特別是對於通過<input type="file">標籤來實現上傳的情況, 存在著嚴重的效能問題,因為使用者提交了檔案之後,在瀏覽器把檔案上傳到伺服器的過程中,介面看上去似乎是靜止的,如果是小檔案還好些,如果不幸需要上傳的是幾兆、幾十兆甚至上百兆的檔案,我相信那是一種非常痛苦的體驗,我們中間的很多人應該都有過此種不堪的經曆。(一笑)
現在我就針對這個問題給出一個解決方案,我們將實現一個具有監控能力的WEB上傳的程式——它不僅把檔案上傳到伺服器,而且"即時地"監視檔案上傳的實際過程。
解決方案的基本思路是這樣的:
- 在Form提交上傳檔案同時,使用AJAX周期性地從Servlet輪詢上傳狀態資訊
- 然後,根據此資訊更新進度條和相關文字,及時反映檔案傳輸狀態
- 如果使用者取消上傳操作,則進行相應的現場清理工作:刪除已經上傳的檔案,在Form提交頁面中顯示相關資訊
- 如果上傳完畢,顯示已經上傳的檔案內容(或連結)
在介紹原始碼之前,我們先來看看程式運行介面:
實現代碼想當然的有伺服器端代碼和用戶端代碼(呵呵),我們先從伺服器端開始。
2.1.1. 檔案上傳狀態類(FileUploadStatus)
使用FileUploadStatus這個類記錄檔案上傳狀態,並將其作為伺服器端與web用戶端之間通訊的媒介,通過對這個類對象提供上傳狀態作為伺服器回應發送給web用戶端, web用戶端使用JavaScript獲得檔案上傳狀態。原始碼如下:
/** * 本常式示範了通過Web上傳檔案過程中的進度顯示。您可以對本常式進行任何修改和使用。 * 如果需要轉載本常式,請您註明作者。 * * 作者: 劉作晨 * EMail:liuzuochen@gmail.com */package liuzuochen.sample.upload;import java.util.*;public class FileUploadStatus { //上傳使用者地址 private String uploadAddr; //上傳總量 private long uploadTotalSize = 0; //讀取上傳總量 private long readTotalSize = 0; //當前上傳檔案號 private int currentUploadFileNum = 0; //成功讀取上傳檔案數 private int successUploadFileCount = 0; //狀態 private String status = ""; //處理起始時間 private long processStartTime = 0l; //處理終止時間 private long processEndTime = 0l; //處理執行時間 private long processRunningTime = 0l; //上傳檔案URL列表 private List uploadFileUrlList = new ArrayList(); //取消上傳 private boolean cancel = false; //上傳base目錄 private String baseDir = ""; public FileUploadStatus() { } public String getBaseDir() { return baseDir; } public void setBaseDir(String baseDir) { this.baseDir = baseDir; } public boolean getCancel() { return cancel; } public void setCancel(boolean cancel) { this.cancel = cancel; } public List getUploadFileUrlList() { return uploadFileUrlList; } public void setUploadFileUrlList(List uploadFileUrlList) { this.uploadFileUrlList = uploadFileUrlList; } public long getProcessRunningTime() { return processRunningTime; } public void setProcessRunningTime(long processRunningTime) { this.processRunningTime = processRunningTime; } public long getProcessEndTime() { return processEndTime; } public void setProcessEndTime(long processEndTime) { this.processEndTime = processEndTime; } public long getProcessStartTime() { return processStartTime; } public void setProcessStartTime(long processStartTime) { this.processStartTime = processStartTime; } public long getReadTotalSize() { return readTotalSize; } public void setReadTotalSize(long readTotalSize) { this.readTotalSize = readTotalSize; } public int getSuccessUploadFileCount() { return successUploadFileCount; } public void setSuccessUploadFileCount(int successUploadFileCount) { this.successUploadFileCount = successUploadFileCount; } public int getCurrentUploadFileNum() { return currentUploadFileNum; } public void setCurrentUploadFileNum(int currentUploadFileNum) { this.currentUploadFileNum = currentUploadFileNum; } public String getStatus() { return status; } public void setStatus(String status) { this.status = status; } public long getUploadTotalSize() { return uploadTotalSize; } public String getUploadAddr() { return uploadAddr; } public void setUploadTotalSize(long uploadTotalSize) { this.uploadTotalSize = uploadTotalSize; } public void setUploadAddr(String uploadAddr) { this.uploadAddr = uploadAddr; } public String toJSon() { StringBuffer strJSon = new StringBuffer(); strJSon.append("{UploadTotalSize:").append(getUploadTotalSize()).append( ",") .append("ReadTotalSize:").append(getReadTotalSize()).append(",") .append("CurrentUploadFileNum:").append(getCurrentUploadFileNum()). append(",") .append("SuccessUploadFileCount:").append( getSuccessUploadFileCount()).append(",") .append("Status:'").append(getStatus()).append("',") .append("ProcessStartTime:").append(getProcessStartTime()). append(",") .append("ProcessEndTime:").append(getProcessEndTime()).append( ",") .append("ProcessRunningTime:").append(getProcessRunningTime()). append(",") .append("Cancel:").append(getCancel()).append("}"); return strJSon.toString(); }}
2.1.2. 檔案上傳狀態偵聽類(FileUploadListener)
使用Common-FileUpload 1.2版本(20070103)。此版本提供了能夠監視檔案上傳情況的ProcessListener介面,使開發人員通過FileUploadBase類對象的setProcessListener方法植入自己的Listener。 FileUploadListener類實現了ProcessListener,在整個檔案上傳過程中,它對上傳進度進行監控,並且根據上傳 情況即時的更新上傳狀態Bean。原始碼如下:
/** * 本常式示範了通過Web上傳檔案過程中的進度顯示。您可以對本常式進行任何修改和使用。 * 如果需要轉載本常式,請您註明作者。 * * 作者: 劉作晨 * EMail:liuzuochen@gmail.com */package liuzuochen.sample.upload;import org.apache.commons.fileupload.ProgressListener;import javax.servlet.http.HttpServletRequest;public class FileUploadListener implements ProgressListener{private HttpServletRequest request=null;public FileUploadListener(HttpServletRequest request){this.request=request;}/** * 更新狀態 */public void update(long pBytesRead, long pContentLength, int pItems){FileUploadStatus statusBean= BackGroundService.getStatusBean(request);statusBean.setUploadTotalSize(pContentLength);//讀取完成 if (pContentLength == -1) { statusBean.setStatus("完成對" + pItems +"個檔案的讀取:讀取了 " + pBytesRead + " bytes."); statusBean.setReadTotalSize(pBytesRead); statusBean.setSuccessUploadFileCount(pItems); statusBean.setProcessEndTime(System.currentTimeMillis()); statusBean.setProcessRunningTime(statusBean.getProcessEndTime()); //讀取中 } else { statusBean.setStatus("當前正在處理第" + pItems +"個檔案:已經讀取了 " + pBytesRead +
"/" + pContentLength+ " bytes."); statusBean.setReadTotalSize(pBytesRead); statusBean.setCurrentUploadFileNum(pItems); statusBean.setProcessRunningTime(System.currentTimeMillis()); } BackGroundService.saveStatusBean(request,statusBean);}}
當前1/2頁
12下一頁閱讀全文