java csv 路径下载,Java不生成临时文件的导出下载csv文件的功能实现(3)

本文是“Java不生成临时文件的导出下载csv文件的功能实现(1)一文的扩展,所以模拟输入和下载文件的代码同上篇文章。

在本系列第二篇文章中,我们每次都会把一个csv文件所需要的数据全部查询出来,方便是方便了,可是数据库的压力就上去了,因为最终生成的一万条数据,可能需要从数据库中查询几十万条数据作为基础,所以,我们还需要对代码做进一步的优化。

在这里,我们使用线程池和future来进行处理。

线程池代码如下:

@Configuration

@EnableAsync

public class TaskExecutePool {

@Bean("exportExecutor")

public ThreadPoolExecutor getExportExecutor() {

// 创建队列

BlockingQueue blockingQueue = new LinkedBlockingDeque<>(120);

// 核心5 最大10 队列120 超时60s 拒绝策略报异常

ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5,10,60, TimeUnit.SECONDS,blockingQueue);

return threadPoolExecutor;

}

}

然后,当然是要定义每次查询的数量。

private static final Integer groupCapacity = 2000;

接着,按照2000进行分组,得出组数。

Integer exportTotal = dataList.size();

Integer groupNum = (exportTotal + groupCapacity - 1) / groupCapacity;//计算组数

log.info("总数" + exportTotal + ", 每组" + groupCapacity + ", 组数" + groupNum);

使用Future和线程池请求调用获取导出列表。

List futures = new ArrayList<>();

for (Integer i = 0; i < groupNum; i++) {

try {

// 多线程调用获取list

Future future = exportExecutor.submit(new CallableTask(dataList, i));

futures.add(future);

} catch (RejectedExecutionException e) {

// 系统繁忙说明队列已满

log.error("第" + i + "次请求队列已满", e);

} catch (Exception e) {

log.error("获取导出列表异常" + e);

}

}

每满5组,进行一次csv文件组装。

//待生成文件的数据列表

List exportList = new ArrayList();

//返回数据的组数,每满5组,进行一次csv文件组装

int exportCount = 0;

//生成文件编号

int exportIndex = 0;

while (true) {

//有未完成的future

if (futures != null && !futures.isEmpty()) {

for (int i = 0; i < futures.size(); i++) {

Future future = futures.get(i);

// 判断future是否执行完成

if (future.isDone()) {

//从future中获取单次2000条数据,存入exportList中

exportList.addAll((Collection) future.get());

futures.remove(i);

i--;

exportCount++;

//累计获取五次时,重置exportCount,生成对应csv文件,然后清空exportList

if (exportCount >= 5) {

exportCount = 0;

exportIndex++;

// 导出excel

byte[] bytes = this.generateCsvFile(exportList, fieldNames, fieldDescs);

bytesList.add(bytes);

exportList.clear();

}

}

}

} else {//future全部完成

//如果exportCount不为零,说明还有不足1w条的数据未生成csv文件

if (exportCount > 0) {

exportIndex++;

// 导出excel

byte[] bytes = this.generateCsvFile(exportList, fieldNames, fieldDescs);

bytesList.add(bytes);

exportList.clear();

}

break;

}

}

线程池中执行的方法如下。

private class CallableTask implements Callable {

private List dataList;

private Integer i;

public CallableTask(List dataList, Integer i) {

this.i = i;

this.dataList = dataList;

}

@Override

public List call() throws Exception {

StopWatch stopWatch = new StopWatch();

stopWatch.start("调用查询接口");

//睡眠一会

sleep(new Random().nextInt(2000));

List subList = null;

//最后一组的i和组容量的乘积大于列表总大小,会造成下面else中的subList越界

if (i * groupCapacity < dataList.size()) {

//最后不足2000的数据

if ((i + 1) * groupCapacity > dataList.size()) {

subList = dataList.subList(i * groupCapacity, dataList.size());

} else {

subList = dataList.subList(i * groupCapacity, (i + 1) * groupCapacity);

}

}

stopWatch.stop();

log.info(stopWatch.prettyPrint());

return subList;

}

}

具体有不清楚的,可以去我的github看看。地址:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值