Servlet:htm+javascript+css+servlet (ajax)实现上传(能显示进度条)

本示例需要commons-fileupload-1.3.jar和commons-io-2.4.jar的支持,新手请参阅无进度条的上传

http://blog.csdn.net/tabactivity/article/details/11180631


害羞确认您的环境配置成功后,下面开始编码:


src/UploadStatus.java ,数据模型类

package com.xieyuan;

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;
	}

}

src/UploadListener.java,继承自ProgressListener,当使用commons_uploadfile组件上传时,调用组件类的方法可添加上传监听,组件就会不断调用UploadListener的update方法

package com.xieyuan;

import org.apache.commons.fileupload.ProgressListener;

public class UploadListener implements ProgressListener {

	private UploadStatus status;

	public UploadListener(UploadStatus status) {
		this.status = status;
	}

	public void update(long bytesRead, long contentLength, int items) {
		status.setBytesRead(bytesRead);
		status.setContentLength(contentLength);
		status.setItems(items);
		
	}
}

src/UploadServlet.java,该类doPost方法用于处理上传,index.jsp后台会使用XmlHttpRequest调用本Servlet的doGet方法,从session中获取最新的上传数据情况

package com.xieyuan;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sound.sampled.AudioFormat.Encoding;

import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;


public class UploadServlet extends HttpServlet {

    //定义临时文件盒上传文件的存储路径
    private File uploadTemp=null;
    private File uploadPath=null;
    
    /**
     * Constructor of the object.
     */
    public UploadServlet() {
        super();
    }

    /**
     * Destruction of the servlet. <br>
     */
    public void destroy() {
        super.destroy(); // Just puts "destroy" string in log
        // Put your code here
    }


    /**
     * The doGet method of the servlet. <br>
     *
     * This method is called when a form has its tag value method equals to get.
     * 
     * @param request the request send by the client to the server
     * @param response the response send by the server to the client
     * @throws ServletException if an error occurred
     * @throws IOException if an error occurred
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         //禁用缓存,index.jsp后台会使用XmlHttpRequest调用本Servlet的doGet方法,从session中获取最新的上传数据情况
        response.setHeader("Cache-Control", "no-store");
        response.setHeader("Pragrma", "no-cache");
        response.setDateHeader("Expires", 0);
        response.setContentType("text/html;charset=utf-8");
        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);
    }

    /**
     * The doPost method of the servlet. <br>
     *
     * This method is called when a form has its tag value method equals to post.
     * 
     * @param request the request send by the client to the server
     * @param response the response send by the server to the client
     * @throws ServletException if an error occurred
     * @throws IOException if an error occurred
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        File file=null;
        String description=null;
        
        //设置响应格式(不设置请求格式,因为文件是二进制的,不能使用UTF-8格式化请求数据)
        response.setContentType("text/html;charset=utf-8");
        
        PrintWriter out=response.getWriter();
        out.println("<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">");
        out.println("<HTML>");
        out.println("<HEAD><TITLE>文件上传</TITLE></HEAD>");
        out.println("<BODY style='margin:50px'>");
        out.println("上传日志:<BR/>");
        
        UploadStatus status=new UploadStatus();
        UploadListener listener=new UploadListener(status);
        /*
         * 
         * 把 UploadStatus 放到 session 里,引用
           返回与此请求关联的当前HttpSession,如果没有当前会话和创造是真实的,返回一个新的会话。
          如果创建是假的,并要求有没有有效的HttpSession,这个方法返回null。
         */
        request.getSession(true).setAttribute("uploadStatus", status);
        
        //创建基于磁盘的工厂,针对大文件,临时文件将存储在磁盘
        DiskFileItemFactory factory=new DiskFileItemFactory();
        //设置缓冲区大小,超出该文件直接写入到磁盘的大小设置门槛。
        factory.setSizeThreshold(10240);  //这里默认10KB
        //设置用于大于配置的大小阈值设置的临时存储文件目录。
        factory.setRepository(uploadTemp);
        //创建一个文件上传的句柄
        ServletFileUpload upload=new ServletFileUpload(factory);
        //设置最大文件尺寸 ,这里是40MB        
        upload.setSizeMax(41943040);
        upload.setHeaderEncoding("utf-8");
        
        // 设置 listener
        upload.setProgressListener(listener);
        
