只做演示,所以都写在Controller里面了;

1:添加EasyExcel的依赖

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.0.5</version><exclusions><exclusion><groupId>javax.servlet</groupId><artifactId>servlet.api</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId></exclusion><exclusion><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId></exclusion></exclusions></dependency>

1:定义线程池ThreadPoolConfig


import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import com.ahzx.common.utils.Threads;/*** 线程池配置***/
@Configuration
public class ThreadPoolConfig {// 核心线程池大小private int corePoolSize = 50;// 最大可创建的线程数private int maxPoolSize = 200;// 队列最大长度private int queueCapacity = 1000;// 线程池维护线程所允许的空闲时间private int keepAliveSeconds = 300;@Bean(name = "threadPoolTaskExecutor")public ThreadPoolTaskExecutor threadPoolTaskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setMaxPoolSize(maxPoolSize);executor.setCorePoolSize(corePoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);// 线程池对拒绝任务(无线程可用)的处理策略executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return executor;}}

1:定义EasyExcel导出的实体类

@Data
public class FmrInfoDtoEeayExcel {@ExcelProperty(value = "ID")private String homeNo;@ExcelProperty(value = "等级")private String rank;@ExcelProperty(value = "分数")private Integer score;@ExcelProperty(value = "状态")private String scoreStatus;//多余的一些字段...}

2:定义Controller

