问题:实现文件上传并给出进度条显示上传过程信息。

  • 如何实现上传的功能  ------使用apache的FileUpload组件上传文件
  • 如何实现上传文件的监听功能 ------使用ProgressListener监听文件状态
  • 如何实现记录上传状态的功能 ------使用session保存文件的状态
  • 客户端如何状态的实时显示 -------客户端使用AJAX来查询上传的状态

思路:


客户端:界面的提交的时候使用<iframe 来实现模拟的无刷新提交,然后在使用ajax来周期的访问servlet并返回sesson中最新的状态信息。

 

服务器端:在servlet介绍到请求的时候,区分请求的类型是上传的请求还是ajax询问的请求,如果是上传的请求,则执行上传的方法,并启动监听保存上传状态到session中。


               




抽象出文件上传过程中需要用到的数据信息,文件的总大小、已上传大小、开始时间。


package com.test.entity;

public class Upload {
	private long totalSize;										//总大小
	private long startTime = System.currentTimeMillis();		//开始时间
	private long uploadSize;									//已上传的大小
	public long getTotalSize() {
		return totalSize;
	}
	public void setTotalSize(long totalSize) {
		this.totalSize = totalSize;
	}
	public long getStartTime() {
		return startTime;
	}
	public void setStartTime(long startTime) {
		this.startTime = startTime;
	}
	public long getUploadSize() {
		return uploadSize;
	}
	public void setUploadSize(long uploadSize) {
		this.uploadSize = uploadSize;
	}
}



设置监听,实现接口ProgressListener


package com.test.lister;

import org.apache.commons.fileupload.ProgressListener;

import com.test.entity.Upload;

public class UploadLister implements ProgressListener{
<span >	</span>private Upload upload = null;
<span >	</span>public UploadLister(Upload upload){
<span >		</span>this.upload = upload;
<span >	</span>}

<span >	</span>/**
<span >	</span> * @param uploadSize 已上传大小
<span >	</span> * @param totalSize 总大小
<span >	</span> * @param items 上传第几个(暂时用不到)
<span >	</span> */
<span >	</span>public void update(long uploadSize,long totalSize,int items) {
<span >		</span>upload.setUploadSize(uploadSize);
<span >		</span>upload.setTotalSize(totalSize);
<span >	</span>}
}



上传服务的servlet:


package com.test.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.test.lister.UploadLister;

@SuppressWarnings("serial")
public class Upload extends HttpServlet {

	public Upload() {
		super();
	}

	public void destroy() {
		super.destroy(); 
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("text/html");
		PrintWriter out = response.getWriter();

		com.test.entity.Upload upload = new com.test.entity.Upload();

		UploadLister lister = new UploadLister(upload);

		ServletFileUpload servletFileUpload = new ServletFileUpload(
				new DiskFileItemFactory());

		// 设置上传监听器
		servletFileUpload.setProgressListener(lister);
		//使用session保存文件的状态
		request.getSession().setAttribute("upload", upload);

		List list = null;
		try {
			list = servletFileUpload.parseRequest(request);
		} catch (FileUploadException e) {
			e.printStackTrace();
		}

		for (Iterator iter = list.iterator(); iter.hasNext();) {
			// 得到文件对象
			FileItem fileItem = (FileItem) iter.next();
			// 是表单才进行处理
			if (fileItem.isFormField()) {
				break;
			}
			// 同一linux和windows的路径分隔符
			String name = fileItem.getName().replaceAll("/", "\\");
			// 得到文件名
			int index = name.lastIndexOf("\\");
			String fileFileName = "";
			if (index == -1) {
				fileFileName = name;
			} else {
				fileFileName = name.substring(index + 1);
			}

			InputStream fileInputStream = fileItem.getInputStream();

			String path = request.getRealPath("/upload");
			// 也可不用自己写实现方法直接使用,fileItem.write(uploadFile);
			File uploadFile = new File(path, fileFileName);
			// 首先要确认路径是否存在
			uploadFile.getParentFile().mkdirs();
			// 检查文件是否已经存在
			if (!uploadFile.exists()) {
				// 建立文件
				uploadFile.createNewFile();
			}
			FileOutputStream out2 = new FileOutputStream(uploadFile);
			// 开始copy文件

			@SuppressWarnings("unused")
			int len = 0;// 每次读取的字节数
			byte[] bytes = new byte[1024];
			while ((len = fileInputStream.read(bytes, 0, bytes.length)) != -1) {
				out2.write(bytes);
			}
			out2.flush();
			out2.close();
			fileInputStream.close();
		}
		out.flush();
		out.close();
	}

	public void init() throws ServletException {

	}

}



刷新进度信息的servlet


package com.test.servlet;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
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.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import com.test.lister.UploadLister;

@SuppressWarnings("serial")
public class Upload extends HttpServlet {

	public Upload() {
		super();
	}

