Java带进度条的文件上传

原创 2016年02月04日 04:49:23

工作原理:

实时显示上传进度的原理是服务器在处理上传文件的同时,将上传进度的信息例如文件总长度、以上传多少、传输速率等写入Session中。客户浏览器利用Ajax技术再新开一个独立的线程从Session中获取上传进度信息,并实时显示。Ajax技术能够不断刷新页面获取服务器数据。Session课看作是服务器内存,可用于存放少量的客户信息。需要使用commons-fileupload-1.2.1.jar与commons-io-1.4.jar包。

上传进度条:

上传进度条用两个

标签实现,通过控制
的css属性就可以显示一个HTML版的进度条。
标签连同css样式、JavaScript脚本、Ajax技术,可以实现非常丰富的效果,代码为:
upload.jsp

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>上传文件</title>
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="this is my page">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="css/style.css">
</head>

<body>
<form action="servlet/UploadServlet" method="post" enctype="multipart/form-data">
<div align="center"><br/>
    <fieldset style="width:90%">
        <legend>上传文件</legend><br/>
        <div class='line'>
            <div align='left' class="leftDiv">上传文件一</div>
            <div align='left' class="rightDiv">
                <input type="file" name="file1" class="text">
            </div>
        </div>
        <div class='line'>
            <div align='left' class="leftDiv">上传文件二</div>
            <div align='left' class="rightDiv">
                <input type="file" name="file2" class="text">
            </div>
        </div>
        <div class='line'>
            <div align='left' class="leftDiv">上传文件说明一</div>
            <div align='left' class="rightDiv"><input type="text" name="description1" class="text"></div>
        </div>
        <div class='line'>
            <div align='left' class="leftDiv">上传文件说明二</div>
            <div align='left' class="rightDiv"><input type="text" name="description2" class="text"></div>
        </div>
        <div class='line'>
            <div align='left' class="leftDiv"></div>
            <div align='left' class="rightDiv"><br/>
                <input type="submit" value="  上传文件  " class="button">
            </div>
        </div>
    </fieldset>
</div>
</form>
</body>
</html>

要控制进度条的显示进度,只需要用JavaScript控制ID为progressBarItem的百分比宽度。

上传监听器:

commons-fileupload版本1.2支持上传监听,只需要实现一个监听器,并把它添加到上传组件即可。监听器需要实现它的ProgressListener接口,代码如下:
UploadListener.java

package com.helloweenvsfei.servlet.upload;

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

ProgressListener接口只有一个方法:upload(long bytesRead,long contentLength,int items).参数byteRead表示已经上传的字节数,contentLength表示上传的总长度(如果为-1则表示总长度未知),items表示正在上传第几个文件。
添加监听该监听器后,上传组件在上传文件的时会不断回调该方法,回传这些数据。利用这些数字,就可以计算出文件上传的进度,用进度条实时显示出来。因此需要把这些数据保存起来。代码中把数据保存到了一个UploadStatus中。这是一个普通的JavaBean,代码如下:
UploadStatus.java

package com.helloweenvsfei.servlet.upload;

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

}

UploadStatus中还记录了开始上传的时间,用于计算上传速率、估计上传总时间等。

监听上传进度:

处理文件上传的Servlet为ProgressUploadServlet.监听伤处过程需要为ServeltFileUpload安装一个监听器,然后把存有上传进度信息的UploadSatus对象放进Session。上传文件使用的是Post方法,因此需要把代码写到doPost()方法中.

现在使用ProgressUploadServlet来处理文件上传,就能获得到上传开始时间、已上传的字节数、正在上传第几个文件等信息了。只不过这些信息还保存在Session里,需要再写一个程序读取出来。
读取上传进度:
上传进度保存在Session中的UploadStatus属性中,从该属性中获取UploadStatus对象,并将上传进度信息读取出来。上传文件只会使用ProgressUploadServletd的doPost()方法而没有占用doGet()方法,因此这里使用doGet()方法来读取上传进度。也就是说,如果以Post方式访问ProgressUploadServlet,会执行上传代码;如果以Get方式访问ProgressUploadServlet,会执行读取上传进度的代码。
根据上传开始时间、已上传字节数、总的字节数等原始数据,可以计算出已传输时间、传输速率、传输总时间、剩余时间、已完成百分比等。这些数据最终要被Ajax程序读取、以进度条形式显示,因此最后将他们用分隔符“||”分开,便于程序处理。
现在上传文件时用快捷键Ctrl+N新开一个子窗口访问ProgressUploadServlet,就可以看到文字版的上传进度。不断刷新,就能不断地更新。不过手工查看上传进度太笨拙了,下一步要写一个Ajax程序,自动获取该Servlet返回的数据、将数据显示在进度条上,并且每一秒自动更新一次。

