SpringBoot+Mybatis-plus整合easyExcel批量导入Excel到数据库+导出Excel ...

打印 上一主题 下一主题

主题 556|帖子 556|积分 1668

一、前言

今天小编带大家一起整合一下easyExcel,之所以用这个,是因为easyExcel性能比较好,不会报OOM!
市面上常见的导入导出Excel分为三种:

  • hutool
  • easyExcel
  • poi
hutool和easyExcel都是对poi的封装,使用起来更加方便!
如果想使用poi和hutool导出的可以看一下小编的之前写的文章:
使用POI+hutool导入Excel
使用POI把查询到的数据表数据导出到Excel中,一个表一个sheet
导出的话看一下这篇,下面主要以导入来展开介绍!
EasyExcel导出Excel表格到浏览器,并通过Postman测试导出Excel
二、导入依赖

小编这里是3.0.X版本的,版本不同可能导致部分有出入,如果大家版本是3.1.X,可以去官方文档看看有不一样的!
官方文档
  1. <dependency>
  2.     <groupId>com.alibaba</groupId>
  3.     <artifactId>easyexcel</artifactId>
  4.     <version>3.0.5</version>
  5. </dependency>
复制代码
三、实体类

这里可以自带的转换器:

  • @DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
  • LocalDateTimeStringConverter
或者自定义转化器:
实现:implements Converter
具体文档:官方文档
@ExcelProperty参数注意:
这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
  1. /**
  2. * @author wangzhenjun
  3. * @date 2022/12/2 15:52
  4. */
  5. @Data
  6. public class Test {
  7.     @TableId
  8.     private Integer id;
  9.     @ExcelProperty(index = 0)
  10.     private String name;
  11.     @ExcelProperty(index = 1)
  12.     private Integer age;
  13.     @ExcelProperty(index = 2,converter = LocalDateTimeStringConverter.class)
  14.     private LocalDateTime time;
  15. }
复制代码
四、编写监听器

注意点:
这个监听器一定不要是单例的,被spring管理默认为单例,如果要使用@Component,一定要加上:
@Scope("prototype"),这样在创建完后spring不会进行管理,每次都会是新bean!
不加@Component在导入时要进行new ImportDataListener !
小编这里不想new了直接这样写!!如果不想这样,可以使用构造器set进行使用!
BATCH_COUNT :数据阈值,超过了就会清理list,在之前可以进行保存到数据库中,方便内存回收,防治OOM!
这里保存到数据库中一般使用批量保存,不要解析到一行就去保存数据库中,这样数据量大会给数据库增加IO,导致挂掉!这里小编使用ServiceImpl的saveBatch()方法,也可以自己写一下,像小编这样写,会出现循环依赖,加上@Lazy就行!
  1. /**
  2. * @author wangzhenjun
  3. * @date 2022/12/2 15:38
  4. */
  5. @Slf4j
  6. @Component
  7. // 每次bean都是新的,不要单例
  8. @Scope("prototype")
  9. public class ImportDataListener implements ReadListener<Test> {
  10.     @Autowired
  11.     @Lazy
  12.     private TestService testService;
  13.    
  14.     /**
  15.      * 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
  16.      */
  17.     private static final int BATCH_COUNT = 100;
  18.     /**
  19.      * 缓存的数据
  20.      */
  21.     private List<Test> importExcelDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
  22.     /**
  23.      * 这个每一条数据解析都会来调用
  24.      *
  25.      * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
  26.      * @param context
  27.      */
  28.     @Override
  29.     public void invoke(Test data, AnalysisContext context) {
  30.         log.info("解析到一条数据:{}", JSON.toJSONString(data));
  31.         importExcelDataList.add(data);
  32.         // 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
  33.         if (importExcelDataList.size() >= BATCH_COUNT) {
  34.             saveData();
  35.             // 存储完成清理 list
  36.             importExcelDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
  37.         }
  38.     }
  39.     /**
  40.      * 所有数据解析完成了 都会来调用
  41.      *
  42.      * @param context
  43.      */
  44.     @Override
  45.     public void doAfterAllAnalysed(AnalysisContext context) {
  46.         // 这里也要保存数据,确保最后遗留的数据也存储到数据库
  47.         saveData();
  48.         log.info("所有数据解析完成!");
  49.     }
  50.     /**
  51.      * 加上存储数据库
  52.      */
  53.     private void saveData() {
  54.         log.info("{}条数据,开始存储数据库!", importExcelDataList.size());
  55.         testService.saveBatch(importExcelDataList);
  56.         log.info("存储数据库成功!");
  57.     }
  58. }
复制代码
五、Controller
  1. /**
  2. * @author wangzhenjun
  3. * @date 2022/10/26 16:51
  4. */
  5. @Slf4j
  6. @RestController
  7. @RequestMapping("/test")
  8. public class TestController {
  9.     @Autowired
  10.     private TestService testService;
  11.     @PostMapping("/import")
  12.     public Result importExcel(@RequestBody MultipartFile multipartFile){
  13.         testService.importExcel(multipartFile);
  14.         return Result.success("ok");
  15.     }
  16. }
复制代码
六、Service
  1. /**
  2. * @author wangzhenjun
  3. * @date 2022/10/26 16:55
  4. */
  5. public interface TestService extends IService<Test> {
  6.     void importExcel(MultipartFile multipartFile);
  7. }
复制代码
七、ServiceImpl
  1. /**
  2. * @author wangzhenjun
  3. * @date 2022/10/26 16:56
  4. */
  5. @Service
  6. public class TestServiceImpl extends ServiceImpl<TestDbMapper, Test> implements TestService{
  7.     @Autowired
  8.     private ImportDataListener importDataListener;
  9.     @SneakyThrows
  10.     @Override
  11.     public void importExcel(MultipartFile multipartFile) {
  12.         InputStream inputStream = multipartFile.getInputStream();
  13.         // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
  14.         EasyExcel.read(inputStream, Test.class, importDataListener).sheet().doRead();
  15.     }
  16. }
复制代码
八、Mapper
  1. /**
  2. * @author wangzhenjun
  3. * @date 2022/10/26 17:07
  4. */
  5. public interface TestDbMapper extends BaseMapper<Test> {
  6. }
复制代码
九、测试

准备Excel数据:

postman上传:

控制台打印:

数据库查看:

完美搞定!!
十、总结

这样就完成了easyExcel批量导入Excel到数据库,还是有很多要注意的点:

  • 自定义转换器
  • 监听器不要单例
  • 保存数据库采用批量
  • 版本差距
如果对你有帮助,还请不要吝啬您的发财小手,你的一键三连是我写作的动力,谢谢大家哈!!
可以看下小编的微信公众号,文章首发看,欢迎关注,一起交流哈!!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

莫张周刘王

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表