基于AJAX的文件上传显示进度条实现

基于Ajax的文件上传要实现的功能要求,要在用户提交了上传按钮请求后,客户端其页面要显示文件上传进度条。

      其整个功能时序图如图所示。

基于AJAX的文件上传显示进度条实现_第1张图片

 简单的说,要实现在客户端显示进度条,需要做的是:当客户端提交上传文件请求后,服务器在上传文件的过程中,将上传进度情况保存到Session中,客户端周期性的发送请求来获取保存在Session中值,以获取上传文件的进度信息。

1. 新建web工程AjaxUpload。

2. 将commons-fileupload-1.2.1-bin.zip包中的commons-fileupload-1.2.1.jar文件和commons-io-1.4-bin.zip包中的commons-io-1.4.jar文件拷贝到web工程下的WEB-INF\lib目录下。

3. 由于本实例涉及到多个类,处理此类问题最好是给相应的类打包进行管理。在web工程src目录下新建一个包com.ncu.upload。

4. 服务器端实现。

首先要创建一个用来保存文件上传状态的类 FileUploadStatus。其源码如下:

package com.ncu.upload;  
  
import java.util.*;  
  
public class FileUploadStatus {  
    //上传总量  
    private long uploadTotalSize=0;  
    //读取上传总量  
    private long readTotalSize=0;  
    //当前上传文件号  
    private int currentUploadFileNum=0;  
    //成功读取上传文件数  
    private int successUploadFileCount=0;  
    //状态  
    private String status="";  
    //处理起始时间  
    private long processStartTime=0l;  
    //处理终止时间  
    private long processEndTime=0l;  
    //处理执行时间  
    private long processRunningTime=0l;  
    //上传文件URL列表  
    private List uploadFileUrlList=new ArrayList();  
    //取消上传  
    private boolean cancel=false;  
    //上传base目录  
    private String baseDir="";  
      
    public String getBaseDir() {  
        return baseDir;  
    }  
    public void setBaseDir(String baseDir) {  
        this.baseDir = baseDir;  
    }  
    public boolean getCancel() {  
        return cancel;  
    }  
    public void setCancel(boolean cancel) {  
        this.cancel = cancel;  
    }  
    public List getUploadFileUrlList() {  
        return uploadFileUrlList;  
    }  
    public void setUploadFileUrlList(List uploadFileUrlList) {  
        this.uploadFileUrlList = uploadFileUrlList;  
    }  
    public long getProcessRunningTime() {  
        return processRunningTime;  
    }  
    public void setProcessRunningTime(long processRunningTime) {  
        this.processRunningTime = processRunningTime;  
    }  
    public long getProcessEndTime() {  
        return processEndTime;  
    }  
    public void setProcessEndTime(long processEndTime) {  
        this.processEndTime = processEndTime;  
    }  
    public long getProcessStartTime() {  
        return processStartTime;  
    }  
    public void setProcessStartTime(long processStartTime) {  
        this.processStartTime = processStartTime;  
    }  
    public long getReadTotalSize() {  
        return readTotalSize;  
    }  
    public void setReadTotalSize(long readTotalSize) {  
        this.readTotalSize = readTotalSize;  
    }  
    public int getSuccessUploadFileCount() {  
        return successUploadFileCount;  
    }  
    public void setSuccessUploadFileCount(int successUploadFileCount) {  
        this.successUploadFileCount = successUploadFileCount;  
    }  
    public int getCurrentUploadFileNum() {  
        return currentUploadFileNum;  
    }  
    public void setCurrentUploadFileNum(int currentUploadFileNum) {  
        this.currentUploadFileNum = currentUploadFileNum;  
    }  
    public String getStatus() {  
        return status;  
    }  
    public void setStatus(String status) {  
        this.status = status;  
    }  
    public long getUploadTotalSize() {  
        return uploadTotalSize;  
    }  
    public void setUploadTotalSize(long uploadTotalSize) {  
        this.uploadTotalSize = uploadTotalSize;  
    }  
      
}

 由于要在客户端要显示进度条,所以在上传过程中服务器端需要监视和维护上传状态的信息,此过程需要处理的数据信息是:不断更新Session中保存的FileUploadStatus实例的信息,如:已经上传的字节数,上传文件的总大小等。FileUpload现在的1.2版本为监视上传进度提供了内建的支持,可以直接继承类ProgressListener,然后重载update()方法,在该方法中添加自己要处理的代码,最后在文件上传处理代码(后面会讲到)中通过为ServletFileUpload对象注册创建的监听类。监听类UploadListener的源代码如下:

