Java文件下载,HTML进度条实时刷新进度

效果展示

这里写图片描述

实现原理

1:后台同步进程开始下载文件
2:前台使用遮罩效果,使页面不能点击,使用circliful进度条插件(插件源码见后)
3:页面使用JavaScript定时器发送ajax请求刷新进度条数据
4:当进度满100的时候,遮罩消失,文件开始保存到本地
5:后台使用SpringMVC,其中使用session来保存当前下载的数据进度,因为下载文件的进度和刷新的进度是不同的方法,下载文件的方法需要将数据存储到一个地方,供进度条方法来获取数据。

代码如下

HTML样式

#Mask {
     position: absolute; top: 0px; filter: alpha(opacity=60); background-color: #333;
     z-index: 1002; left: 0px;
     opacity:0.5; -moz-opacity:0.5;
}
#Progress{
    position: absolute; top: 35%;left:35%;z-index: 2000;
}
#Progress .circle-info{
    color:black;
}
<!---Mask是遮罩,Progress是进度条->
<div>
      <div id="Mask"></div>
      <div id="Progress" data-dimension="250" data-text="0%" data-info="导出进度" data-width="30" data-fontsize="38" data-percent="0" data-fgcolor="#61a9dc" data-bgcolor="#eee"></div>
  </div>

js刷新进度请求

因为插件问题,所以需要判断是不是第一次导出数据,如果是第一次,则执行circliful()方法,如果不是,则直接显示原来创建的#Progress对象,否则会显示多个进度条在页面上。各种常见问题的处理都已做判断处理,比如第二次下载,进度一下显示为100%等。直接拷贝进去就可以使用。

    //显示进度条
	var isFirstExport=true;
    function showProgress(){
        $("#Mask").css("height",$(document).height());
        $("#Mask").css("width",$(document).width());
        $("#Mask").show();
        if(isFirstExport){
            $("#Progress").circliful();
        }else{
            $("#Progress .circle-text").text("0%");
            $("#Progress .circle-info").text("导出进度");
	        $("#Progress").show();
        }
    }  
    //隐藏进度条
    function hideProgress(){
        $("#Mask").hide();
        $("#Progress").hide();
    }
    function onZipAll() {
        //这里开始下载文件
	    var formData=$("#form_id").serialize();
        location.href="${root}/record/v_seal_excel_all.do?"+formData;
         //Ajax刷新进度条
         showProgress();
         window.setTimeout(function(){
            var timer=window.setInterval(function(){
              $.ajax({
                 type:'post',
                  dataType:'json', 
                  url: "${root}/record/flushProgress.do",
                  success: function(data) {
                      $("#Progress .circle-text").text(data.percentText);
                      if(data.curCount===undefined||data.totalCount===undefined){
                          $("#Progress .circle-info").text("导出进度");
                      }
                      else{
                           $("#Progress .circle-info").text("导出进度:"+data.curCount+"/"+data.totalCount);
                      }
                      if(data.percent=="100"){
                          window.clearInterval(timer);
                          hideProgress();
                      }
                  },
                  error:function(data){}
               });
            },200);
         },200);
         isFirstExport=false;
    }

SpringMVC进度条刷新方法

/**
     * 进度条刷新,数据从session当中取
     */
    @RequestMapping(value = "/flushProgress3.do")
    @ResponseBody
    public String flushProgress3(HttpServletRequest request) throws Exception
    {
        HashMap<String,Object> map=null;
        try {
            HttpSession session = request.getSession();
            map=new HashMap<String, Object>();
            map.put("totalCount", session.getAttribute("totalCount"));  //总条数
            map.put("curCount", session.getAttribute("curCount"));      //已导条数
            map.put("percent", session.getAttribute("percent"));          //百分比数字
            map.put("percentText", session.getAttribute("percentText"));  //百分比文本
        } catch (Exception e) {
            e.printStackTrace();
        }
        return JSON.toJSONString(map);
    } 

###SpringMVC数据下载记录进度方法

