EasyExcel批量读取Excel文件数据导入到MySQL表中

1、EasyExcel简介

官网:EasyExcel官方文档 - 基于Java的Excel处理工具 | Easy Excel 官网

2、代码实战

首先引入jar包

html 复制代码
   <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>easyexcel</artifactId>
      <version>3.3.2</version> 
   </dependency>

2.1 读取Excel

2.1.1 使用PageReadListener

这种方式代码简洁,通俗易懂,直接看示例:

java 复制代码
 public void readExcelFile2(MultipartFile file) {
    AtomicInteger count = new AtomicInteger(0);
    try {
          int batch = 10;
          EasyExcel.read(file.getInputStream(), SharePathApproveModule.class, new PageReadListener<SharePathApproveModule>(list -> {
             System.out.println("已完成" + list.size() + "条数据读取...");
             for (SharePathApproveModule module : list) {
                  System.out.println("读取到" + count.incrementAndGet() + "条数据=>" + JSONObject.toJSONString(module));

              }
              //批量写入
              //sharePathApproveMapper.insertBatch(list);
          }, batch)).sheet(0).doRead();
          //sheetNo参数不传默认0,读取第一个sheet;填0也是读取第1个sheet;填1即读取第2个sheet
      } catch (Exception e) {
          log.error("读取Excel数据异常,", e);
      }
  }

这种方式是直接使用了PageReadListener监听器,有兴趣的同学可以自行解读PageReadListener源码,这里我只把源码粘贴出来,本文主要讲实战,就不过多说PageReadListener。

java 复制代码
import java.util.List;
import java.util.function.Consumer;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.util.ListUtils;

import org.apache.commons.collections4.CollectionUtils;

/**
 * page read listener
 *
 * @author Jiaju Zhuang
 */
public class PageReadListener<T> implements ReadListener<T> {
    /**
     * Default single handle the amount of data
     */
    public static int BATCH_COUNT = 100;
    /**
     * Temporary storage of data
     */
    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    /**
     * consumer
     */
    private final Consumer<List<T>> consumer;

    /**
     * Single handle the amount of data
     */
    private final int batchCount;

    public PageReadListener(Consumer<List<T>> consumer) {
        this(consumer, BATCH_COUNT);
    }

    public PageReadListener(Consumer<List<T>> consumer, int batchCount) {
        this.consumer = consumer;
        this.batchCount = batchCount;
    }

    @Override
    public void invoke(T data, AnalysisContext context) {
        cachedDataList.add(data);
        if (cachedDataList.size() >= batchCount) {
            consumer.accept(cachedDataList);
            cachedDataList = ListUtils.newArrayListWithExpectedSize(batchCount);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (CollectionUtils.isNotEmpty(cachedDataList)) {
            consumer.accept(cachedDataList);
        }
    }

}

简单的说一下PageReadListener监听器的两个方法:invoke和doAfterAllAnalysed;他们都是实现ReadListener接口里面定义的方法。

invoke:表示每解析完一条数据就会调用该初始方法,因此很多条件筛选或业务我们可以放在里面实现。

doAfterAllAnalysed:表示每解析完一个sheet页后调用该方法。

从源码中知道,invoke()中当数组的长度大于等于设置的长度时,则执Consumer,执行完成后在进行初始化集合;

doAfterAllAnalysed()中在获取完数据后,判断当前集合时候还有数据,有的话则执行Consumer。

2.1.2 自定义监听器

我们可以通过继承AnalysisEventListener类来自定义监听器,重新里面的invoke和doAfterAllAnalysed方法。

首先,新建一个Module

java 复制代码
/**
 * @description
 * @date 2024-07-10 18:02
 **/
@Data
public class ShareModule {

    @ExcelProperty(value = "share路径", index = 0)
    @ColumnWidth(value = 10)
    private String sharePath;

    @ExcelProperty(value = "权限", index = 1)
    @ColumnWidth(value = 10)
    private String access;

    @ExcelProperty(value = "组名", index = 2)
    @ColumnWidth(value = 10)
    private String groupCn;

    @ExcelProperty(value = "历史申请人", index = 3)
    @ColumnWidth(value = 20)
    private String applicants;
}

接着,定义Mapper和Mapper.xml,这里我们只写一个批量插入的方法,使用

insert into table_name(column1,column2,column3) values(x,x,x),(x,x,x),.....

这种方式减少了数据库的连接,提高插入效率,而mybatis这样执行批处理需要在数据库url配置上添加rewriteBatchedStatements=true,进行批处理开启。

java 复制代码
public interface ShareMapper {

    int insertBatch(@Param("shareModules")List<ShareModule> shareModules);

    int clearTableData();
}
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.demo.mapper.ShareMapper">

