使用方法

导入依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>最新版本</version>
</dependency>

出现 java.lang.NoSuchMethodError: 'void org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream.putArchiveEntry(org.apache.commons.compress.archivers.zip.ZipArchiveEntry)'

EasyExcel 依赖于比较新的 commons-io 版本,额外引入这个包或者 在 parentdependencyManagement 里面加入

    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <!-- 这个版本可以继续往上升 ,但是不要低于这个 -->
      <version>2.15.0</version>
    </dependency>

监听器

/**
 * @author fjzheng
 * @version 1.0
 * @date 2024/4/12 16:22
 */
@Slf4j
public class UserExcelListener extends AnalysisEventListener<User> {

    /**
     * 每隔100条处理下,然后清理list ,方便内存回收
     */
    private static final int BATCH_COUNT = 100;


    /**
     * 缓存的数据
     */
    private List<User> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);


    /**
     *
     * @param exception
     * @param context
     * @throws Exception
     */
    @Override
    public void onException(Exception exception, AnalysisContext context) throws Exception {
        log.error("======>>>解析异常:", exception);
        throw exception;
    }

    /**
     * 当读取到一行数据时,会调用这个方法,并将读取到的数据以及上下文信息作为参数传入
     * 可以在这个方法中对读取到的数据进行处理和操作,处理数据时要注意异常错误,保证读取数据的稳定性
     * @param user
     * @param context
     */
    @Override
    public void invoke(User user, AnalysisContext context) {
        log.info("解析到一条数据:{}", user);
        cachedDataList.add(user);
        if (cachedDataList.size() >= BATCH_COUNT) {
            // 处理缓存的数据,比如说入库。。。
            // 然后清空
            cachedDataList.clear();
        }
    }

    /**
     * 当每个sheet所有数据读取完毕后,会调用这个方法,可以在这个方法中进行一些收尾工作,如资源释放、数据汇总等。
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 收尾工作,处理剩下的缓存数据。。。

        log.info("sheet={} 所有数据解析完成!", context.readSheetHolder().getSheetName());
    }

}

@SpringBootTest
@RunWith(SpringRunner.class)
@Slf4j
public class ExcelTest {

    @Test
    public void testExcelRead() {
        String fileName = "/Users/shepherdmy/Desktop/test1.xlsx";
        EasyExcel.read(fileName, User.class, new UserExcelListener()).sheet().doRead();
        // 如果excel是多行表头比如说2行,需要设置行头数headRowNumber,默认不设置为1行表头,sheet不传默认读取第一个sheet
//        EasyExcel.read(fileName, User.class, new UserExcelListener()).sheet().headRowNumber(2).doRead();
    }
}

数据生成

 private List<DemoData> data() {
        List<DemoData> list = ListUtils.newArrayList();
        for (int i = 0; i < 10; i++) {
            DemoData data = new DemoData();
            data.setString("字符串" + i);
            data.setDate(new Date());
            data.setDoubleData(0.56);
            list.add(data);
        }
        return list;
    }
String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, DemoData.class)
            .sheet("模板")
            .doWrite(data());

常用注解

ExcelProperty

用于匹配excel和实体类的匹配,参数如下:

名称

默认值

描述

value

用于匹配excel中的头,必须全匹配,如果有多行头,会匹配最后一行头

order

Integer.MAX_VALUE

优先级高于value,会根据order的顺序来匹配实体和excel中数据的顺序

index

-1

优先级高于valueorder,会根据index直接指定到excel中具体的哪一列

converter

自动选择

指定当前字段用什么转换器,默认会自动选择。读的情况下只要实现com.alibaba.excel.converters.Converter#convertToJavaData(com.alibaba.excel.converters.ReadConverterContext<?>) 方法即可

ExcelIgnore

默认所有字段都会和excel去匹配,加了这个注解会忽略该字段

ExcelIgnoreUnannotated

默认不加ExcelProperty 的注解的都会参与读写,加了不会参与读写

DateTimeFormat

日期转换,用String去接收excel日期格式的数据会调用这个注解,参数如下:

名称

默认值

描述

value

参照java.text.SimpleDateFormat书写即可

use1904windowing

自动选择

excel中时间是存储1900年起的一个双精度浮点数,但是有时候默认开始日期是1904,所以设置这个值改成默认1904年开始

NumberFormat

数字转换,用String去接收excel数字格式的数据会调用这个注解。

名称

默认值

描述

value

参照java.text.DecimalFormat书写即可

roundingMode

RoundingMode.HALF_UP

格式化的时候设置舍入模式

踩坑点

  • 导入commons-io 依赖

  • easyexcel不要使用lombok,有冲突