 @PostMapping("/exportAll")public synchronized void exportAll(HttpServletResponse response) {log.info("sql分页导出excel....");//用于计算方法运行时间,为了方便直接用DataDate start = new Date();//定义easyExcel导出的对象ExcelWriter excelWriter = null;//导出的文件名String fileName = "/tmp/导出的excel文件名称.xlsx";//主要进行处理的方法,用于返回需要的集合List<FmrInfoDtoEeayExcel> listFaram = this.multiThreadList();try{excelWriter = EasyExcel.write(fileName,FmrInfoDtoEeayExcel.class).build();WriteSheet writeSheet = EasyExcel.writerSheet("sheet1").build();excelWriter.write(listFaram,writeSheet);Date end = new Date();String datePoor = DateUtils.getDatePoor(end, start);log.info("导出耗时:" + datePoor);} catch(Exception e){logger.debug("文件导出报错,{}",e.getMessage());}finally {if(excelWriter != null ){excelWriter.finish();}}}

3:定于multiThreadList方法

//定义PAGENUM 也就是每个线程查询的页数
private static final int PAGENUM = 5000;private  List<FmrInfoDtoEeayExcel> multiThreadList(){//定义多线程的任务List<FutureTask<List<FmrInfoDtoEeayExcel>>> tasks =  new ArrayList<>();//定义导出的集合List<FmrInfoDtoEeayExcel> fmrInfoDtoEeayExcelList = new ArrayList<>();//查询要导出表的总数long count = tbFmrInfoService.selectTbFmrInfoCount();//计算开启的线程数int loopNum = new Double(Math.ceil((double)count / PAGENUM )).intValue();logger.info("多线程查询,总数:{},开启线程数:{}",count,loopNum);executeTask(tasks,loopNum,count);for(FutureTask<List<FmrInfoDtoEeayExcel>> task : tasks){try{fmrInfoDtoEeayExcelList.addAll(task.get());}catch(Exception e){logger.debug("出错了:{}",e.getMessage());}}return fmrInfoDtoEeayExcelList;}

4:定义executeTask方法

private void executeTask(List<FutureTask<List<FmrInfoDtoEeayExcel>>> tasks, int loopNum, long count) {for (int i = 0; i < loopNum; i++) {Map<String, Object> map = new HashMap<>();map.put("offset", i * PAGENUM);if( i == loopNum -1 ){map.put("limit",count - PAGENUM * i);}else{map.put("limit",PAGENUM);}FutureTask<List<FmrInfoDtoEeayExcel>> task =  new FutureTask<>(new listThread(map));logger.info("开始查询第{}条开始的{}条记录",i * PAGENUM, PAGENUM);//new Thread(task).start();threadPool.threadPoolTaskExecutor().execute(task);tasks.add(task);}}

5:定于多线程处理的内部类

//因为数据不在同一个表里面,所以查多张表,进行处理private class listThread implements Callable<List<FmrInfoDtoEeayExcel>> {private final Map<String, Object> map;public listThread(Map<String, Object> map) {this.map = map;}@Overridepublic List<FmrInfoDtoEeayExcel> call() throws Exception {//分页查询出5000条主表数据List<FmrInfoDtoEeayExcel> fmrInfoDtos  = tbFmrInfoMapper.selectTbFmrInfoRankListPage(map);//用stream流处理编号,提取出编号的集合List<String> homeNoList = fmrInfoDtos.stream().map(s -> s.getHomeNo()).collect(Collectors.toList());//用编号集合去另外一个表里面查这个对象的分数List<GradeScore> gradeScore = gradeRankMapper.selectScoreByFrmIdList(homeNoList);//查出分数的集合,将两个集合根据一定的要求进行字段处理fmrInfoDtos.forEach(e -> {if (StringUtils.isNotNull(e.getRank())) {e.setScoreStatus("已评分");} else {e.setScoreStatus("未评分");}//处理身份证号码if (StringUtils.isNotEmpty(e.getCardNo())) {e.setBirthDay(StringUtils.substring(e.getCardNo(), 6, 14));}//两者id相同,则将查出来的分数进行赋值处理gradeScore.forEach(n -> {if (e.getHomeNo().equals(n.getObjectNo())) {e.setScore(n.getScore().intValue());}});});return fmrInfoDtos;}}

6:对应的mapper文件

//tbFmrInfoService.selectTbFmrInfoCount();public Long selectTbFmrInfoCount() {return tbFmrInfoMapper.selectTbFmrInfoCount();}<select id="selectTbFmrInfoCount" parameterType="com.ahzx.credit.domain.TbFmrInfo" resultType="java.lang.Long">SELECT count(*)FROMt_collect_farmer tfi
</select>// tbFmrInfoMapper.selectTbFmrInfoRankListPage(map);<select id="selectTbFmrInfoRankListPage" parameterType="java.util.Map" resultMap="TbFmrInfoExcelResult">SELECTa.object_no home_no,b.cgroupFROMgrade_rank a,t_collect_farmer b,//先将id查询出来再去查询想要的数据用id驱动,查询效率会快很多,注意关注索引值( SELECT id FROM t_collect_farmer WHERE STATUS != 0 LIMIT #{offset}, #{limit} ) temp<where>a.object_no = temp.idAND b.id = temp.idAND a.object_type = 'fmr'</where>order by a.object_no asc</select>//gradeRankMapper.selectScoreByFrmIdList(homeNoList);此处使用in查询
<select id="selectScoreByFrmIdList" resultMap="TbGradeScore">SELECT object_no, IFNULL(sum(score),0) scoreFROM grade_scoreWHERE object_no in<foreach item="item" index="index" collection="list"open="(" separator="," close=")">#{item}</foreach>GROUP BY object_no
</select>

7:至此多线程文件导出完毕,其中线程池的那边和sql还有优化空间,整个数据大概40w,处理完毕大概20s左右,我感觉还是很慢,写的还是有问题,仅供参考,如果有更好的方法希望可以多加讨论

使用EasyExcel进行百万数据文件导出思路相关推荐

  1. 百万数据报表导出:需求以及思路分析

    百万数据报表导出 需求分析 使用Apache POI完成百万数据量的Excel报表导出 解决方案 思路分析 基于XSSFWork导出Excel报表,是通过将所有单元格对象保存到内存中,当所有的Exce ...

  2. POI报表及百万数据导入导出方案

    1.POI报表的概述 1.1 需求说明 在企业级应用开发中,Excel报表是一种最常见的报表需求.Excel报表开发一般分为两种形式:为了方便操作,基于Excel的报表批量上传数据:通过java代码生 ...

  3. POI报表入门及百万数据报表导出和读取

    POI报表概述 需求说明 在企业级应用开发中,Excel报表是一种最常见的报表需求.Excel报表开发一般分为两种形式: 为了 方便操作,基于Excel的报表批量上传数据 通过java代码生成Exce ...

  4. 巧用千寻位置GNSS测绘软件| 数据文件导出技巧

    日常进行测量放样或者是静态数据采集等作业时,都需要将这些数据进行导出.使用千寻位置GNSS测绘软件可快速完成项目数据和道路断面的数据导出.本期带来具体的操作技巧,方便测绘朋友在短时间内完成数据文件导出 ...

  5. 报表技术2(百万数据导入导出,POI操作word)

    POI模板导出,操作word 导出用户详情数据(图片,公式处理) 使用模板导出用户详细信息 使用模板引擎 1.编写模板引擎 2.使用模板引擎 百万数据导出 代码实现: 百万数据导入 步骤分析: 1.自 ...

  6. 百万数据报表导出:使用SXSSFWorkbook完成百万数据报表打印

    在原有代码的基础上替换之前的XSSFWorkbook,使用SXSSFWorkbook完成创建过程即可 /*** 当月人事报表导出* 参数:* 年月-月(2018-02%)*/ @RequestMapp ...

  7. 百万数据报表导出:原理分析与总结

    对比测试 (1)XSSFWorkbook生成百万数据报表 使用XSSFWorkbook生成Excel报表,时间较长,随着时间推移,内存占用原来越多,直至内存溢出 (2)SXSSFWorkbook生成百 ...

  8. 面试官问百万数据excel导出功能如何实现?

    文章目录 背景 实现 1.异步处理 1.1 使用job 1.2 使用mq 2.使用easyexcel 4.多个sheet 5.计算limit的起始位置 6.文件上传到OSS 7.通过WebSocket ...

  9. SpringBoot使用EasyExcel 模板填充数据并导出,以及Excel导入解析入库

    需求 1.导出Excel模板,第一个sheet为用户基本信息,默认只有表头,用户手动填写后续用来导入人员信息.第二个sheet为组织架构信息,默认从数据库查询组织信息,方便用户查询组织编码. 2.导入 ...

最新文章

  1. Kotlin协程使用,协程使用注意事项,协程中的await方法使用|不使用suspend使用协程
  2. HTML5学习笔记简明版(3):新元素之hgroup,header,footer,address,nav
  3. 如何用cmd命令控制mysql数据库
  4. Mac下使用svn命令
  5. 什么是线程池,连接池,线程池和连接池之间的区别
  6. python define function的顺序_Python怎么根据一个函数来决定列表顺序
  7. 30人团队的数据架构师:谈谈数据湖这个风口吧,你们说的都没价值
  8. Dockerfile文件中CMD指令与ENTRYPOINT指令的区别
  9. Linux 命令(11)—— col 命令
  10. IS-IS详解(七)——IS-IS LSP报文详解
  11. 全国省市区三级数据库sql
  12. sap 流程图 退货销售订单_ERP系统:退货流程的解决方案
  13. 量子计算机宋超,蒿杰团队实感计算架构助力20超导量子比特薛定谔猫态制备-资讯-知识分子...
  14. 【ES6】Promise
  15. 【整理】学习Android Studio时遇到的错误及解决方法(持续更新)
  16. App如何在background状态下存活
  17. 我的同学是计算机作文,我的同桌作文
  18. 画火柴人动画的手机软件_火柴人动画制作软件(Pivot Stickfigure Animator)2.25 中文版附教程...
  19. Oracle-enq: TX - row lock contention 等待事件分析
  20. 1.5 黑群晖安装后洗白的三种方法 教程

热门文章

  1. matlab画图常见问题,matlab常见问题集
  2. 为什么中国码农不断涌向杭州?
  3. (1)简单易学—— 人脸检测 Tensorflow_MTCNN模型训练详细步骤(纯干货,适用于windows和ubuntu系统)
  4. JAVA实现简单数据采集
  5. java通过比对MD5值判断是否是相同图片
  6. PAMI19 - 强大的级联RCNN架构《Cascade R-CNN: High Quality Object Detection and Instance Segmentation》
  7. DDR 6 内存已经投入研发
  8. 写了很久,这是一份最适合/贴切普通大众/科班/非科班的『学习路线』
  9. Unsupervised Hyperspectral Mixed Noise Removal Via Spatial-Spectral Constrained Deep Image Prior
  10. ResponseEntity