[进度条]文件下载

本文介绍了一种实现文件下载时显示进度条的方法。通过在前端搭建下载页面并绘制进度条,后台处理文件下载并在Controller中使用全局的进度工具类记录下载状态。利用JavaScript的定时函数和Ajax,前端每秒查询一次下载进度,当进度达到100%时停止定时任务,完成下载进度的实时更新。提供了进度条工具类和相关JS函数的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现思路:

  1. 首先前台搭建好下载页面,绘制一个进度条
  2. 后台写好文件下载功能
  3. 在前台中使用一个隐藏的表单,用来执行下载功能,用JS提交表单实现下载,这样执行下载时不会跳转页面
  4. 在后台实现文件下载时检测文件下载进度,同时用进度工具类来存储下载进度
  5. 在Controller中定义一个进度工具类全局引用变量,但不需要初始化,当用户进行下载时初始化进度工具类全局引用变量,已达到一个用户下载对用一个进度
  6. 前台写入Ajax事件,用JS的定时函数,来调用Ajax事件,一秒访问一次后台的进度工具类的全局引用变量,用来获取下载进度
  7. 当Ajax获取的下载进度为100%时,调用JS的停止定时函数,结束前台文件下载进度的检测
  8. 文件下载结束

JS中用到的两个函数:

  1. setInterval(function,time);第一个参数为要执行的方法,第二个参数为每隔多少时间执行一次,此函数有返回值,当调用停止定时函数时,需要传入此setInterval()方法的返回值,来结束此函数
    例如:var int = setInterval(…. , …);

  2. clearInterval(obj);方法参数为setInterval()方法的返回值,用来结束定时函数
    例如:var int = setInterval(…. , …);
    clearInterval(int);

下面为下载代码示例:

进度条工具类ProgressBarThread:

public class ProgressBarThread implements Runnable{

    private ArrayList<Integer> proList = new ArrayList<Integer>();
    private int progress;//当前进度
    private int totalSize;//总大小
    private boolean run = true;
    private java.text.DecimalFormat df =
                new java.text.DecimalFormat("#.00");//格式化数字 
    //进度(百分比)
    private String sum ; 
    public ProgressBarThread(int totalSize){
        this.totalSize = totalSize;
        //创建进度条
    }
    //获取总进度(百分比)
    public String total(){
        return sum;
    }

    /**
     * @param progress 进度
     */
    public void updateProgress(int progress){
        synchronized (this.proList) {
            if(this.run){
                this.proList.add(progress);
                this.proList.notify();
            }
        }
    }

    public void finish(){
        this.run = false;
        //关闭进度条
    }

