后台:
package com.scott.uploadfile; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.Iterator; import java.util.List; import java.util.concurrent.ConcurrentHashMap; 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.FileUploadException; import org.apache.commons.fileupload.ProgressListener; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; /** * @author scott.wanglei * @since 2009-1-8 * 使用多线程实现文件进度的显示 */ public class UploadFile extends HttpServlet { private static final long serialVersionUID = 4030816613803833495L; //同步散列表保存文件上传进度类的引用 private ConcurrentHashMap<String,Progress> chp = new ConcurrentHashMap<String,Progress>(); public UploadFile() { super(); } public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); response.setHeader("pragma", "no-cache"); response.setHeader("cache-control", "no-cache"); response.setHeader("expires", "0"); if(request.getContentType() == null){ Progress p = new Progress(); //根据上request对象产生的String的hashcode值做为key值 String key = Integer.toString(request.toString().hashCode()); //根据key值储存当前文件的进度对象引用 chp.put(key, p); //把key传回并发起上传文件的请求 this.sendMsg(response,"parent.uploadFile('"+key+"')"); //上传线程没有开始时候阻塞更新线程 while(true){ if(p.getLength() != 0) break; } long temp = 0; while(! p.isComplete){ if(temp != p.getCurrentLength()){ temp = p.getCurrentLength(); //更新客户端进度 this.sendMsg(response, "parent.upload('"+temp+"','"+p.getLength()+"')"); } } } else if(request.getContentType().indexOf("multipart/form-data") > -1){ //上传线程开始执行 String key = request.getParameter("key"); Progress p = chp.get(key); if(p != null){ p.setLength(request.getContentLength()); this.startUploadFile(request,response, p,request.getRealPath("/"),key); chp.remove(key); } else{ this.sendMsg(response, "alert('Progress is null,k1 is not equal k2')"); } } else { this.sendMsg(response, "alert('ContentType is not correctly')"); } } //上传文件 private void startUploadFile( HttpServletRequest request, HttpServletResponse response,Progress p, String path,String key) throws IOException{ //设置上传工厂 DiskFileItemFactory factory = new DiskFileItemFactory(); factory.setRepository(new File(path)); //阀值,超过这个值才会写到临时目录 factory.setSizeThreshold(1024*1024*10); ServletFileUpload upload = new ServletFileUpload(factory); //最大上传限制 upload.setSizeMax(1024*1024*200); //设置监听器监听上传进度 upload.setProgressListener(p); List<FileItem> items = null; try { items = upload.parseRequest(request); } catch (FileUploadException e) { e.printStackTrace(); this.errorAndStorp(response, "alert('FileUploadExeception happened')", p,key); } for(Iterator<FileItem> it = items.iterator();it.hasNext();){ FileItem item = it.next(); if(item.isFormField()){ //处理表单域 } else{ try { FileOutputStream fos = new FileOutputStream(path+URLEncoder.encode(item.getName(),"utf-8")); if(item.isInMemory()){//文件全在内存中 fos.write(item.get()); p.setComplete(true); } else{ InputStream is = item.getInputStream(); byte[] buffer = new byte[1024]; int len; while((len = is.read(buffer)) > 0){ fos.write(buffer, 0, len); } p.setComplete(true); is.close(); fos.close(); } } catch (Exception e) { e.printStackTrace(); this.errorAndStorp(response, "alert('Exception happened')", p,key);} } } } //上传线程一旦出现意外,就让progress出于完成状态以终止向客户端发送信息的线程 private void errorAndStorp(HttpServletResponse response,String script, Progress p,String key) throws IOException{ p.setComplete(true); chp.remove(key); this.sendMsg(response, script); } //向客户端发送数据 private void sendMsg(HttpServletResponse response,String script) throws IOException{ PrintWriter out = response.getWriter(); out.println("<script type='text/javascript'>" +script +"</script>"); //ie太拽了发送的字节少了它根本不掉你 out.println("---------------------------------------------------"); out.println("---------------------------------------------------"); out.println("---------------------------------------------------"); out.println("---------------------------------------------------"); out.flush(); } //存放文件上传进度 private static class Progress implements ProgressListener{ private long length = 0;//文件总长度 private long currentLength = 0;//已上传的文件长度 private boolean isComplete = false;//上传是否完成 //实现监听器方法实时更新进度属性 public void update(long bytesRead, long contentLength, int items) { currentLength = bytesRead; } public Progress(){} public long getLength() { return length; } public void setLength(int l){ this.length = l; } public long getCurrentLength() { return currentLength; } public void setCurrentLenght(int cl){ this.currentLength = cl; } public boolean isComplete() { return isComplete; } public void setComplete(boolean isComplete) { this.isComplete = isComplete; } } }
前台
<%@ page language="java" pageEncoding="utf-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>ajax显示上传文件进度</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <!-- <link rel="stylesheet" type="text/css" href="styles.css" mce_href="styles.css"> --> <mce:style type="text/css"><!-- iframe{ border:0; } #p_out{ width:200px; height:12px; margin:10px 0 0 0; padding:1px 1px 1px 1px; font-size:10px; border:solid #d4e4ff 1px; } #p_in{ width:0%; height:100%; background-color:#d4e4ff; margin:0; padding:0; } #dis{ margin:0; padding:0; text-align:center; font-size:12px; height:12px; width:200px; } --></mce:style><mce:style type="text/css" mce_bogus="1"><!-- iframe{ border:0; } #p_out{ width:200px; height:12px; margin:10px 0 0 0; padding:1px 1px 1px 1px; font-size:10px; border:solid #d4e4ff 1px; } #p_in{ width:0%; height:100%; background-color:#d4e4ff; margin:0; padding:0; } #dis{ margin:0; padding:0; text-align:center; font-size:12px; height:12px; width:200px; } --></mce:style><style type="text/css" mce_bogus="1" mce_bogus="1"> iframe{ border:0; } #p_out{ width:200px; height:12px; margin:10px 0 0 0; padding:1px 1px 1px 1px; font-size:10px; border:solid #d4e4ff 1px; } #p_in{ width:0%; height:100%; background-color:#d4e4ff; margin:0; padding:0; } #dis{ margin:0; padding:0; text-align:center; font-size:12px; height:12px; width:200px; } </style> </head> <body> <form id="uploadfile_form" name="uploadfile_form" enctype="multipart/form-data" method="post" target="uploadfile_iframe"> <input type="file" name="file" /> <br><br> <button onclick="progress()">提交</button> <div id="p_out"><div id="p_in"></div></div> <div id="dis"></div> </form> <iframe width="0px" height="0px" id="uploadfile_iframe" name="uploadfile_iframe" src="javascript:void(0)" ></iframe> <iframe width="0px" height="0px" id="progress_iframe" name="progress_iframe" src="javascript:void(0)" ></iframe> </body> <script type="text/javascript"> function progress(){ document.getElementById('progress_iframe').src = 'myFileUpload'; document.getElementById('dis').innerHTML = '初始化数据...'; } function uploadFile(k){ console.log("k="+k); document.forms[0].action = 'myFileUpload?key='+k; document.forms[0].submit(); } function upload(len,total){ console.log("len="+len+"total="+total); document.getElementById('p_in').style.width = (Math.round(len/total*100))+'%'; document.getElementById('dis').innerHTML = len+'/'+total+' Byte'; } </script> </html>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <display-name></display-name> <servlet> <servlet-name>myFileUpload</servlet-name> <servlet-class>com.scott.uploadfile.UploadFile</servlet-class> </servlet> <servlet-mapping> <servlet-name>myFileUpload</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
导入commons-fileupload-1.3.1.jar,commons-io-2.2.jar