@RequestMapping(value = "/download")
    public void download( HttpServletRequest request) throws Exception {
            //首先需要移除掉session当中的数据,因为如果是第二次下载数据的话,这些数据已经存在
            //会导致进度条先是100%的状态,然后才从0%开始
            request.getSession().removeAttribute("totalCount");
            request.getSession().removeAttribute("curCount");
            request.getSession().removeAttribute("percent");
            request.getSession().removeAttribute("percentText");
            
            //计算百分比,这里将下载数据的过程省略,需要有总数和当前数,总数应该是不变的,而当前数会不断变化,比如每循环一次加1等,因此会一直不断的写入到session当中,这里重点是计算百分数
            ++curCount;
            double dPercent=(double)curCount/totalCount;   //将计算出来的数转换成double
            int percent=(int)(dPercent*100);               //再乘上100取整
            request.getSession().setAttribute("curCount", curCount);
            request.getSession().setAttribute("percent", percent);    //比如这里是50
            request.getSession().setAttribute("percentText",percent+"%");//这里是50%
     }

附:插件源码

circliful插件源码,包含一个css和一个js,使用的时候直接引入到html当中即可

CSS

.circliful {
    position: relative; 
}

.circle-text, .circle-info, .circle-text-half, .circle-info-half {
    width: 100%;
    position: absolute;
    text-align: center;
    display: inline-block;
}

.circle-info, .circle-info-half {
	color: #999;
}

.circliful .fa {
	margin: -10px 3px 0 3px;
	position: relative;
	bottom: 4px;
}