显示上传进度:

上传文件时,如果不对表单做特别处理,提交表单后会转到另一个页面,造成页面的刷新。而且新页面显示之前,浏览器会因等待而显示白屏。如果上传的文件很大,白屏时间会很长。因此需要对表单做一些特别处理,使提交表单后的原页面内容不变,同时显示进度条,知道文件上传结束,从而避免出现白屏。方式更改Form的target属性。代码如下:
progressUpload.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
body, td, div {font-size: 12px; font-familly: 宋体; }
#progressBar {width: 400px; height: 12px; background: #FFFFFF; border: 1px solid #000000; padding: 1px; }
#progressBarItem {width: 30%; height: 100%; background: #FF0000; }
</style>
</head>

<body>

<iframe name=upload_iframe width=0 height=0></iframe>

<form action="servlet/ProgressUploadServlet" method="post" enctype="multipart/form-data" target="upload_iframe" onsubmit="showStatus(); ">

<input type="file" name="file1" style="width: 350px; "> <br />
<input type="file" name="file2" style="width: 350px; "> <br />
<input type="file" name="file3" style="width: 350px; "> <br />
<input type="file" name="file4" style="width: 350px; "> <input type="submit"
    value=" 开始上传 " id="btnSubmit"></form>

<div id="status" style="display: none; ">
    上传进度条:
    <div id="progressBar"><div id="progressBarItem"></div></div>
    <div id="statusInfo"></div>
</div>

<br/>
<br/>
<br/>
<br/>
<br/>

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

    setTimeout("requestStatus()", 1000); 
}

function requestStatus(){

    if(_finished)   return;

    var req = createRequest(); 

    req.open("GET", "servlet/ProgressUploadServlet");
    req.onreadystatechange=function(){callback(req);}
    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;
        }

        _debug("status.jsp 返回值:" + req.responseText);

        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;
        }
    }
}
function _debug(obj){
    var div = document.createElement("DIV");
    div.innerHTML = "[debug]: " + obj;
    document.body.appendChild(div); 
}

</script>

</body>
</html>

target属性默认为_self.如果target为默认值,则提交后的新页面会在当前窗口显示,造成当前窗口短暂地白屏。在页面内添加一个隐藏的iframe(通过制定iframe的宽高为0实现隐藏),把target属性指定为该iframe,则提交后的新页面会在iframe内显示,iframe内会短暂白屏。因为iframe是隐藏的,所以上传文件的时候当前页面看不到任何变化。
注意上传文件的表单要指定method=”POST”与enctype=”multipart/form-data”.另外为表单添加一个onsubmit=”showStatus();”事件,表单提交时会执行页面内的showStatus()方法。这是一段JavaScript程序代码。该方法显示进度条,并用Ajax读取Session里保存的上传进度,实时刷新进度条。showStatus()如上代码所示。
Ajax能够不刷新页面改变页面内容。它的原理是创建一个request,用这个request获取其他页面内容,并显示到页面上。因为没有在浏览器上输入新的地址,所以页面不会有刷新、抖动等。
Ajax的核心就是这个request,学名为XMLHttpRequest,需要浏览器支持。目前所有的主流的浏览器都能提供XMLHttpRequest.
progressUpload.jsp代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<style type="text/css">
body, td, div {font-size: 12px; font-familly: 宋体; }
#progressBar {width: 400px; height: 12px; background: #FFFFFF; border: 1px solid #000000; padding: 1px; }
#progressBarItem {width: 30%; height: 100%; background: #FF0000; }
</style>
</head>

<body>

<iframe name=upload_iframe width=0 height=0></iframe>

<form action="servlet/ProgressUploadServlet" method="post" enctype="multipart/form-data" target="upload_iframe" onsubmit="showStatus(); ">

<input type="file" name="file1" style="width: 350px; "> <br />
<input type="file" name="file2" style="width: 350px; "> <br />
<input type="file" name="file3" style="width: 350px; "> <br />
<input type="file" name="file4" style="width: 350px; "> <input type="submit"
    value=" 开始上传 " id="btnSubmit"></form>