    <insert id="insertBatch">
        INSERT INTO share_path_approve (share_path, access, group_cn, applicants) VALUES
        <foreach collection="shareModules" index="index" item="po" separator=",">
            (#{po.sharePath}, #{po.access}, #{po.groupCn}, #{po.applicants})
        </foreach>
    </insert>

    <update id="clearTableData">
        truncate table share_path_approve
    </update>

</mapper>

然后,就是自定义监听器,配将这个监听器交给Spring容器

java 复制代码
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.example.wangpeng.mapper.SharePathApproveMapper;
import com.example.wangpeng.po.module.SharePathApproveModule;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

/**
 * @description share auto
 * @date 2024-07-10 10:30
 */
@Slf4j
public class ShareListener extends AnalysisEventListener<ShareModule> {

    private List<ShareModule> cacheData = new ArrayList<>();
    private static final int BATCH_COUNT = 8;

    private final ShareMapper shareMapper;

    public SharePathApproveListener(ShareMapper shareMapper) {
        this.shareMapper= shareMapper;
    }


    @Override
    public void invoke(ShareModule shareModule, AnalysisContext analysisContext) {
        cacheData.add(shareModule);
        if (cacheData.size() >= BATCH_COUNT) {
            log.info("保存数据--share auto-----{}条", cacheData.size());
            saveData();
            // 可以清理缓存数据
            cacheData = new ArrayList<>();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext analysisContext) {
        // 处理最后未达到8条数据的插入
        if (!cacheData.isEmpty()) {
            log.info("保存数据--share auto-----{}条", cacheData.size());
            saveData();
        }
    }

    private void saveData() {
        // 这里可以使用MyBatis的批量插入方法
        shareMapper.insertBatch(cacheData);
    }
}
java 复制代码
import com.example.wangpeng.excel.SharePathApproveListener;
import com.example.wangpeng.mapper.SharePathApproveMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @description
 * @date 2024-07-10 18:17
 */
@Configuration
public class EasyExcelConfig {

    @Bean
    public ShareListener shareListener(ShareMapper shareMapper) {
        return new shareListener(shareMapper);
    }
}

最后一步,就是编写Service和实现类、控制层接口代码

java 复制代码
public interface ExcelService {

    ResponseResult<?> importExcel(MultipartFile file, Integer type);

}
java 复制代码
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.excel.ShareListener;
import com.example.demo.mapper.ShareMapper;
import com.example.demo.po.module.ShareModule;
import com.example.demo.response.ResponseResult;
import com.example.demo.service.ExcelService;
import lombok.extern.log4j.Log4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;


/**
 * @description
 * @date 2024-06-03 15:57
 */
@Log4j
@Service
public class ExcelServiceImpl implements ExcelService {

    @Autowired
    private SharePathApproveMapper sharePathApproveMapper;


    @Override
    public ResponseResult<?> importExcel(MultipartFile file, Integer type) {

        try (InputStream inputStream = file.getInputStream()) {
            if (0 == type) {
                //全量覆盖
                sharePathApproveMapper.clearTableData();
            }  //增量插入

            EasyExcel.read(inputStream, ShareModule.class, new ShareListener(shareMapper))
                    .sheet()
                    .doRead();

            return ResponseResult.success();
        } catch (Exception e) {
            log.info("ShareExcel并解析 异常!", e);
            return ResponseResult.fail(e.getMessage());
        }
    }
}
java 复制代码
@RestController
@RequestMapping(value = "/excel")
public class ExcelController {

    @Autowired
    private ExcelService excelService;

    @PostMapping(value = "/import")
    public ResponseResult<String> excelFile2(@RequestBody MultipartFile file, Integer type) {
        excelService.importExcel(file, type);
        return ResponseResult.success();
    }
}

运行如下:

相关推荐
开开心心就好11 分钟前
本地文件搜索工具,双击Ctrl就能呼出搜索
java·服务器·前端·支持向量机·ffmpeg·音视频·模拟退火算法
独隅15 分钟前
Claude 高效使用指南深度评测
java·开发语言·claude·claude code
ByteCoder.23 分钟前
班前十分钟的清单,按体检引导单来写
java·服务器·前端·助播虾
海的透彻25 分钟前
如何让docker容器启动时用自定义的用户
java·docker·dubbo
疯狂学习GIS29 分钟前
将谷歌地球引擎账号升级为Contributor与Partner层级的方法
java·数据库·人工智能
GG.WinGel41 分钟前
质数数目(蓝桥杯练习题)
java·数据结构·算法·青少年编程·蓝桥杯
泡泡糖的中文规格书1 小时前
HDLbits 2.2 学习笔记 · 多路复用器
java·开发语言
John_Hui1 小时前
第 3 篇:配置 JDK 17 环境
java·开发语言·ubuntu
秋天的怀念_David1 小时前
算法一千零一夜 · 第十七夜 长街点灯
java·程序人生·算法
不吃鱼的羊1 小时前
如何应对恐惧
java