	public void destroy() {
		super.destroy(); 
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		doPost(request, response);
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		response.setContentType("text/html");
		PrintWriter out = response.getWriter();

		com.test.entity.Upload upload = new com.test.entity.Upload();

		UploadLister lister = new UploadLister(upload);

		ServletFileUpload servletFileUpload = new ServletFileUpload(
				new DiskFileItemFactory());

		// 设置上传监听器
		servletFileUpload.setProgressListener(lister);
		//使用session保存文件的状态
		request.getSession().setAttribute("upload", upload);

		List list = null;
		try {
			list = servletFileUpload.parseRequest(request);
		} catch (FileUploadException e) {
			e.printStackTrace();
		}

		for (Iterator iter = list.iterator(); iter.hasNext();) {
			// 得到文件对象
			FileItem fileItem = (FileItem) iter.next();
			// 是表单才进行处理
			if (fileItem.isFormField()) {
				break;
			}
			// 同一linux和windows的路径分隔符
			String name = fileItem.getName().replaceAll("/", "\\");
			// 得到文件名
			int index = name.lastIndexOf("\\");
			String fileFileName = "";
			if (index == -1) {
				fileFileName = name;
			} else {
				fileFileName = name.substring(index + 1);
			}

			InputStream fileInputStream = fileItem.getInputStream();

			String path = request.getRealPath("/upload");
			// 也可不用自己写实现方法直接使用,fileItem.write(uploadFile);
			File uploadFile = new File(path, fileFileName);
			// 首先要确认路径是否存在
			uploadFile.getParentFile().mkdirs();
			// 检查文件是否已经存在
			if (!uploadFile.exists()) {
				// 建立文件
				uploadFile.createNewFile();
			}
			FileOutputStream out2 = new FileOutputStream(uploadFile);
			// 开始copy文件

			@SuppressWarnings("unused")
			int len = 0;// 每次读取的字节数
			byte[] bytes = new byte[1024];
			while ((len = fileInputStream.read(bytes, 0, bytes.length)) != -1) {
				out2.write(bytes);
			}
			out2.flush();
			out2.close();
			fileInputStream.close();
		}
		out.flush();
		out.close();
	}

	public void init() throws ServletException {

	}

}



上传的文件的jsp界面


<html>
  <head>
    <base href="<%=basePath%>">
    <title>使用Ajax、Jquery进行文件上传,带进度条</title>
	<meta http-equiv="pragma" content="no-cache">
	<meta http-equiv="cache-control" content="no-cache">
	<meta http-equiv="expires" content="0">    
	<meta http-equiv="keywords" content="struts2 ajax upload progress">
	<meta http-equiv="description" content="file upload by struts2 and ajax and jquery progress">
	<script type="text/javascript" src="js/jquery-1.7.1.js"></script>
	<script type="text/javascript">
		var over = false;
		var inter;
		function upload(){
			over = false;
			$("#state").html("");
			$("#progress").css("width","0");
			$("input[type=submit]").attr("disabled",true);
			$("#progress").css("width","0%");
			$("#state").html("正在上传... 总大小:0MB,已上传:0MB,0%,已用时:0秒,剩余时间:0秒,速度:0KB/S");
			inter = setInterval(req,1000);
		}
		function req(){
			//如果上传已经完成
			if(over){
				clearInterval(inter);
				return;
			}
			var url = "upload/AjaxServlet";
			$.get(url,function(date){
				var state = date.split("-");
				$("#state").html("正在上传... 总大小:"+state[4]+"MB,已上传:"+state[3]+"MB,"+state[2]+"%,已用时:"+state[0]+"秒,剩余时间:"+state[5]+"秒,速度:"+state[1]+"KB/S");
				$("#progress").animate({width:state[2]+"%"},500);
				if(state[3] == state[4]){
					over = true;
					$("input[type=submit]").attr("disabled",false);
					$("#state").html("上传已完成,总大小:"+state[4]+"MB,已上传:"+state[3]+"MB,"+state[2]+"%,已用时:"+state[0]+"秒,剩余时间:"+state[5]+"秒,速度:"+state[1]+"KB/S");
				}
			});	
		}
	</script>
  </head>
  
  <body>
  	<form action="servlet/Upload" method="post" enctype="multipart/form-data" target="upload_iframe" οnsubmit="upload()">
  		<p><input type="file" name="file" id="file"></p>
  		<p><input type="submit" value="上传文件"></p> 
  	</form>
  	<iframe name="upload_iframe" width="0" height="0" frameborder="0"></iframe>
  	<div id="state">
  	</div>
  	<div id="progress" style="background: #728820; height: 20px; width: 0">
  	</div>
  </body>
</html>



配置文件信息


<?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">
	
  <servlet>
    <servlet-name>AjaxServlet</servlet-name>
    <servlet-class>com.test.servlet.AjaxServlet</servlet-class>
  </servlet>
  <servlet>
    <servlet-name>Upload</servlet-name>
    <servlet-class>com.test.servlet.Upload</servlet-class>
  </servlet>

  <servlet-mapping>
    <servlet-name>AjaxServlet</servlet-name>
    <url-pattern>/upload/AjaxServlet</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>Upload</servlet-name>
    <url-pattern>/servlet/Upload</url-pattern>
  </servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>upload.jsp</welcome-file>
  </welcome-file-list>
</web-app>


用到的公共文件: jquery-1.7.1.js  、 commons-fileupload-1.2.2.jar、  commons-io-2.0.1.jar