如何实现一个前后端实时通信的进度条功能

1、需求背景
我们的产品有个下载导出成员信息表单的功能,但当数据量大的时候,处理时间较长,客户希望能有个进度条显示下载的进度,在焦急等待的时候,有个心理安慰


2、开发工具及框架
SpringBoot + Maven +JDK8


3、整体思路
数据传输的主要途径:request.session
(1)前端页面编写调试
(2)后端最短路径传输模拟数据,调试
(3)后端业务逻辑处理,传输真实数据
(4)前端操作、页面优化

进度条最终效果
1\点击“导入excel表格”
在这里插入图片描述

2\刚下载完
在这里插入图片描述

3\下载完2秒左右关闭进度条


1. 前端页面编写

进度条核心标签:progress
js定时器:setInterval、setTimeout


思路:
① 如果你的项目和我一样,要运行后才能打开前端页面的话,建议自己新建一个项目,把前端页面调好后,再放到原项目中
② 调试过程中,如果你的百分数直接从0到100,没有中间的数字,一定是不对的,继续调整
③ 注意判断条件添加的位置:如果你的提示语显示顺序和百分数有关,那就一定要小心谨慎了,这里很有可能弄错

(1)测试代码编写:为便于调试,我把js代码也一并写到了html页面中(以下代码浏览器打开可直接运行)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>进度调测试5</title>
    <script>
        function download() {
            var  pro=document.getElementsByTagName( "progress" )[0];
            pro.style.display = 'block';
            var progressValue = document.querySelector('#progress-value');
            progressValue.style.display = 'block';
            var value = 0;

            setInterval(function() {
                if (value < 100){
                    value++;
                    pro.value = value;
                    progressValue.innerText = value + '%';
                }else {
                    progressValue.innerText = '下载完成';
                    setInterval(function (){
                        location.replace(location.href);
                    },2000);
                }
            }, 20);
        };
    </script>
</head>
<body>
<br/>
<span id="progress-value" hidden="hidden">0</span>
<progress value= "0"  max= "100" hidden="hidden">您的浏览器不支持progress标签</progress>

<br/>
<button onclick="download()">点击下载</button>
</body>
</html>

如何实现一个前后端实时通信的进度条功能_第1张图片
如何实现一个前后端实时通信的进度条功能_第2张图片

(2)测试代码运行没问题后,挪入项目中,修改的点有:

  • 将百分数和下载提示分成了2个标签;
  • 百分数改为从request中获取数据
//html代码:

<div style="position: relative;width: 175px;height: 100%;margin-left: calc(50% - 50px);display: inline-block">
    <progress value= "0"  max= "100" hidden="hidden">
        您的浏览器不支持progress标签
    </progress>
    <span id="progress-value" hidden="hidden" style="position: absolute;top:-4px;right:5px"></span>
    <p id="progress-tips" hidden="hidden" style="text-align: center;width: 122px"></p>
</div>
//js代码:在下载按钮的点击函数中调用以下函数:

function progressBar() {
   //显示进度条、百分数、提示语
   var pro = document.getElementsByTagName("progress")[0];
   pro.style.display = 'block';
   var progressValue = document.querySelector('#progress-value');
   progressValue.style.display = 'block';
   var progressTips = document.querySelector('#progress-tips');
   progressTips.style.display = 'block';
   progressTips.innerText = '';
   var value = 0;
   //设置定时器,每隔一段时间获取requestSession中的百分数
   var time = setInterval(function () {
      $.ajax({
         async: true,
         type: 'post',
         dataType: 'json',
         url: ctx + "/member/getPercent",
         //获取百分数成功,修改相关值
         success: function (data) {
            value = data.percent;
               pro.value = value;
               progressValue.innerText = value + '%';
               progressTips.innerText = '下载中';
            //下载完成后,请求刷新百分数,并在2秒后关闭标签
            if (value == "100"){
               progressTips.innerText = '下载完成!';
               setTimeout(function (){
                  $.ajax({
                     type: 'post',
                     dataType: 'json',
                     url: ctx + "/member/flushPercent",
                     success:function (){
                           pro.style.display = 'none';
                           progressValue.style.display = 'none';
                           progressTips.style.display = 'none';
                           pro.value = 0;
                           progressValue.innerText = '';
                     }
                  });
               },2000);
               clearInterval(time);
               return ;
            }
         },
      });
   }, 10);
};