<div id="status" style="display: none; ">
    上传进度条:
    <div id="progressBar"><div id="progressBarItem"></div></div>
    <div id="statusInfo"></div>
</div>

<br/>
<br/>
<br/>
<br/>
<br/>

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

    setTimeout("requestStatus()", 1000); 
}

function requestStatus(){

    if(_finished)   return;

    var req = createRequest(); 

    req.open("GET", "servlet/ProgressUploadServlet");
    req.onreadystatechange=function(){callback(req);}
    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;
        }

        _debug("status.jsp 返回值:" + req.responseText);

        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;
        }
    }
}
function _debug(obj){
    var div = document.createElement("DIV");
    div.innerHTML = "[debug]: " + obj;
    document.body.appendChild(div); 
}

</script>

</body>
</html>

运行效果如图所示:
这里写图片描述

版权声明:本文为博主原创文章,未经博主允许不得转载。

springMVC是实现前台带进度条文件上传

项目框架采用spring+hibernate+springMVC如果上传文件不想使用flash那么你可以采用html5;截图前段模块是bootstarp框架;不废话直接来代码;spring-mvc配置...
  • zmx729618
  • zmx729618
  • 2016年07月11日 16:23
  • 8489

java文件上传带进度条的

本文将使用   apache fileupload   ,spring MVC   jquery1.6x , bootstrap  实现一个带进度条的多文件上传, 由于fileupload 的局限,...
  • gaochh01
  • gaochh01
  • 2013年03月28日 09:52
  • 15585

Java web 中实现 文件上传 进度条显示

请客官参考http://blog.itpub.net/30066956/viewspace-1775286/ 这一篇文章,来决定使用哪儿种,个人觉得使用uploadify更好更方便。感谢:http:/...
  • chengwangbaiko
  • chengwangbaiko
  • 2017年05月11日 14:43
  • 2235

java FTP上传文件(进度条显示进度)

java实现FTP上传有2种方式,一种是org.apache.commons.net.ftp.FTPClient这个jar包,一种是sun.net.ftp.FtpClient。不知道为什么,在使用前一...
  • u013401219
  • u013401219
  • 2015年06月12日 11:00
  • 2878

ServletFileUpload上传文件带进度条

ServletUpload,文件上传,带进度条
  • luozw_123
  • luozw_123
  • 2016年07月29日 11:42
  • 3051

JAVA实现大文件上传及显示进度信息

一. 大文件上传基础描述:   各种WEB框架中,对于浏览器上传文件的请求,都有自己的处理对象负责对Http MultiPart协议内容进行解析,并供开发人员调用请求的表单内容。 比如: ...
  • moonpure
  • moonpure
  • 2017年02月04日 10:15
  • 1099

Java动态显示文件上传进度的简单实现

实现文件上传的进度显示,我们先看看都有哪些问题我们要解决。 1 上传数据的处理进度跟踪 2 进度数据在用户页面的显示 就这么2个问题, 第一个问题,主要是组件的选择 必须支持数据处理侦听或通知的组件。...
  • java2000_net
  • java2000_net
  • 2008年03月08日 06:12
  • 8468

JAVA实现显示上传文件进度条

很久不在这里发帖子了,最近在家闲来无事,想到转视频的那东西又要做了,遂翻出以前的帖子,看到一年前丰哥让我做一下文件上传的进度条....额~~那就做一下吧。东西很简单,主要用到commons-fileu...
  • BBG_0622
  • BBG_0622
  • 2010年04月26日 13:44
  • 6702

重新学javaweb---文件上传监听--进度条

update方法API void update(long pBytesRead, long pContentLength, int pItems)Parameters:pBytesRead - Th...
  • fangchao3652
  • fangchao3652
  • 2016年05月10日 00:27
  • 1998

HTML5 jQuery+FormData 异步上传文件,带进度条

利用jQuery和html5的FormData异步上传文件的好处是: 实现很简单很方便地支持进度条很方便地进行扩展和美化 先看看效果图: 图片上传后的结果: ...
  • Michaelwubo
  • Michaelwubo
  • 2016年03月12日 14:00
  • 13630
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Java带进度条的文件上传
举报原因:
原因补充:

(最多只允许输入30个字)