JS

    (function( $ ) {
 
    $.fn.circliful = function(options) {
        
        var settings = $.extend({
            // These are the defaults.
            foregroundColor: "#556b2f",
            backgroundColor: "#eee",
            fillColor: false,
            width: 15,
            dimension: 200,
            size: 15, 
			percent: 50,
            animationStep: 1.0
        }, options );
         return this.each(function() {
                var dimension = '';
                var text = '';
				var info = '';
                var width = '';
                var size = 0;
				var percent = 0;
				var endPercent = 100;
				var fgcolor = '';
				var bgcolor = '';
				var icon = '';
                var animationstep = 0.0;
    
                $(this).addClass('circliful');
    
                if($(this).data('dimension') != undefined) {
                    dimension = $(this).data('dimension');
                } else {
                    dimension = settings.dimension;
                }
    
                if($(this).data('width') != undefined) {
                    width = $(this).data('width');
                } else {
                    width = settings.width;
                }
    
                if($(this).data('fontsize') != undefined) {
                    size = $(this).data('fontsize');
                } else {
                    size = settings.size;
                }
				
				if($(this).data('percent') != undefined) {
                    percent = $(this).data('percent') / 100;
					endPercent = $(this).data('percent');
                } else {
                    percent = settings.percent / 100;
                }
				
				if($(this).data('fgcolor') != undefined) {
                    fgcolor = $(this).data('fgcolor');
                } else {
                    fgcolor = settings.foregroundColor;
                }
				
				if($(this).data('bgcolor') != undefined) {
                    bgcolor = $(this).data('bgcolor');
                } else {
                    bgcolor = settings.backgroundColor;
                }
				
                if($(this).data('animation-step') != undefined) {
                    animationstep = parseFloat($(this).data('animation-step'));
                } else {
                    animationstep = settings.animationStep;
                }
                if($(this).data('text') != undefined) {
                    text = $(this).data('text');
					
					if($(this).data('icon') != undefined) {
						icon = '<i class="fa ' + $(this).data('icon') + '"></i>';
					}
					
					 if($(this).data('type') != undefined) {
						type = $(this).data('type');
					
						if(type == 'half') {
							$(this).append('<span class="circle-text-half">' +  icon  + text + '</span>');
							$(this).find('.circle-text-half').css({'line-height': (dimension / 1.45) + 'px', 'font-size' : size + 'px' });
						} else {
							$(this).append('<span class="circle-text">' + icon + text + '</span>');
							$(this).find('.circle-text').css({'line-height': dimension + 'px', 'font-size' : size + 'px' });
						}
					} else {
						$(this).append('<span class="circle-text">' + icon + text + '</span>');
						$(this).find('.circle-text').css({'line-height': dimension + 'px', 'font-size' : size + 'px' });
					}
                } else if($(this).data('icon') != undefined) {
				
				}
				
				if($(this).data('info') != undefined) {
                    info = $(this).data('info');
					
					if($(this).data('type') != undefined) {
						type = $(this).data('type');
					
						if(type == 'half') { 
							$(this).append('<span class="circle-info-half">' + info + '</span>');
							$(this).find('.circle-info-half').css({'line-height': (dimension * 0.9) + 'px', });
						} else {
							$(this).append('<span class="circle-info">' + info + '</span>');
							$(this).find('.circle-info').css({'line-height': (dimension * 1.25) + 'px', });
						}
					} else {
						$(this).append('<span class="circle-info">' + info + '</span>');
						$(this).find('.circle-info').css({'line-height': (dimension * 1.25) + 'px', });
					}
                }
    
                $(this).width(dimension + 'px');
				
              var canvas = $('<canvas></canvas>').attr({ width: dimension, height: dimension }).appendTo($(this)).get(0);
              var context = canvas.getContext('2d');
              var x = canvas.width / 2;
              var y = canvas.height / 2;
			  var degrees = percent * 360.0;
			  var radians = degrees * (Math.PI / 180);
              var radius = canvas.width / 2.5;
              var startAngle = 2.3 * Math.PI;
              var endAngle = 0;
              var counterClockwise = false;
              var curPerc = animationstep === 0.0 ? endPercent : 0.0;
              var curStep = Math.max(animationstep, 0.0);
			  var circ = Math.PI * 2;
			  var quart = Math.PI / 2;
			  var type = '';
			  var fill = false;
			  
			  if($(this).data('type') != undefined) {
                    type = $(this).data('type');
					
					if(type == 'half') {
						var startAngle = 2.0 * Math.PI;
						var endAngle = 3.13;
						var circ = Math.PI * 1.0;
						var quart = Math.PI / 0.996;
					}
                }
				
				if($(this).data('fill') != undefined) {
					fill = $(this).data('fill');
				} else {
					fill = settings.fillColor;
				}
			  //animate foreground circle
			  function animate(current) {
				context.clearRect(0, 0, canvas.width, canvas.height);
				 
				context.beginPath();
				context.arc(x, y, radius, endAngle, startAngle, false);
				context.lineWidth = width - 1;
		
				// line color
				context.strokeStyle = bgcolor;
				context.stroke();

				if(fill) {
					context.fillStyle = fill;
					context.fill();
				}
				 
				context.beginPath();
				context.arc(x, y, radius, -(quart), ((circ) * current) - quart, false);
				context.lineWidth = width;
				// line color
				context.strokeStyle = fgcolor;
				context.stroke();

				if (curPerc < endPercent) {
  				     curPerc += curStep;
					 requestAnimationFrame(function () {
						 animate(Math.min(curPerc, endPercent) / 100);
					 });
				}
				
			 }

			 animate(curPerc / 100);

        });
 
    };
 
}( jQuery ));
  • 5
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
要在Java中实现实时读取进度的功能,你可以使用线程和回调函数来实现。下面是一个简单的示例: 首先,定义一个接口 `ProgressCallback`,其中包含一个用于接收进度更新的回调方法 `onProgressUpdate`: ```java public interface ProgressCallback { void onProgressUpdate(int progress); } ``` 然后,在你的主程序中创建一个实现了该接口的类,并实现 `onProgressUpdate` 方法,以便在每次更新进度时执行相应的操作: ```java public class ProgressBar implements ProgressCallback { @Override public void onProgressUpdate(int progress) { // 在这里更新进度条或执行其他操作 System.out.println("当前进度:" + progress + "%"); } } ``` 接下来,在你的主程序中创建一个线程来模拟进度更新,并在每次更新时调用回调方法: ```java public class Main { public static void main(String[] args) { ProgressBar progressBar = new ProgressBar(); // 创建一个线程来模拟进度更新 Thread progressThread = new Thread(new Runnable() { @Override public void run() { for (int i = 0; i <= 100; i++) { // 模拟耗时操作 try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 更新进度 progressBar.onProgressUpdate(i); } } }); // 启动线程 progressThread.start(); } } ``` 在上面的示例中,`ProgressBar` 类实现了 `ProgressCallback` 接口,并在 `onProgressUpdate` 方法中打印当前进度。然后,创建一个线程 `progressThread` 来模拟进度更新,每次更新时调用 `progressBar.onProgressUpdate` 方法。 当你运行上述代码时,你将看到每秒钟输出一次当前进度的消息,模拟了实时读取进度的功能。你可以根据实际需求,在 `onProgressUpdate` 方法中执行你想要的操作,比如更新进度条的显示或执行其他相关任务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值