一:controller请求
/**
* 多线程文件导出
*
* @param response
* @throws Exception
*/
@ApiOperation("文件导出")
@ApiImplicitParams({
@ApiImplicitParam(name = "babyInsuranceParam", value = "保险领取表实体类", dataType = "BabyInsuranceParam", paramType = "query", example = "xxx"),
})
@ResponseBody
@ApiResource(name = "文件导出", path = "/exportInsuranceClaimExcel",requiredLogin = false,requiredPermission = false)
public void exportInsuranceClaimExcel(HttpServletResponse response, BabyInsuranceParam babyInsuranceParam){
try {
//1:获取数据
List<Future<List<InsuranceClaimExcel>>> futures = InsuranceClaimQueryExecutor.executeThreadPool(babyInsuranceMapper, babyInsuranceParam);
List<InsuranceClaimExcel> list = new ArrayList<>();
for (int i = 0; i < futures.size(); i++) {
List<InsuranceClaimExcel> excelList = futures.get(i).get();
list.addAll(excelList);
}
//2:下载
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 和easyexcel没有关系
String fileName = URLEncoder.encode("Excel-保单领取", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
//3:创建EXCEL
ExcelWriter excelWriter = EasyExcelFactory.write(response.getOutputStream()).build();
//4:构建多sheet,分割list
int listSize=list.size();
int toIndex=200000;
//用map存起来新的分组后数据
Map<Integer, List<InsuranceClaimExcel>> map = new HashMap<>();
int keyToken = 0;
for(int i = 0;i<list.size();i+=200000){
//作用为toIndex最后没有200000条数据则剩余几条newList中就装几条
if(i+200000>listSize){
toIndex=listSize-i;
}
List<InsuranceClaimExcel> newList = list.subList(i,i+toIndex);
map.put(keyToken, newList);
keyToken++;
}
map.forEach((k,v)->{
WriteSheet writeSheet = EasyExcelFactory.writerSheet(k, "保单领取-"+k).head(InsuranceClaimExcel.class).build();
writeSheet.setAutomaticMergeHead(Boolean.TRUE);
writeSheet.setColumnWidthMap(new HashMap<>(0,30*256));
writeSheet.setTableStyle(TableStyleUtils.createTableStyle());
excelWriter.write(v, writeSheet);
});
excelWriter.finish();
} catch (Exception var1) {
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, String> map = new HashMap();
map.put("status", "failure");
map.put("message", "下载文件失败" + var1.getMessage());
try {
response.getWriter().println(JSON.toJSONString(map));
} catch (IOException e) {
e.printStackTrace();
}
}
}
二:多线程去查询数据
package com.wing.cloud.base.modular.thread;
import com.wing.cloud.base.modular.mapper.BabyInsuranceMapper;
import com.wing.cloud.base.modular.model.params.BabyInsuranceParam;
import com.wing.cloud.base.modular.model.params.InsuranceClaimExcel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* <p>
* 使用线程池导出保险领取文件
* </p>
*
* @author: heluwei
* @Date: 2020/5/18 14:52
*/
public class InsuranceClaimQueryExecutor {
//核心线程数为 5
private static final int CORE_POOL_SIZE = 5;
//最大线程数 10
private static final int MAX_POOL_SIZE = 10;
private static final int QUEUE_CAPACITY = 100;
/**
* 当线程数大于核心线程数时,多余的空闲线程存活的最长时间
*/
private static final Long KEEP_ALIVE_TIME = 1L;
public static List<Future<List<InsuranceClaimExcel>>> executeThreadPool(BabyInsuranceMapper babyInsuranceMapper,
BabyInsuranceParam babyInsuranceParam){
//通过ThreadPoolExecutor构造函数自定义参数创建
ThreadPoolExecutor executor = new ThreadPoolExecutor(
CORE_POOL_SIZE,
MAX_POOL_SIZE,
//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
KEEP_ALIVE_TIME,
//时间单位
TimeUnit.SECONDS,
//任务队列,用来储存等待执行任务的队列
new ArrayBlockingQueue<>(QUEUE_CAPACITY),
//饱和策略,简单点说就是后面排队的线程就在那儿等着。 被拒绝的任务在主线程中运行,所以主线程就被阻塞了,
// 别的任务只能在被拒绝的任务执行完之后才会继续被提交到线程池执行
new ThreadPoolExecutor.CallerRunsPolicy());
List<Future<List<InsuranceClaimExcel>>> futureList = new ArrayList<>();
//1:查询一共有多少值
int countExportExcel = babyInsuranceMapper.countExportExcel(babyInsuranceParam);
long round = Math.round((countExportExcel / 5000) + 0.5);
for (int i = 0; i < round; i++) {
int startLen = i * 5000;
Future<List<InsuranceClaimExcel>> submit = executor.submit(new InsuranceClaimQueryThread(babyInsuranceMapper, babyInsuranceParam, startLen));
futureList.add(submit);
}
//终止线程池
executor.shutdown();
//若关闭后所有任务都已完成,则返回true。注意除非首先调用shutdown或shutdownNow,否则isTerminated永不为true。
while (!executor.isTerminated()) {
//System.out.println("线程池还没有完全关闭!!!");
}
return futureList;
}
}
call方法:
package com.wing.cloud.base.modular.thread;
import com.wing.cloud.base.modular.mapper.BabyInsuranceMapper;
import com.wing.cloud.base.modular.model.params.BabyInsuranceParam;
import com.wing.cloud.base.modular.model.params.InsuranceClaimExcel;
import java.util.List;
import java.util.concurrent.Callable;
/**
* <p>
*
* </p>
*
* @author: heluwei
* @Date: 2020/5/18 15:03
*/
public class InsuranceClaimQueryThread implements Callable<List<InsuranceClaimExcel>> {
//数据层访问
private BabyInsuranceMapper babyInsuranceMapper;
//查询参数
private BabyInsuranceParam babyInsuranceParam;
/**
*开始数
*/
private int beginNum;
public InsuranceClaimQueryThread(BabyInsuranceMapper babyInsuranceMapper, BabyInsuranceParam babyInsuranceParam, int beginNum) {
this.babyInsuranceMapper = babyInsuranceMapper;
this.babyInsuranceParam = babyInsuranceParam;
this.beginNum = beginNum;
}
@Override
public List<InsuranceClaimExcel> call() throws Exception {
//返回数据给Future
List<InsuranceClaimExcel> list = babyInsuranceMapper.threadExportExcelList(babyInsuranceParam,beginNum,5000);
return list;
}
}