package com.ncu.upload;  
  
import javax.servlet.http.HttpSession;  
  
import org.apache.commons.fileupload.ProgressListener;  
  
public class UploadListener implements ProgressListener {  
      
    private HttpSession session=null;  
      
    public UploadListener (HttpSession session){  
        this.session=session;  
    }  
    /** 
     * 更新状态 
     * @param pBytesRead 读取字节总数 
     * @param pContentLength 数据总长度 
     * @param pItems 当前正在被读取的field号 
     */  
    public void update(long pBytesRead, long pContentLength, int pItems) {  
        FileUploadStatus fuploadStatus = UploadServlet.takeOutFileUploadStatusBean(this.session);  
        fuploadStatus.setUploadTotalSize(pContentLength);  
        //读取完成  
        if (pContentLength == -1) {  
            fuploadStatus.setStatus("完成对" + pItems + "个文件的读取:读取了 " + pBytesRead + "/"  + pContentLength+ " bytes.");  
            fuploadStatus.setReadTotalSize(pBytesRead);  
            fuploadStatus.setCurrentUploadFileNum(pItems);  
            fuploadStatus.setProcessEndTime(System.currentTimeMillis());  
            fuploadStatus.setProcessRunningTime(fuploadStatus.getProcessEndTime());  
        }else{//读取过程中  
               fuploadStatus.setStatus("当前正在处理第" + pItems+"个文件:已经读取了 " + pBytesRead + " / " + pContentLength+ " bytes.");  
               fuploadStatus.setReadTotalSize(pBytesRead);  
               fuploadStatus.setCurrentUploadFileNum(pItems);  
               fuploadStatus.setProcessRunningTime(System.currentTimeMillis());  
        }  
        //System.out.println("已经读取:" + pBytesRead);  
        UploadServlet.storeFileUploadStatusBean(this.session, fuploadStatus);  
    }  
  
}  

有了前面两个类的基础,下来我们可以动手去实现真正处理整个操作Servlet类。源代码如下。

package com.ncu.upload;  
  
import java.io.*;  
import java.util.List;  
  
import javax.servlet.ServletException;  
import javax.servlet.http.HttpServletRequest;  
import javax.servlet.http.HttpServletResponse;  
import javax.servlet.http.HttpSession;  
  
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.*;  
  
