需要commons-fileupload-1.2.1.jar和commons-io-1.4.jar
原理:
实时显示文件上传进度的原理是处理文件上传的同时,将上传进度的信息写入session中,浏览器利用ajax技术新开一个线程获取session中的信息,并实时显示
上传监听器(上传文件时会不断回调监听器总的update方法)
import org.apache.commons.fileupload.ProgressListener; import com.qf.util.UploadStatus; public class UploadListener implements ProgressListener{ private UploadStatus status; public UploadListener(UploadStatus status) { this.status = status; } @Override public void update(long bytesRead, long contentLength, int items) { status.setBytesRead(bytesRead); status.setContentLength(contentLength); status.setItems(items); } }
上传文件相关数据(javabean)
public class UploadStatus { //已上传字节数 private long bytesRead; //所有文件总字节数 private long contentLength; //正在上传第几个文件 private int items; //开始上传的时间 private long startTime = System.currentTimeMillis(); public long getBytesRead() { return bytesRead; } public void setBytesRead(long bytesRead) { this.bytesRead = bytesRead; } public long getContentLength() { return contentLength; } public void setContentLength(long contentLength) { this.contentLength = contentLength; } public int getItems() { return items; } public void setItems(int items) { this.items = items; } public long getStartTime() { return startTime; } public void setStartTime(long startTime) { this.startTime = startTime; } }
处理文件上传的servlet
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Iterator; import java.util.List; 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.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; public class ProgressUploadServlet extends HttpServlet { private static final long serialVersionUID = -4935921396709035718L; public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 上传状态 UploadStatus status = new UploadStatus(); // 监听器 UploadListener listener = new UploadListener(status); // 把 UploadStatus 放到 session 里 request.getSession(true).setAttribute("uploadStatus", status); // Apache 上传工具 ServletFileUpload upload = new ServletFileUpload( new DiskFileItemFactory()); // 设置 listener upload.setProgressListener(listener); try { List<?> itemList = upload.parseRequest(request); for (Iterator<?> it = itemList.iterator(); it.hasNext();) { FileItem item = (FileItem) it.next(); if (item.isFormField()) { System.out.println("FormField: " + item.getFieldName() + " = " + item.getString()); } else { System.out.println("File: " + item.getName()); // 统一 Linux 与 windows 的路径分隔符 String fileName = item.getName().replace("/", "\\"); fileName = fileName.substring(fileName.lastIndexOf("\\")); File saved = new File("C:\\upload_test", fileName); saved.getParentFile().mkdirs(); InputStream ins = item.getInputStream(); OutputStream ous = new FileOutputStream(saved); byte[] tmp = new byte[1024]; int len = -1; while ((len = ins.read(tmp)) != -1) { ous.write(tmp, 0, len); } ous.close(); ins.close(); response.getWriter().println("已保存文件:" + saved); } } } catch (Exception e) { e.printStackTrace(); response.getWriter().println("上传发生错误:" + e.getMessage()); } } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("Cache-Control", "no-store"); response.setHeader("Pragrma", "no-cache"); response.setDateHeader("Expires", 0); UploadStatus status = (UploadStatus) request.getSession(true) .getAttribute("uploadStatus"); if (status == null) { response.getWriter().println("没有上传信息"); return; } long startTime = status.getStartTime(); long currentTime = System.currentTimeMillis(); // 已传输的时间 单位:s long time = (currentTime - startTime) / 1000 + 1; // 传输速度 单位:byte/s double velocity = ((double) status.getBytesRead()) / (double) time; // 估计总时间 单位:s double totalTime = status.getContentLength() / velocity; // 估计剩余时间 单位:s double timeLeft = totalTime - time; // 已完成的百分比 int percent = (int) (100 * (double) status.getBytesRead() / (double) status .getContentLength()); // 已完成数 单位:M double length = ((double) status.getBytesRead()) / 1024 / 1024; // 总长度 单位:M double totalLength = ((double) status.getContentLength()) / 1024 / 1024; // 格式:百分比||已完成数(M)||文件总长度(M)||传输速率(K)||已用时间(s)||估计总时间(s)||估计剩余时间(s)||正在上传第几个文件 String value = percent + "||" + length + "||" + totalLength + "||" + velocity + "||" + time + "||" + totalTime + "||" + timeLeft + "||" + status.getItems(); response.getWriter().println(value); } }
显示页面jsp
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Insert title here</title> <style type="text/css"> body, td, div { font-size: 12px; font-familly: 宋体; } #progressBar { width: 400px; height: 12px; background: #FFFFFF; border: 1px solid #000000; padding: 1px; } #progressBarItem { width: 30%; height: 100%; background: #FF0000; } </style> </head> <body> <iframe name=upload_iframe width=0 height=0></iframe> <form action="servlet/ProgressUploadServlet" method="post" enctype="multipart/form-data" target="upload_iframe" οnsubmit="showStatus(); "> <input type="file" name="file1" style="width: 350px;"> <br /> <input type="file" name="file2" style="width: 350px;"> <br /> <input type="file" name="file3" style="width: 350px;"> <br /> <input type="file" name="file4" style="width: 350px;"> <input type="submit" value=" 开始上传 " id="btnSubmit"> </form> <div id="status" style="display: none;"> 上传进度条: <div id="progressBar"> <div id="progressBarItem"></div> </div> <div id="statusInfo"></div> </div> <br /> <br /> <br /> <br /> <br /> <script type="text/javascript"> var _finished = true; function $(obj) { return document.getElementById(obj); } function showStatus() { _finished = false; $('status').style.display = 'block'; $('progressBarItem').style.width = '1%'; $('btnSubmit').disabled = true; setTimeout("requestStatus()", 1000); } function requestStatus() { if (_finished) return; var req = createRequest(); req.open("GET", "servlet/ProgressUploadServlet"); req.onreadystatechange = function() { callback(req); } req.send(null); setTimeout("requestStatus()", 1000); } function createRequest() { if (window.XMLHttpRequest)//ns { return new XMLHttpRequest(); } else//IE { try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { return new ActiveXObject("Microsoft.XMLHTTP"); } } return null; } function callback(req) { if (req.readyState == 4) { if (req.status != 200) { _debug("发生错误。 req.status: " + req.status + ""); return; } _debug("status.jsp 返回值:" + req.responseText); var ss = req.responseText.split("||"); // 格式:百分比||已完成数(M)||文件总长度(M)||传输速率(K)||已用时间(s)||估计总时间(s)||估计剩余时间(s)||正在上传第几个文件 $('progressBarItem').style.width = '' + ss[0] + '%'; $('statusInfo').innerHTML = '已完成百分比: ' + ss[0] + '% <br />已完成数(M): ' + ss[1] + '<br/>文件总长度(M): ' + ss[2] + '<br/>传输速率(K): ' + ss[3] + '<br/>已用时间(s): ' + ss[4] + '<br/>估计总时间(s): ' + ss[5] + '<br/>估计剩余时间(s): ' + ss[6] + '<br/>正在上传第几个文件: ' + ss[7]; if (ss[1] == ss[2]) { _finished = true; $('statusInfo').innerHTML += "<br/><br/><br/>上传已完成。"; $('btnSubmit').disabled = false; } } } function _debug(obj) { var div = document.createElement("DIV"); div.innerHTML = "[debug]: " + obj; document.body.appendChild(div); } </script> </body> </html>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>ServletDemo003</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>search.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>servlet</servlet-name> <servlet-class>com.qf.servlet.ProgressUploadServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>servlet</servlet-name> <url-pattern>/servlet/*</url-pattern> </servlet-mapping> </web-app>