標籤:
P.S. HTML5經過了W3C的8年努力,終於正式推廣了。這次升級最大的就是升級了XMLHTTPRequest,讓它變成了XMLHTTPRequest Level II(這有啥奇怪的?)。這個對象現在非常強大,可能會讓所有使用jQuery的人全部重新拾起HTML原生的ajax技術。
閑話扯到這,接著是主題:我們今天要實現的就是下面的效果:
這裡面檔案名稱、檔案大小和MIME都是在選擇檔案時讀取和現實,然後點擊上傳之後,上傳進度即時顯示,最後彈出右邊的對話方塊確認檔案資訊(當然這裡我為了方便直接把檔案資訊壓到POST請求裡面了,否則可能亂碼,你也可以試試伺服器端直接讀取)。
接著,看到了這個強大的效果,我們簡單地分析以下思路。
1、我們首先確定實現方式:Javascript將會顯示在用戶端顯示進度(用的是XMLHTTPRequest Level II的幾個新的Event),然後同時上傳檔案資訊和檔案本身,當然是非同步。
2、伺服器端用一個servlet就行,這裡使用commonfileupload接受上傳。
然後看一下新的XMLHTTPRequest Level II,看看如何監視這一過程。
<input type="file" name="fileToUpload" id="fileToUpload" onchange="fileSelected();"/>
選擇檔案這裡看到了一個onchange事件,這不是一個新事件,但在HTML5標準中被重新定義了,被用於檔案被選擇的時候調用。
function fileSelected() { //檔案選擇更改時調用的事件 var file = document.getElementById(‘fileToUpload‘).files[0]; //獲得檔案上傳資訊 if (file) { //如果使用者選擇了檔案(沒有選擇的話,file就是null或是undefined,這樣可以判斷) var fileSize = 0; //檔案大小 if (file.size > 1024 * 1024) //如果檔案大小大於1MB fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100) .toString() + ‘MB‘; //轉換檔大小並以MB單位顯示 else //否則 fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + ‘KB‘; //否則用KB單位顯示 document.getElementById(‘fileName‘).innerHTML = ‘ ‘ + file.name; //顯示檔案名稱資訊 document.getElementById(‘fileSize‘).innerHTML = ‘ ‘ + fileSize; //顯示檔案大小資訊 document.getElementById(‘fileType‘).innerHTML = ‘ ‘ + file.type; //顯示檔案MIME資訊 }}
這個注釋不是我加的,我也不清楚是誰加的……但是大家應該能看懂了。
function uploadFile() { //點擊上傳按鈕時的時間 var fd = new FormData(); //FormData是Html5的新增類 fd.append("file", document.getElementById(‘fileToUpload‘).files[0]); //向表單資料添加檔案主體 var file = document.getElementById(‘fileToUpload‘).files[0]; //獲得檔案主體 var xhr = new XMLHttpRequest(); //初始化ajax請求 xhr.upload.addEventListener("progress", uploadProgress, false); //HTML5的新的事件,上傳進度改變時,只能在有檔案上傳的情況下調用 xhr.addEventListener("load", uploadComplete, false); //老事件,上傳完成後 xhr.addEventListener("error", uploadFailed, false); //出錯時 xhr.addEventListener("abort", uploadCanceled, false); //中斷時 var caption=document.getElementById("caption").value; //標題(和檔案上傳無關緊要) fd.append("filename", file.name); //檔案名稱添加到表單資料 fd.append("filesize", file.size); //檔案尺寸添加到表單資料 fd.append("filetype", file.type); //MIME添加到表單資料 fd.append("caption", caption); //標題添加到表單資料 xhr.open("POST", "FileUpload",true); //準備上傳 //xhr.setRequestHeader("Content-Type", "multipart/form-data"); //這句千萬不能有!!!我也不知道為什麼…… xhr.send(fd); //發出請求}
點擊上傳按鈕之後就是這段代碼,FormData也是新加的對象,用於儲存表單資料(某人加的注視應該夠明白了……)。
接著我們看後台,後台使用commonfileupload接收(貌似說過了……),先把代碼貼出來:
package Upload;import java.io.File;import java.io.IOException;import java.io.PrintWriter;import java.util.Iterator;import java.util.List;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.commons.fileupload.FileItem;import org.apache.commons.fileupload.FileItemFactory;import org.apache.commons.fileupload.FileUploadException;import org.apache.commons.fileupload.disk.DiskFileItemFactory;import org.apache.commons.fileupload.servlet.ServletFileUpload;import Log.LogManager;public class FileUpload extends HttpServlet { /** * Constructor of the object. */ public FileUpload() { super(); } /** * Destruction of the servlet. <br> */ public void destroy() { super.destroy(); // Just puts "destroy" string in log // Put your code here } /** * The doPost method of the servlet. <br> * * This method is called when a form has its tag value method equals to post. * * @param request the request send by the client to the server * @param response the response send by the server to the client * @throws ServletException if an error occurred * @throws IOException if an error occurred */ public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { request.setCharacterEncoding("UTF-8"); DiskFileItemFactory fif=new DiskFileItemFactory(); fif.setSizeThreshold(1024*1024); ServletFileUpload sfu=new ServletFileUpload(fif); sfu.setSizeMax(1024*1024*1024); List items=null; try { items=sfu.parseRequest(request); } catch (FileUploadException e) { // TODO Auto-generated catch block e.printStackTrace(); } Iterator iter=items.iterator(); String filename=""; String filesize=""; String filetype=""; String caption=""; FileItem fi=null; while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); if (item.isFormField()) { String name=item.getFieldName(); if(name.equals("filename")==true){ filename=item.getString("UTF-8"); }else if(name.equals("filesize")==true){ filesize=item.getString("UTF-8"); }else if(name.equals("filetype")==true){ filetype=item.getString("UTF-8"); }else if(name.equals("caption")==true){ caption=item.getString("UTF-8"); } } else { fi=item; } } ServletContext application=getServletContext(); String path=(String) application.getAttribute("datapath")+"uploadpath"+application.getAttribute("systempi")+filename; File f1=new File(path); try { fi.write(f1); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println("你上傳了一個檔案到伺服器,下面將核實這些資訊:"); out.println("1、檔案名稱:"+filename); out.println("2、檔案大小:"+filesize); out.println("3、檔案MIME類型:"+filetype); out.println("如果資訊全部正確,說明檔案成功上傳了!"); String sqls1=""; LogManager.log("一個檔案上傳請求已經被受理!檔案儲存體於:"+path); out.flush(); out.close(); } catch (Exception e) { LogManager.err(e.toString()); } } /** * Initialization of the servlet. <br> * * @throws ServletException if an error occurs */ public void init() throws ServletException { // Put your code here }}
還挺簡單的,對嗎?處理HTML5的上傳請求和處理以前版本的上傳請求基本一樣,唯一需要注意的是:原來是你來拼接請求,所以說,位置由你決定,現在FormData拼接請求的字串中項目的順序和append的順序有關,所以別搞錯了(貌似我就搞錯了,先添加了檔案,然後在後台補救了一下……)。
基本上就這些代碼,然後就是添加檔案資訊到資料庫什麼的,具體上傳步驟查查commonfileupload的api好了。
整個項目不方便讓大家下載,但這是一個OJ項目裡面的,有興趣的關注一下進入項目的git。另外如果轉載的話,註明一下,謝謝!
HTML5+J2EE實現檔案非同步上傳