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

来源:互联网 发布:新思路二级vb序列号 编辑:程序博客网 时间:2024/06/05 13:30

本示例需要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{width:400px;height:12px;background:#FFFFFF;border:1px solid #000000;padding:1px;}    #progressBarItem{width: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打印的运行情况


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