/** 
 * Servlet implementation class for Servlet: UploadServlet 
 * 
 */  
 public class UploadServlet extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {  
   static final long serialVersionUID = 1L;  
     
     public static final String UPLOAD_STATUS="UPLOAD_STATUS";  
     public static final String UPLOAD_DIR="/upload";  
     
    public UploadServlet() {  
        super();  
    }    
      
    /** 
     * 从文件路径中取出文件名 
     * @param filePath 
     * @return 
     */  
    private String takeOutFileName(String filePath){  
        int pos=filePath.lastIndexOf(File.separator);  
        if (pos>0){  
            return filePath.substring(pos+1);  
        }  
        else{  
            return filePath;  
        }  
    }  
      
    /** 
     * 从request中取出FileUploadStatus Bean 
     * @param request 
     * @return 
     */  
    public static FileUploadStatus takeOutFileUploadStatusBean(HttpSession session){  
        Object obj=session.getAttribute(UPLOAD_STATUS);  
        if (obj!=null){  
            return (FileUploadStatus)obj;  
        }  
        else{  
            return null;  
        }  
    }  
      
    /** 
     * 把FileUploadStatus Bean保存到session 
     * @param request 
     * @param uploadStatusBean 
     */  
    public static void storeFileUploadStatusBean(  
            HttpSession session,  
            FileUploadStatus uploadStatusBean){  
        session.setAttribute(UPLOAD_STATUS,uploadStatusBean);  
    }  
      
    /** 
     * 删除已经上传的文件 
     * @param request 
     */  
    private void deleteUploadedFile(HttpServletRequest request){  
        FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession());  
        for(int i=0;i0){  
                    String fileName=takeOutFileName(item.getName());  
                    File uploadedFile = new File(request.getRealPath(UPLOAD_DIR)+File.separator+fileName);  
                    item.write(uploadedFile);  
                    //更新上传文件列表  
                    FileUploadStatus fUploadStatus=takeOutFileUploadStatusBean(request.getSession());  
                    fUploadStatus.getUploadFileUrlList().add(fileName);  
                    storeFileUploadStatusBean(request.getSession(),fUploadStatus);  
                    Thread.sleep(500);  
                }  
            }  
          
        } catch (FileUploadException e) {  
            e.printStackTrace();  
            //uploadExceptionHandle(request,"上传文件时发生错误:"+e.getMessage());  
        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
            //uploadExceptionHandle(request,"保存上传文件时发生错误:"+e.getMessage());  
        }  
    }  
      
    /** 
     * 回应上传状态查询 
     * @param request 
     * @param response 
     * @throws IOException 
     */  
    private void responseFileUploadStatusPoll(HttpServletRequest request,HttpServletResponse response) throws IOException{  
        FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS);  
        //计算上传完成的百分比  
        long percentComplete = (long)Math.floor(((double) fUploadStatus.getReadTotalSize()/(double) fUploadStatus.getUploadTotalSize())*100.0);  
        System.out.println("com:"+percentComplete);  
        response.setContentType("text/xml");  
        response.setCharacterEncoding("UTF-8");  
        response.setHeader("Cache-Control", "no-cache");  
        if ( ((long)fUploadStatus.getReadTotalSize() == (long)fUploadStatus.getUploadTotalSize()) || (fUploadStatus.getCancel() == true)){  
        response.getWriter().write(fUploadStatus.getStatus().toString()+"success");  
        }else{  
            response.getWriter().write(fUploadStatus.getStatus().toString()+"
"); } } /** * 处理取消文件上传 * @param request * @param response * @throws IOException */ private void processCancelFileUpload(HttpServletRequest request,HttpServletResponse response) throws IOException{ FileUploadStatus fUploadStatus=(FileUploadStatus)request.getSession().getAttribute(UPLOAD_STATUS); fUploadStatus.setCancel(true); request.getSession().setAttribute(UPLOAD_STATUS, fUploadStatus); responseFileUploadStatusPoll(request,response); } /** * 在上传文件列表中查找与文件名相关的id * @param request * @param fileName 文件名 * @return 找到返回id,否则返回-1 */ private int findFileIdInFileUploadedList(HttpServletRequest request,String fileName){ FileUploadStatus fileUploadStatus=takeOutFileUploadStatusBean(request.getSession()); for(int i=0;i

至此,服务器端的代码已经基本完成。

 

5. 客户端实现

由于在上传文件时需要在同一页面显示对应的进度条控件,因此,在提交表单时当前页面不能被刷新。我们可以通过将表单提交至一个隐藏的 iframe 中来实现。关于Ajax的技术前面讲过,这里就不再细说,直接给出源代码如下:

  
  
  
  
基于Ajax的上传文件显示进度条  
   
  
  
  



 至此,整个文件上传的实现到此完成,读者可以在此基础上,发挥自己的创新能力,去完善此实例。

Good Luck!

http://plkong.iteye.com/blog/238159

你可能感兴趣的:(基于AJAX的文件上传显示进度条实现)