2. 前后端打通

目的:主要是测试前端是否能成功获取到后端传来的数据并展示,所以直接选取一个最短路径来传输数据,在controller中新增如下两个接口。
这里在控制台打印percent,主要是方便查看程序运行中接口的调用情况(作用很大!!!不要省略!!!)


(这时不建议大家直接将业务层计算的百分数传给前端,增加数据传输流程,如果出问题的话,排查起来更慢。但嫌麻烦的话,也可以直接跳到第3步。)

//接口一:设置并获取百分数
HashMap<String, Object> map = new HashMap<>();
  try {
  	 request.getSession().setAttribute("percent",50);
    Object percent = request.getSession().getAttribute("percent");
    map.put("percent",percent);
  } catch (Exception e) {
    e.printStackTrace();
  }
String per = JSON.toJSONString(map);
System.out.println("2、获取到的百分数为" + per);

//接口二:刷新百分数
request.getSession().setAttribute("percent",null);
Object percent = request.getSession().getAttribute("percent");
System.out.println("3、刷新百分数为" + percent);

3. 后端传输真实业务数据

第三步没问题后,我们就直接处理实际的业务逻辑啦,计算真实的百分数,并拉通数据传输的通道

(1)本项目中的进度条主要是用来体现表格的下载进度,而表格下载的主要代码逻辑就在于,将成员数据写入表格里的这个过程。所以我这里的百分数,计算的方式是:
百分数 = 当前写入成员的序号 / 总成员数 * 100;

代码如下:

//设置百分数
//list是成员集合

for (int i = 0; i < list.size(); i++) {
    Double percent = (i + 1) / (double)list.size() * 100;
    //这里对小数采用向下取整,例如99.5会取整为99
    percent = Math.floor(percent);
    request.getSession().setAttribute("percent",percent);
    System.out.println("1、设置百分数为" + percent);
    }

(2)修改controller的两个接口

//获取百分数
@ResponseBody
@RequestMapping(value = "/getPercent")
public String getPercent(HttpServletRequest request) {
    HashMap<String, Object> map = new HashMap<>();
    try {
    Object percent = request.getSession().getAttribute("percent");
    map.put("percent",percent);
    } catch (Exception e) {
       e.printStackTrace();
    }
    String per = JSON.toJSONString(map);
    System.out.println("2、获取到的百分数为" + per);
    return per;
    }
    
//刷新百分数
@ResponseBody
@RequestMapping(value = "/flushPercent")
public void flushPercent(HttpServletRequest request) {
    request.getSession().setAttribute("percent",null);
    Object percent = request.getSession().getAttribute("percent");
    System.out.println("3、刷新百分数为" + percent);
}

(3)运行项目,测试。调试过程中,不要忘了看控制台打印的输出语句,对排查bug很有用哦

4. 调试优化

这里主要就是前端页面的优化啦~
我这个项目里,存在以下一个关键问题:
成员信息表格下载,后端逻辑处理主要是3个部分:
(1)根据用户选择的成员,遍历到数据库中查找成员信息;
(2)将成员信息写入到表格里
(3)将表格写入到流中,导出文件
过程(1)(2)都很耗时间,然而进度条只能反映过程(2)的进度,所以过程(1)还是需要用户等待。这时前端页面的优化为:在前端页面添加相关提示,提醒用户文件正在下载。


如果你从头到这里都没调通的话,建议就先只做进度条和百分数的展示(省去提示语),减少一些前端的判断。因为前后端拉通调的话,数据传输、判断的先后等细节都可能导致成功与你擦肩而过(别问我为什么知道


最后,如果有什么没讲清楚或可以完善优化地方,欢迎一起讨论;看完有收获就点个赞吧
bye~

参考文档:
progress bar(可参考前端页面进度条的实现)
SpringBoot如何实现一个实时更新的进度条的示例代码(可参考进度条实现的整体思路)

你可能感兴趣的:(功能实现,java,javascript,html,js)