依赖
<!-- easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.2.1</version>
</dependency>
线程池
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
private final Integer corePoolSize =Math.max(2, Math.min(CPU_COUNT - 1, 4));
private final Integer maxPoolSize = CPU_COUNT * 2 + 1;
private static final Integer KEEP_ALIVE_TIME = 30;
@Bean(name = "asyncExecutor")
@Primary
public ThreadPoolTaskExecutor asyncServiceExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
int queueCapacity = 1000;
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(KEEP_ALIVE_TIME);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix("asyncExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
return executor;
}
实体类
package com.pay.entity;
import java.util.Date;
import java.io.Serializable;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
/**
* (User)实体类
*
* @author makejava
* @since 2023-06-23 16:28:16
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class User implements Serializable {
private static final long serialVersionUID = -60097174267113685L;
@ExcelProperty("ID")
private Long id;
/**
* 昵称
*/
@ExcelProperty("昵称")
private String nickname;
/**
* 真实用户名(身份证上的用户名)
*/
@ExcelProperty("真实用户名")
private String username;
/**
* 登录账号
*/
@ExcelProperty("登录账号")
private String account;
/**
* 密码
*/
@ExcelProperty("密码")
private String password;
/**
* 手机号
*/
@ExcelProperty("手机号")
private String phone;
/**
* 性别(0保密,1女,2男)
*/
@ExcelProperty("性别")
private Integer sex;
/**
* 头像
*/
@ExcelProperty("头像")
private String avatar;
/**
* 微信号
*/
@ExcelProperty("微信号")
private String wechat;
/**
* 用户是否认证(1已认证,0未认证)
*/
@ExcelProperty("是否认证")
private Integer isAuth;
/**
* 用户状态(1,可用,0禁用)
*/
@ExcelProperty("用户状态")
private Integer status;
/**
* 用户类型(0超级管理员,1管理员,2系统用户)
*/
@ExcelProperty("用户类型")
private Integer userType;
/**
* 用户积分
*/
@ExcelProperty("用户积分")
private Integer integral;
/**
* vip等级
*/
@ExcelProperty("vip等级")
private Integer vip;
/**
* 排序 数字越小越靠前
*/
@ExcelProperty("排序")
private Integer sort;
/**
* 创建时间
*/
@ExcelProperty("创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@DateTimeFormat(value="yyyy-MM-dd HH:mm:ss")
private Date createTime;
/**
* 更新时间
*/
@ExcelProperty("更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
@DateTimeFormat(value="yyyy-MM-dd HH:mm:ss")
private Date updateTime;
@Override
public String toString() {
return JSON.toJSONString(this);
}
}
@Override
public void exportExcel(String filename, HttpServletResponse response) throws BizException {
try {
long startTime = System.currentTimeMillis();
String name = StringUtils.isEmpty(filename) ? "用户信息" : filename;
String fileName = URLEncoder.encode(name + ExcelTypeEnum.XLSX.getValue(), StandardCharsets.UTF_8);
response.setHeader("content-disposition", "attachment;filename=" + fileName);
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
Long count = userMapper.selectCount(queryWrapper);
Integer pageSize = 1000; // 每个sheet文件显示1000 条数据
OutputStream outputStream = response.getOutputStream();
ExcelWriter excelWriter = EasyExcel.write(outputStream).build();
List<CompletableFuture> completableFutures = new ArrayList<>();
long countSheet = (count / pageSize) + 1;
for (int i = 0; i < countSheet; i++) {
Integer start = i * pageSize;
List<User> users = userMapper.selectLimit(start, pageSize);
int finalI = i;
completableFutures.add(CompletableFuture.runAsync(() -> {
if (!CollectionUtils.isEmpty(users)) {
WriteSheet writeSheet = EasyExcel.writerSheet(start, "sheet" + (finalI + 1)).head(User.class)
.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).build();
synchronized (excelWriter) {
excelWriter.write(users, writeSheet);
}
}
}, threadPoolTaskExecutor));
}
completableFutures.forEach(CompletableFuture::join);
excelWriter.finish();
excelWriter.close();
outputStream.flush();
outputStream.close();
log.info("文件导出耗时:{}", (System.currentTimeMillis() - startTime) + "毫秒");
} catch (Exception e) {
e.printStackTrace();
}
}
异常:
CompletableFuture 结合自定义线程池文件导出或下载出现 Cannot call sendError() after the response has been committed异常
报错原因:我的类使用@RestController注解,所以每个方法的返回值是通过response响应出去,所以这里就出现了第二次response的问题。