excel导出百万数据与进度条展示

news/2024/7/21 4:28:21 标签: excel, 大数据, java, spring boot, vue.js, 数据库

前言

需求:用户在UI界面上选择想要导出的列,然后点击导出按钮,就能导出用户想要的数据。

效果展示

在这里插入图片描述

可能会产生的问题
1.如果同步到数据,接口很容易造成超时。
2.如果把数据一次性装载到内存里,很容易造成OOM与GC。
3.如果数据量太大sql语句查询也会很慢。

以下是批量导出解决的方案,如有更好的办法请支持。

1.在pom文件中导入poi的包

		<poi.version>4.1.2</poi.version>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>${poi.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>${poi.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>${poi.version}</version>
		</dependency>

2.查询导出数据条数

select count(id) from you_table_name;

3.通过总条数计算需要进行几次分页查询
每次查询20w条数据,每次向excel输出1w条,减轻对内存的压力,已经减少用户等待时长。

java"> int pageSize = 200000;  // 每页显示的记录数
 if (totalCount > 200000) {
  int totalPages = (int) Math.ceil((double) totalCount / pageSize);
  for (int page = 1; page <= totalPages; page++) {
   int offset = (page - 1) * pageSize;
   //组装SQL语句
   Map<String, Object> sqlParamsMap = getDownloadOrgDataLimit(filters, filedList, offset, pageSize);
   String sql = (String) sqlParamsMap.get("sql");
   //查询数据
   List<Map<String, String>> dataset = listOfSQL(sql.toString());
   int totalSize = dataset.size();
   //定义每次只输出1万条
   int batchSize = 10000;
   for (int i = 0; i < totalSize; i += batchSize) {
       int endIndex = Math.min(i + batchSize, totalSize);
       //批次
       List batch = Arrays.asList(dataset.toArray()).subList(i, endIndex);
       Iterator<Map> it = batch.iterator();
        while (it.hasNext()) {
        	Row row = sheet.createRow(index);
        	//循环输出数据...
		}
    }
  }
 }

4.为了让UI界面更直观的观察到导出进度可以加一个进度条

 //导出的进度条信息
   double dPercent=(double)index/totalCount;   //将计算出来的数转换成double
   int  percent=(int)(dPercent*100);               //再乘上100取整
   request.getSession().setAttribute("curCount", index);
   request.getSession().setAttribute("percent", percent);    //比如这里是50
   request.getSession().setAttribute("percentText",percent+"%");//这里是50%
   //...也可以增加当前导出条数,剩余条数

5.前端需要频繁获取进度条进度

			//下载数据
 			downloadOrgData(){
 					//将刷新进度条状态打开
                    this.downloadFlag=true;
                    //执行进度条刷新方法
                    this.flushProgress();
                    axios.get("/org/orgDataDownload/",{
                        params:{
                            filedList: this.filedList.toString()
                        },
                        timeout:600000,
                        responseType:'blob'
                    }).then(res=>{
                        var blob = new Blob([res.data])
                        let fileName =  decodeURI(res.headers['content-disposition'].split("filename= ")[1])
                        var downloadElement = document.createElement('a');
                        var href = window.URL.createObjectURL(blob); //创建下载的链接
                        downloadElement.href = href;
                        downloadElement.download = fileName; //下载后文件名
                        document.body.appendChild(downloadElement);
                        downloadElement.click(); //点击下载                  
                        document.body.removeChild(downloadElement); //下载完成移除元素  
                        window.URL.revokeObjectURL(href); //释放掉blob对象
                        this.downloadFlag=false;    //关闭状态
                    })
                },
 			flushProgress(){
                    $.ajaxSettings.async = false;
                    //刷新进度条
                  if (this.downloadFlag){
                      window.setTimeout(function(){
                          var timer=window.setInterval(function(){
                              axios.get("/org/flushProgress").then(res=>{
                                  let progress =  res.data.data.map.percent;

                                  const progressBar = document.querySelector('.progress');
                                  const progressText = document.querySelector('.progress-text');
                                  if (progress===null){
                                      progressText.innerText = `数据准备中`;
                                  }else if (progress===100){
                                      progressText.innerText = `文档下载中`;
                                  } else {
                                      progressBar.style.width = `${progress}%`;
                                      progressText.innerText = `${progress}%`;
                                  }
                                  if(res.data.data.map.percent=="100"){
                                      window.clearInterval(timer);
                                  }
                              })
                          },800);
                      },800);
                  }
                    $.ajaxSettings.async = true;
                },

其他方案:如果请求超时时间太长,配置也不能修改的情况下,可以使用异步导出。
1.导出成功后将excel上传到OSS,用户直接下载OSS中文件。
2.导出成功后将消息发送到mq中,mq消费消息时通知用户下载excel.


http://www.niftyadmin.cn/n/455143.html

相关文章

❤ vue3 组件传值

❤ vue3 组件传值 [1] 子组件向父组件传值 使用emit使用方法 【子组件】 1、定义 emits,emits的定义是与component、setup等这些属性是同级 emits此时是作为数组&#xff0c;它也可以接收一个对象 2、使用 setup(props, { emit, refs }) {emit(addImg, 参数); }有时候需使…

web基础---css函数,命名规则

1.相等&#xff08;&#xff09;&#xff0c;属于非严格相等 检查两个操作数是否相等&#xff0c;会比较不同类型的操作数&#xff0c;并尝试强制转换类型 2.严格相等&#xff08;&#xff09; 不会尝试类型转换&#xff0c;认为不同类型的操作数是不同的 3.javascript 对大…

论文阅读笔记3:Patch-NetVLAD

题目&#xff1a;Patch-NetVLAD: Multi-Scale Fusion of Locally-Global Descriptorsfor Place Recognition 团队&#xff1a;澳大利亚昆士兰理工大学&#xff0c;电气工程与机器人学院和QUT机器人中心 解决的问题&#xff1a;克服视点和外观变化的双重问题 创新点&#xff…

Goby 漏洞发布|PandoraFMS 软件 upload_head_image.php 任意文件上传漏洞

漏洞名称&#xff1a;PandoraFMS 软件 upload_head_image.php 任意文件上传漏洞 English Name&#xff1a;PandoraFMS upload_head_image.php Arbitrary File Upload Vulnerability CVSS core: 9.0 影响资产数&#xff1a;768 漏洞描述&#xff1a; PandoraFMS是美国Pando…

使用数据泵+ogg同步oracle数据

本次迁移背景&#xff1a; 机房要搬迁&#xff0c;新搭建了一套oracle数据库&#xff0c;计划不停机迁移&#xff0c;将源端旧库的数据迁移到目标端新库里。 原本想用RMAN方式迁移&#xff0c;但是由于旧库是AIX系统&#xff0c;新库是linux系统&#xff0c;用RMAN迁移会有问…

准备换工作跳槽面试人一定要看的的18条忠告

1、如果想好要跳槽就别犹豫&#xff0c;不用纠结太多外在因素&#xff0c;很多事情只有去做了才知道。&#xff08;当然&#xff0c;如果你是非某家公司不可的话&#xff0c;那可以慢慢等待机会&#xff09; 2、关于跳槽的渠道&#xff0c;主要有四种&#xff1a;直接被公司挖…

干货分享 | TSMaster标定模块自动化控制应用指南

本文目录&#xff1a; 一、TSMaster标定模块自动化控制的基础原理 1.1 TSMaster的标定系统变量 1.2 内部TSMaster调用C脚本实现标定模块的自动化控制 1.3 外部调用COM组件实现自动化标定 二、标定自动化控制场景与TSMaster实例 2.1 C脚本实现控制标定模块的启动与关闭的设…

JUC高级-0620

8. CAS 原子类&#xff1a;Atomic没有CAS之前&#xff1a;多线程环境不使用原子类保证线程安全i&#xff08;基本数据类型&#xff09;&#xff0c;可以使用synchronized&#xff0c;但是很重有CAS之后&#xff1a; 使用AtomicInteger.getAndIncrement这样的API&#xff0c;保…