赞
踩
async-excel是easy-excel的辅助组件,抽取通用异步逻辑,通过引入一个starter配置个数据源就可以让导入导出变成异步,无需额外的任何代码,不改变easy-excel的任何特性。
为了支持业务上日益变态的需求,对async-excel进行了一轮重构
当前版本1.1.0。修改了部分写法,兼容1.0.0版本。一些方法被标注为过时。将会在以后的某个版本中移除。
1.1.0版本重构主要内容如下
如果项目对你有帮助可以给个star支持下
async-excel基于easy-excel抽取了异步逻辑,并且使用了sping的父子容器,适配了springboot-starter,使用该组件非常简单
引入starter
<dependency>
<groupId>com.asyncexcel</groupId>
<artifactId>async-excel-springboot-starter</artifactId>
<version>1.1.0</version>
</dependency>
初始化数据库
drop table if exists excel_task; CREATE TABLE `excel_task` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id', `type` tinyint(2) NOT NULL COMMENT '类型:1-导入,2-导出', `status` tinyint(2) NOT NULL DEFAULT 0 COMMENT '状态:0-初始,1-进行中,2-完成,3-失败', `estimate_count` bigint(20) NOT NULL DEFAULT 0 COMMENT '预估总记录数', `total_count` bigint(20) NOT NULL DEFAULT 0 COMMENT '实际总记录数', `success_count` bigint(20) NOT NULL DEFAULT 0 COMMENT '成功记录数', `failed_count` bigint(20) NOT NULL DEFAULT 0 COMMENT '失败记录数', `file_name` varchar(200) DEFAULT NULL COMMENT '文件名', `file_url` varchar(500) DEFAULT NULL COMMENT '文件路径', `failed_file_url` varchar(500) DEFAULT NULL COMMENT '失败文件路径', `failed_message` varchar(255) DEFAULT NULL COMMENT '失败消息', `start_time` datetime DEFAULT NULL COMMENT '开始时间', `end_time` datetime DEFAULT NULL COMMENT '结束时间', `tenant_code` varchar(50) default NULL COMMENT '租户编码', `create_user_code` varchar(50) default NULL COMMENT '用户编码', `business_code` varchar(50) default NULL COMMENT '业务编码', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='导入导出任务';
配置数据源,父子容器多数据源配置,不影响你原有数据源
#aysncexcel 数据源
spring.excel.datasource.url=jdbc:mysql://localhost:3306/async-excel?serverTimezone=GMT%2B8&autoReconnect=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&&useCursorFetch=true&&rewriteBatchedStatements=true
spring.excel.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.excel.datasource.password=root
spring.excel.datasource.username=root
多sheet导出
controller 注入excelService
@AutoWire
ExcelService excelService
//导出最简示例,支持多个sheet导出
@PostMapping("/exports")
public Long exports(){
DataExportParam dataExportParam=new DataExportParam()
.setExportFileName("用户导出")
.setLimit(5);
return excelService.doExport(dataExportParam,UserExportHandler.class, UserExportHandlerA.class);
}
第一个sheet
@ExcelHandle public class UserExportHandler implements ExportHandler<UserExportModel> { @Autowired IUserService userService; @Override public void init(ExcelContext ctx, DataParam param) { ExportContext context = (ExportContext) ctx; //此处的sheetNo会被覆盖,为了兼容一个文件多sheet导出 WriteSheet sheet = EasyExcel.writerSheet(0, "第一个sheet").head(UserExportModel.class).build(); context.setWriteSheet(sheet); } @Override public ExportPage<UserExportModel> exportData(int startPage, int limit, DataExportParam dataExportParam) { IPage<User> iPage = new Page<>(startPage, limit); IPage page = userService.page(iPage); List<UserExportModel> list = ExportListUtil.transform(page.getRecords(), UserExportModel.class); ExportPage<UserExportModel> result = new ExportPage<>(); result.setTotal(page.getTotal()); result.setCurrent(page.getCurrent()); result.setSize(page.getSize()); result.setRecords(list); return result; } @Override public void beforePerPage(ExportContext ctx, DataExportParam param) { //分页执行,每页开始执行前 } @Override public void afterPerPage(List<UserExportModel> list, ExportContext ctx, DataExportParam param) { //分页执行,每页执行完成后 } @Override public void callBack(ExcelContext ctx, DataParam param) { //全部执行完成后回调 } }
第二个sheet
@ExcelHandle public class UserExportHandlerA implements ExportHandler<UserExportModel> { @Autowired IUserService userService; @Override public void init(ExcelContext ctx, DataParam param) { ExportContext context = (ExportContext) ctx; //此处的sheetNo会被覆盖,为了兼容一个文件多sheet导出 WriteSheet sheet = EasyExcel.writerSheet(0, "第二个sheet").head(UserExportModel.class).build(); context.setWriteSheet(sheet); } @Override public ExportPage<UserExportModel> exportData(int startPage, int limit, DataExportParam dataExportParam) { IPage<User> iPage = new Page<>(startPage, limit); IPage page = userService.page(iPage); List<UserExportModel> list = ExportListUtil.transform(page.getRecords(), UserExportModel.class); ExportPage<UserExportModel> result = new ExportPage<>(); result.setTotal(page.getTotal()); result.setCurrent(page.getCurrent()); result.setSize(page.getSize()); result.setRecords(list); return result; } @Override public void beforePerPage(ExportContext ctx, DataExportParam param) { //分页执行,每页开始执行前 } @Override public void afterPerPage(List<UserExportModel> list, ExportContext ctx, DataExportParam param) { //分页执行,每页执行完成后 } @Override public void callBack(ExcelContext ctx, DataParam param) { //全部执行完成后回调 } }
动态表头导入
表头不确定,需要业务上进行判断怎么办?
只要将你的导入实体继承至ImportRowMap即可
@Data
public class ImportRowMap extends ImportRow {
@ExcelIgnore
private Map<Integer, String> headMap;
@ExcelIgnore
private Map<Integer, Cell> dataMap;
}
这个类带了两个map 一个是表头的map,一个是数据的map
根据map自己去做对应的数据处理
示例代码
@ExcelHandle public class DynamicHeadImportsHandler implements ImportHandler<DynamicHeadImportsModel> { @Autowired IOplogService service; @Override public List<ErrorMsg> importData(List<DynamicHeadImportsModel> list, DataImportParam param) throws Exception { List<ErrorMsg> errorMsgList = new ArrayList<>(); //List<Oplog> oplogs = ExportListUtil.transform(list, Oplog.class); for (DynamicHeadImportsModel dynamicHeadImportsModel : list) { //处理固定列 Oplog oplog = new Oplog(); oplog.setOpUser(dynamicHeadImportsModel.getOpUser()); oplog.setOpRemark(dynamicHeadImportsModel.getOpRemark()); oplog.setOpSummary(dynamicHeadImportsModel.getOpSummary()); oplog.setOpContent(dynamicHeadImportsModel.getOpContent()); //模拟错误 if (dynamicHeadImportsModel.getRow()%2==0){ errorMsgList.add(new ErrorMsg(dynamicHeadImportsModel.getRow(),"2的倍数行出错")); } //处理动态列 Map<Integer, String> headMap = dynamicHeadImportsModel.getHeadMap(); Map<Integer, Cell> dataMap = dynamicHeadImportsModel.getDataMap(); Map<String, Cell> stringCellMap = mergeHeadAndData(headMap, dataMap); System.out.println(stringCellMap.keySet()); } System.out.println("分页数据处理完成"); return errorMsgList; } private Map<String,Cell> mergeHeadAndData(Map<Integer, String> headMap,Map<Integer, Cell> dataMap){ Set<Integer> headKeySet = headMap.keySet(); Map<String,Cell> mergeMap=new LinkedHashMap<>(); Iterator<Integer> iterator = headKeySet.iterator(); for (int i = 0; i <headKeySet.size() ; i++) { Integer key= iterator.next(); mergeMap.put(headMap.get(key),dataMap.get(key)); } return mergeMap; } //新增导入导出完成后的回调支持,如果多sheet导出时,也是整个生命周期完成后按顺序执行 @Override public void callBack(ExcelContext ctx, DataParam param) { //整个生命周期完成后执行一次该方法 System.out.println("执行完成"); } }
导入入参说明
public class DataImportParam extends DataParam { /** * 输入流 */ private InputStream stream; /** * 文件名称 */ private String filename; /** * 导入对应的实体类 */ private Class<?> model; /** * 分批次大小,如果你导入1w条数据,每次1000会分10次读到内存中 */ private int batchSize = 1000; /** * 是否限制导入行数,默认false,如果限制行数将会触发行数限制异常,例如限制1000行,你的文件如果超过1000行将会抛异常 */ private boolean validMaxRows = false; /** * 行数限制validMaxRows=true时起作用 */ private int maxRows = 1000; /** * 是否进行表头校验,顺序单元格内容都应该与实体类保持一致。 */ private boolean validHead = true; }
导出入参说明
public class DataExportParam<T> extends DataParam { /** * 分页大小 */ private int limit=1000; /** * 导出文件名称 */ private String exportFileName; /** * 写入excel的sheetName */ @Deprecated private String sheetName; /** * 是否动态表头,默认false。 */ @Deprecated private boolean dynamicHead; /** * 当dynamicHead=true时需要传一个动态表头进来 */ @Deprecated private List<List<String>> headList; /** * 表头对应的实体类 */ @Deprecated private Class<?> headClass; /** * 自定义写处理器为了,自定义样式,表格合并之类的easyExcel原生扩展 */ @Deprecated private List<WriteHandler> writeHandlers; /** * 自定义类型转换器easyExcel原生扩展 */ @Deprecated private List<Converter<?>> converters; }
@Data
public class DataParam {
//业务额外参数
private Map<String, Object> parameters;
//租户参数
private String tenantCode;
//用户参数
private String createUserCode;
//业务参数用于区分文件展示的不同模块
private String businessCode;
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。