原文: http://www.codeguru.com/java/article.php/c13913/AJAX-File-Upload-Progress-for-Java.htm#page-1
文件上传需要用到commons-fileupload-1.2.1.jar
首先创建一个FileUploadServlet文件
1 package com.psclistens.ajax.fileupload; 2 3 import java.io.File; 4 import java.io.IOException; 5 import java.io.PrintWriter; 6 import java.util.Iterator; 7 import java.util.List; 8 import javax.servlet.Servlet; 9 import javax.servlet.ServletException; 10 import javax.servlet.http.HttpServlet; 11 import javax.servlet.http.HttpServletRequest; 12 import javax.servlet.http.HttpServletResponse; 13 import javax.servlet.http.HttpSession; 14 import org.apache.commons.fileupload.FileItem; 15 import org.apache.commons.fileupload.FileItemFactory; 16 import org.apache.commons.fileupload.FileUploadException; 17 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 18 import org.apache.commons.fileupload.servlet.ServletFileUpload; 19 20 /** 21 * This is a File Upload Servlet that is used with AJAX 22 * to monitor the progress of the uploaded file. It will 23 * return an XML object containing the meta information 24 * as well as the percent complete. 25 */ 26 public class FileUploadServlet 27 extends HttpServlet 28 implements Servlet 29 { 30 private static final long serialVersionUID = 2740693677625051632L; 31 32 public FileUploadServlet() 33 { 34 super(); 35 } 36 37 protected void doGet(HttpServletRequest request, 38 HttpServletResponse response) 39 throws ServletException, IOException 40 { 41 } 42 43 protected void doPost(HttpServletRequest request, 44 HttpServletResponse response) 45 throws ServletException, IOException 46 { 47 } 48 }
修改 web.xml 文件添加servlet配置
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>AJAXFileUploadApp</display-name> <servlet> <description>Servlet for file uploads</description> <display-name>File Upload Servlet</display-name> <servlet-name>>FileUploadServlet</servlet-name> <servlet-class> com.psclistens.ajax.fileupload.FileUploadServlet </servlet-class> </servlet> <servlet-mapping> <servlet-name>FileUploadServlet</servlet-name> <url-pattern>/servlet/FileUploadServlet</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>fileUpload.html</welcome-file> </welcome-file-list> </web-app>
接着,创建一个文件上传的监听,监听继承自org.apache.commons.fileupload.ProgressListener
package com.psclistens.ajax.fileupload; import org.apache.commons.fileupload.ProgressListener; /** * This is a File Upload Listener that is used by Apache * Commons File Upload to monitor the progress of the * uploaded file. */ public class FileUploadListener implements ProgressListener { private volatile long bytesRead = 0L, contentLength = 0L, item = 0L; public FileUploadListener() { super(); } public void update(long aBytesRead, long aContentLength, int anItem) { bytesRead = aBytesRead; contentLength = aContentLength; item = anItem; } public long getBytesRead() { return bytesRead; } public long getContentLength() { return contentLength; } public long getItem() { return item; } }
修改servlet中的doPost方法为下面代码
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // create file upload factory and upload servlet FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); // set file upload progress listener FileUploadListener listener = new FileUploadListener(); HttpSession session = request.getSession(); session.setAttribut("LISTENER", listener); // upload servlet allows to set upload listener upload.setProgressListener(listener); List uploadedItems = null; FileItem fileItem = null; String // Path to store file on local system filePath = "c:\\temp"; try { // iterate over all uploaded files uploadedItems = upload.parseRequest(request); Iterator i = uploadedItems.iterator(); while (i.hasNext()) { fileItem = (FileItem) i.next(); if (fileItem.isFormField() == false) { if (fileItem.getSize() > 0) { File uploadedFile = null; String myFullFileName = fileItem.getName(), myFileName = "", slashType = (myFullFileName.lastIndexOf("\\") > 0) ? "\\" : "/"; // Windows or UNIX int startIndex = myFullFileName.lastIndexOf(slashType); // Ignore the path and get the filename myFileName = myFullFileName.substring (startIndex + 1, myFullFileName.length()); // Create new File object uploadedFile = new File(filePath, myFileName); // Write the uploaded file to the system fileItem.write(uploadedFile); } } } } catch (FileUploadException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } }
创建上传的html页面,上传完成后跳转至当前页面隐藏的iframe中,从而实现实现当前页面不刷新
<html> <head> <title>Ajax File Upload</title> </head> <body> <iframe id="uploadFrameID" name="uploadFrame" height="0" width="0" frameborder="0" scrolling="yes"></iframe> <form id="myForm" enctype="multipart/form-data" method="post" target="uploadFrame" action="servlet/FileUploadServlet" onsubmit="ajaxFunction()"> <input type="file" name="txtFile" id="txtFile" /><br /> <input type="submit" id="submitID" name="submit" value="Upload" /> </form> </body> </html>
添加一个隐藏的div,当上传表单提交的时候,显示该div作为进度的显示。
<div id="initializing" style="visibility: hidden; position: absolute; top: 100px;"> <table width="100%" style="border: 1px; background-color: black;"> <tr> <td> <table width="100%" style="border: 1px; background-color: black; color: white;"> <tr> <td align="center"> <b>Initializing Upload...</b> </td> </tr> </table> </td> </tr> </table> </div> <div id="progressBarTable" style="visibility: hidden; position: absolute; top: 100px;"> <table width="100%" style="border: 1px; background-color: black; color: white;"> <tr> <td> <table id="progressBar" width="0px" style="border: 1px; width: 0px; background-color: blue;"> <tr> <td> </td> </tr> </table> </td> </tr> </table> <table width="100%" style="background-color: white; color: black;"> <tr> <td align="center" nowrap="nowrap"> <span id="bytesRead" style="font-weight: bold;"> </span> </td> </tr> </table> </div> <div id="percentCompleteTable" align="center" style="visibility: hidden; position: absolute; top: 100px;"> <table width="100%" style="border: 1px;"> <tr> <td> <table width="100%" style="border: 1px;"> <tr> <td align="center" nowrap="nowrap"> <span id="percentComplete" style="color: white; font-weight: bold;"> </span> </td> </tr> </table> </td> </tr> </table> </div>
修改servlet的doGet方法,返回XHR数据作为ajax请求的数据。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter out = response.getWriter(); HttpSession session = request.getSession(); FileUploadListener listener = null; StringBuffer buffy = new StringBuffer(); long bytesRead = 0, contentLength = 0; // Make sure the session has started if (session == null) { return; } else if (session != null) { // Check to see if we've created the listener object yet listener = (FileUploadListener)session.getAttribute("LISTENER"); if (listener == null) { return; } else { // Get the meta information bytesRead = listener.getBytesRead(); contentLength = listener.getContentLength(); } } response.setContentType("text/xml"); buffy.append("<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"); buffy.append("<response>\n"); buffy.append("\t<bytes_read>" + bytesRead + "</bytes_read>\n"); buffy.append("\t<content_length>" + contentLength + "</content_length>\n"); // Check to see if we're done if (bytesRead == contentLength) { buffy.append("\t<finished />\n"); // No reason to keep listener in session since we're done session.setAttribute("LISTENER", null); } else { // Calculate the percent complete long percentComplete = ((100 * bytesRead) / contentLength); buffy.append("\t<percent_complete>" + percentComplete + "</percent_complete>\n"); } buffy.append("</response>\n"); out.println(buffy.toString()); out.flush(); out.close(); }
添加ajax代码:
<script language="javascript"> var req; function ajaxFunction() { var url = "servlet/FileUploadServlet"; if (window.XMLHttpRequest) // Non-IE browsers { req = new XMLHttpRequest(); req.onReadyStateChange = processStateChange; try { req.open("GET", url, true); } catch (e) { alert(e); } req.send(null); } else if (window.ActiveXObject) // IE Browsers { req = new ActiveXObject("Microsoft.XMLHTTP"); if (req) { req.onReadyStateChange = processStateChange; req.open("GET", url, true); req.send(); } } } function processStateChange() { /** * State Description * 0 The request is not initialized * 1 The request has been set up * 2 The request has been sent * 3 The request is in process * 4 The request is complete */ if (req.readyState == 4) { if (req.status == 200) // OK response { var xml = req.responseXML; // No need to iterate since there will only be one set // of lines var isNotFinished = xml.getElementsByTagName("finished")[0]; var myBytesRead = xml.getElementsByTagName("bytes_read")[0]; var myContentLength = xml.getElementsByTagName("content_length")[0]; var myPercent = xml.getElementsByTagName("percent_complete")[0]; // Check to see if it's even started yet if ((isNotFinished == null) && (myPercent == null)) { document.getElementById ("initializing").style.visibility = "visible"; // Sleep then call the function again window.setTimeout("ajaxFunction();", 100); } else { document.getElementById("initializing" ). style.visibility = "hidden"; document.getElementById("progressBarTable" ). style.visibility = "visible"; document.getElementById("percentCompleteTable" ). style.visibility = "visible"; document.getElementById("bytesRead" ). style.visibility = "visible"; myBytesRead = myBytesRead.firstChild.data; myContentLength = myContentLength.firstChild.data; // It's started, get the status of the upload if (myPercent != null) { myPercent = myPercent.firstChild.data; document.getElementById("progressBar").style.width = myPercent + "%"; document.getElementById("bytesRead").innerHTML = myBytesRead + " of " + myContentLength + " bytes read"; document.getElementById("percentComplete").innerHTML = myPercent + "%"; // Sleep then call the function again window.setTimeout("ajaxFunction();", 100); } else { document.getElementById("bytesRead").style. visibility = "hidden"; document.getElementById("progressBar").style.width = "100%"; document.getElementById("percentComplete"). innerHTML = "Done!"; } } } else { alert(req.statusText); } } } </script>
这样实现一个简易的ajax上传进度显示功能