        try {
            //将解析结果放在LIST中
            List<FileItem> list =upload.parseRequest(request);
            out.println("遍历所有的 FileItem ... <br/>");
            // 遍历 list 中所有的 FileItem
            for(FileItem item:list)
            {
                // 如果是 文本域
                if(item.isFormField())
                {
                    if(item.getFieldName().equals("description1")||item.getFieldName().equals("description2"))
                    {
                                            
                        description = item.getString("UTF-8");    
                        System.out.println("遍历到 "+item.getFieldName()+" ... <br/>"+description+"<BR/>");    
                    }
                }
                else 
                {
                    //否则为文件域,当getName为Null说明没有选则文件
                    if((item.getFieldName().equals("file1")||item.getFieldName().equals("file2"))
                            &&item.getName()!=null&&!item.getName().equals(""))
                    {
                        try 
                        {
                            // 统一 Linux 与 windows 的路径分隔符
                            String fileName = item.getName();
                            //fileName = fileName.substring(fileName.lastIndexOf("\"));

                            // 服务器端文件,放在 upload 文件夹下
                            file=new File(uploadPath,fileName);
                            if(!file.getParentFile().exists())
                                file.getParentFile().mkdirs();
                            if(!file.exists())
                                file.createNewFile();
                            
                            item.write(file);
                            
                            System.out.println("遍历到 "+fileName+" ... <br/>"+description+"<BR/>");    
                        } catch (Exception e) {
                            System.out.println("Request 上传失败!"+e.getMessage());
                        }
                        finally //总是立即删除保存表单字段内容的临时文件
                        {
                            item.delete();
                        }
                    }
                }
            }
            System.out.println("Request 解析完毕,文件上传完毕!");
        } catch (Exception e) {
            System.out.println("Request 解析异常!"+e.getMessage());
        }
        out.flush();
        out.close();
    }

    
    /**
     * Initialization of the servlet. <br>
     *
     * @throws ServletException if an error occurs
     */
    public void init() throws ServletException {

        uploadPath=new File(this.getServletContext().getRealPath("upload"));
        if(!uploadPath.exists())
            uploadPath.mkdirs();        
        uploadTemp=new File(this.getServletContext().getRealPath("upload/temp"));
        if(!uploadTemp.exists())
            uploadTemp.mkdirs();
    }

}



web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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">
  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>com.xieyuan.UploadServlet</servlet-class>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/servlet/UploadServlet</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
</web-app>

WebRoot / index.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
  <head>
    <title>带进度条的文件上传</title>
    
    <style type="text/css">
    #progressBar{400px;height:12px;background:#FFFFFF;border:1px solid #000000;padding:1px;}
    #progressBarItem{30%;height:100%;background:#FF0000;}
    </style>
    <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;
         <!--隔1秒后执行一次-->
         setTimeout("requestStatus()",1000);
      }
      <!--发送请求获取文件上传状态-->
      function requestStatus()
      {
         if(_finished)
               return;
         var req=createRequest();
         req.open("GET","servlet/UploadServlet");
         req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
         req.onreadystatechange=function(){callback(req);};
         //我们的实例在 open() 的第三个参数中使用了 "true"。该参数规定请求是否异步处理。
         //True 表示脚本会在 send() 方法之后继续执行,而不等待来自服务器的响应。
         
         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;
             }
    
            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;
            }
           _debug("status.jsp 返回值:" + req.responseText);
        
          }
      }
      function _debug(obj)
      {
        //var div=document.createElement("DIV");
        $('debug').innerHTML="[debug]:"+obj+"<br/>";             
        //document.body.appendChild(div);
        
      }
    </script>
  </head> 
  <body style="margin:50px">
     <iframe name="upload_iframe" width="0" height="0" frameborder="0" ></iframe>
      
      <form action="servlet/UploadServlet" method="post" enctype="multipart/form-data"
            target="upload_iframe" onsubmit="showStatus();">
         <p>上传文件:</p>
         文件1:<input type="file" name="file1" /><br/>
         描述:<input type="text" name="description1" /><br/>
         文件2:<input type="file" name="file2" /><br/>
        描述:<input type="text" name="description2" /><br/>
      <input type="submit" id="btnSubmit" value=" 上  传 " />  
      </form>
      <div id="status" style="display:none;position:relative;line-height:100%;opacity:1;">
           上传进度:
           <div id="progressBar" ><div id="progressBarItem" /></div>
           <div id="statusInfo" style="margin:10px 0px 0px 0px;"/>
      </div>
      <BR/>
      <div id="debug" />
  </body>
  </html>




通过访问:http://127.0.0.1:8080/Test/   查看程序效果,如图

System.out.println打印的运行情况


至此,一个简单的上传程序就完成了。

原文地址:https://www.cnblogs.com/xieyuan/p/3787498.html