    @Override
    public void run() {
        synchronized (this.proList) {
            try {
                while (this.run) {
                    if(this.proList.size()==0){
                        this.proList.wait();
                    }
                    synchronized (proList) {
                        this.progress += this.proList.remove(0);
                        //更新进度条
                        sum = df.format((int)(((float)this.progress/this.totalSize)*100));
                        sum = sum.substring(0, sum.indexOf("."));
                        System.out.println("当前进度:"+sum+"%");
                    }
                }
                System.err.println("下载完成");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

Controller后台

@Controller
@RequestMapping("download")
public class DownloadController {
    //创建进度条
    //必须要定义为全局变量,这样前台才能访问进度,且一个用户一个进度
    private ProgressBarThread  pbt;

    /**
     * @author 佳。
     * @date 2016年3月11日
     * @Description: 获取进度
     * @param: @param request
     * @param: @param response 
     * @return void  
     * @throws
     */
    @RequestMapping("total")
    public void text1(HttpServletRequest request , HttpServletResponse response){
        //设置输出文本格式
        response.setContentType("application/json;charset=utf-8");
        //获取进度
        String total = pbt.total();
        //创建JSON
        JSONObject json = new JSONObject();
        //存储进度
        json.put("total", total);
        try {
            //向前台返回进度
            response.getWriter().write(json.toJSONString());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * @author 佳。
     * @date 2016年3月11日
     * @Description: 跳转至下载页面
     * @param: @param request
     * @param: @return 
     * @return String  
     * @throws
     */
    @RequestMapping("text")
    public String text(HttpServletRequest request){
        return "text/text";
    }

    /**
     * @author 佳。
     * @date 2016年3月7日
     * @Description: 文件下载
     * @param: @param fileName 文件名称
     * @return String  返回值为null
     * @throws
     */
    @RequestMapping(value = "download")
    public void download(String fileName, HttpServletRequest request,
            HttpServletResponse response) {
        response.setCharacterEncoding("utf-8");
        response.setContentType("multipart/form-data");
        response.setHeader("Content-Disposition", "attachment;fileName="
                + fileName);

        try {
            //  /WEB-INF/download文件夹的根目录
            String path = request.getSession().
                    getServletContext().getRealPath("/WEB-INF/download");

            // 获取相应文件的流
            // File.separator(Windows系统为'/')
            File file = new File(path + File.separator + fileName);
            //创建进度条
            pbt = new ProgressBarThread((int)file.length());
            //开启线程,刷新进度条
            new Thread(pbt).start();

            //设置文件长度
            response.setHeader("Content-Length", (int)file.length()+"");
            //IO流复制
            InputStream inputStream = new FileInputStream(file);
            OutputStream os = response.getOutputStream();
            byte[] b = new byte[2048];
            int length;
            while ((length = inputStream.read(b)) > 0) {
                os.write(b, 0, length);
                //写完一次,更新进度条
                pbt.updateProgress(length);
            }
            //文件读取完成,关闭进度条
            pbt.finish();
            // 释放资源 
            os.close();

            inputStream.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

JSP前端:

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>文件下载</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0"> 

    <!-- 引入三个读取CSS框架 -->
    <link href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" rel="stylesheet">
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js"></script>
    <!-- 引入jQuery -->   
    <script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-2.1.4.js"></script>
    <script type="text/javascript">
        window.onload = function (){
            document.getElementById("load").onclick = function (){
                //调用JS封装的方法,实现文件下载
                downLoad('${pageContext.request.contextPath }/download/download','myeclipse.exe');
                //定时访问进度
                var int = setInterval(function(){
                    $.ajax({
                        type : 'POST',
                        //访问此url,用来返回进度
                        url : '${pageContext.request.contextPath }/download/total',
                        success:function(data){
                            var total = data.total;
                            if(total=='100'){
                                //设置下载进度
                                $('#proBar').css('width','100%');
                                alert("下载完成");
                                //结束当前定时任务,
                                //clearInterval(int)方法的参数为setInterval的变量名
                                //var int = setInterval...
                                clearInterval(int);
                            }else{
                                //设置下载进度
                                $('#proBar').css('width',total+'%');
                                //alert(total); 
                            }
                        }
                    });
                //100毫秒调用一次
                },100);
            }
        }

        /*
            JS实现文件下载:
                利用jQuary绘制一个隐藏表单
                表单里只有一个hidden隐藏域,域的value为文件名
                绘制完毕后自动提交,访问后台Controller,实现文件下载

                参数:
                    fromAction:要提交的URL路径
                    fileName:要下载的文件名称

                例如:fromAction:'${pageContext.request.contextPath }/download/download'
                     fileName  :'jQuery.txt'
        */
        function downLoad(fromAction,fileName) { 
            var form = $("<form>");   //定义一个form表单
            form.attr('id','form');
            form.attr('style', 'display:none');   //在form表单中添加查询参数
            form.attr('target', '');
            form.attr('method', 'post');
            form.attr('action', fromAction+'');

            var input1 = $('<input>');
            input1.attr('type', 'hidden');
            input1.attr('name', 'fileName');
            input1.attr('value', fileName+'');
            //将内置表单添加在页面中 
            $('body').append(form);  
            //将隐藏域添加到表单上
            form.append(input1);  
            form.submit();
         }
    </script>

  </head>

  <body>
    <br/>
    <input type="button" value="文件下载" id="load" style="position: relative;left:500px;"/>
    <br/><br/>

    <div class="progress" style="width: 300;position: relative;left:500px;">
    <div class="progress-bar" role="progressbar" aria-valuenow="60" 
      aria-valuemin="0" aria-valuemax="100" style="width: 0%;" id="proBar">
        <span class="sr-only">40% 完成</span>
    </div>
</div>
  </body>
</html>
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值