一个基于easyexcel大数据量数据导入导出异步处理组件,如果你觉得对你有帮助,请点击右上角的star,支持下
支持的功能列表:
引入starter
<dependency>
<groupId>com.asyncexcel</groupId>
<artifactId>async-excel-springboot-starter</artifactId>
<version>1.0.0</version>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</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='导入导出任务';
配置数据源(此处为多数据源,使用了spring 父子容器技术,所以不影响你原本的数据源)
#asyncexcel 数据源
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
#业务数据源
spring.datasource.url=jdbc:mysql://localhost:3306/async-excel-sample?serverTimezone=GMT%2B8&autoReconnect=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&&useCursorFetch=true&&rewriteBatchedStatements=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.password=root
spring.datasource.username=root
使用@EnableAsyncExcel注解启用配置
@SpringBootApplication
@EnableAsyncExcel
@MapperScan({"com.asyncexcel.sample.mapper"})
public class AsyncExcelSampleApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncExcelSampleApplication.class, args);
}
}
编写极简示例 示例项目 async-excel-sample 欢迎添加使用示例
@RestController
@RequestMapping("/user")
public class UserController {
@Resource
ExcelService excelService;
//导入最简示例
@PostMapping("/imports")
public Long imports(@RequestBody MultipartFile file) throws Exception{
DataImportParam dataImportParam = new DataImportParam()
.setStream(file.getInputStream())
.setModel(UserImportModel.class)
.setBatchSize(3)
.setFilename("用户导入");
Long taskId = excelService.doImport(UserImportHandler.class, dataImportParam);
return taskId;
}
//导出最简示例
@PostMapping("/exports")
public Long exports(){
DataExportParam dataExportParam=new DataExportParam()
.setExportFileName("用户导出")
.setLimit(5)
.setHeadClass(UserExportModel.class);
return excelService.doExport(UserExportHandler.class,dataExportParam);
}
}
导入导出model
@Data
public class UserExportModel extends ExportRow {
@ExcelProperty("用户编码")
private String userCode;
@ExcelProperty("用户姓名")
private String userName;
@ExcelProperty("手机号")
private String mobile;
@ExcelProperty("备注")
private String remarks;
}
@Data
public class UserImportModel extends ImportRow {
@ExcelProperty("用户编码")
private String userCode;
@ExcelProperty("用户姓名")
private String userName;
@ExcelProperty("手机号")
private String mobile;
@ExcelProperty("备注")
private String remarks;
}
编写导入导出处理类
@ExcelHandle
public class UserExportHandler implements ExportHandler<UserExportModel> {
@Autowired
IUserService userService;
@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;
}
}
@ExcelHandle
public class UserImportHandler implements ImportHandler<UserImportModel> {
@Autowired
IUserService userService;
@Override
public List<ErrorMsg> importData(List<UserImportModel> list, DataImportParam dataImportParam)
throws Exception {
List<ErrorMsg> errorList=new ArrayList<>();
List<User> saveUsers=new ArrayList<>();
for (UserImportModel userImportModel : list) {
if (userImportModel.getMobile().contains("00000000")){
ErrorMsg msg = new ErrorMsg(userImportModel.getRow(), "手机号包含太多0");
errorList.add(msg);
}else{
BeanCopier beanCopier = BeanCopier.create(UserImportModel.class, User.class, false);
User user = new User();
beanCopier.copy(userImportModel,user,null);
saveUsers.add(user);
}
}
userService.saveBatch(saveUsers);
return errorList;
}
}
编写前端页面
假如你已经对接好了第三方的存储比如oss、cos,七牛云存储等 你只需要在你的项目中实现IStorageService 接口即可 友情链接:存储可以引入!梦想大佬的sdk【spring-file-storage】 全平台支持
@Component
public class CosStorageService implements IStorageService {
@Autowired
private CosClient cosClient;
@Override
public String write(String name, Consumer<OutputStream> osConsumer) throws Exception {
return null;
}
//实现此方法即可
@Override
public String write(String name, InputStream data) throws Exception {
String url = cosClient.upload(name,data);
return url;
}
@Override
public InputStream read(String path) throws Exception {
return null;
}
@Override
public boolean delete(String path) throws Exception {
return false;
}
}
你可以直接使用spring的线程池,如果你需要传入你系统自定义的上下文你只需要做如下配置即可 前提是你已经定义好spring的线程池并填充好上下文装饰器ContextDecorator,线程装饰器的目的是为了将主线程的上下文传递给子线程
@Configuration
@EnableAsync()
public class ContextDecoratorThreadPoolConfiguration {
@Bean
ThreadPoolTaskExecutor threadPoolTaskExecutor(){
int core = Runtime.getRuntime().availableProcessors();
if (core<2){
core=2;
}
int corePool=core*2;
int maxPool=core*10;
ThreadPoolTaskExecutor threadPoolTaskExecutor=new ThreadPoolTaskExecutor();
//核心线程数
threadPoolTaskExecutor.setCorePoolSize(corePool);
//最大线程数
threadPoolTaskExecutor.setMaxPoolSize(maxPool);
//设置线程装饰器
threadPoolTaskExecutor.setTaskDecorator(new ContextDecorator());
//设置阻塞队列容量
threadPoolTaskExecutor.setQueueCapacity(1000);
//设置线程前缀
threadPoolTaskExecutor.setThreadNamePrefix("system-context-async-");
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
配置线程池,如果你未配置系统将声明一个默认的线程池DefaultThreadPoolConfiguration
@Configuration
@AutoConfigureBefore(ExcelAutoConfiguration.class)
@ConditionalOnClass(ExcelThreadPool.class)
public class AsyncExcelConfiguration {
@Bean
public ExcelThreadPool excelThreadPool(ThreadPoolTaskExecutor threadPoolTaskExecutor){
return new ExcelThreadPool(threadPoolTaskExecutor.getThreadPoolExecutor());
}
}
此时我们可以开启最大行数校验 dataImportParam.setMaxRows=1000; dataImportParam.setValidMaxRows=true; dataImportParam.setBatchSize=1000; 这样就变成单页处理。
dataExportParam.setDynamicHead=true;
此时我们需要传入一个动态表头
dataExportParam.setHeadList=list<List
dataExportParam.setWriteHandlers=List
表中内置三个权限隔离字段
tenant_code
'租户编码'create_user_code
'用户编码'business_code
'业务编码'
可以在插入数据时进行带入,如果你声明了自定义线程池,可以从系统上下文读取对应字段设置进去。
DataParam.setxxx 系统将会默认插入数据库,不用在进行特殊处理。后续查询时你想根据什么维度查询都可以,businessCode用于区分不同的业务模块比如用户模块,订单模块可以定一个枚举进行区分
权限可以隔离到用户,也可以隔离到租户,根据你系统的要求自行定义。使用ExcelService.listPage进行数据查询。当然你也可以自定义接口的方式根据你喜欢的方式进行查询建议使用最新版本
1.1.2版本
1.1.1版本