Skip to content

前后端Excel处理篇——后端EasyExcel写操作入门

注:本文内容不包括EasyExcel写操作

文章大纲:

一、EasyExcel简介

Java领域解析,生成Excel比较有名的框架有Apache poijslx等,但他们都存在一个严重的问题就是非常的耗内存,如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc.

EasyExcel是阿里巴巴开源项目,基于Java的简单、省内存的Excel处理框架。

EasyExcel原理是通过POI的SAX模式,在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析,从而大大减少内存占用。

官网:https://www.yuque.com/easyexcel/

二、api

1、常用api

  • EasyExcel  入口类,用于构建开始各种操作
  • ExcelWriter 可以理解为一个工具类,直接完成EasyWriterBuilder的创建、数据的写入等
  • WriteWorkbook理解为Excel 工作簿、WriteSheet理解为Excel的sheet,WriteTable理解为sheet中的一块区域
  • **WriteHandler ** 类似切面 在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据

所有配置都是继承的,Workbook的配置会被Sheet继承,所以在用EasyExcel设置参数的时候,在EasyExcel...sheet()方法之前作用域是整个sheet,之后针对单个sheet

2、注解

  • ExcelProperty index 指定写到第几列,默认根据成员变量排序。value指定写入的名称,默认成员变量的名字,多个value可以参照快速开始中的复杂头
  • ExcelIgnore 默认所有字段都会写入excel,这个注解会忽略这个字段
  • DateTimeFormat日期转换,将Date写到excel会调用这个注解。里面的value参照java.text.SimpleDateFormat
  • NumberFormat 数字转换,用Number写excel会调用这个注解。里面的value参照java.text.DecimalFormat
  • ExcelIgnoreUnannotated 默认不加ExcelProperty 的注解的都会参与读写,加了不会参与

3、源码体系结构

个人看EasyExcel写操作相关源码,对EasyExcel 类体系结构的一个理解:

  • builder: ExcelWriterBuilderExcelWriterSheetBuilder等等,可以理解为最外层的构造器,配置执行逻辑,处于最上层
  • exector  根据builder中的逻辑执行,内置了handler切面
  • hander: 类似切面或Hook,在工作簿(WorkBook)、表(sheet)、行、单元格创建前后调用

三、怎么用

本部分只作为一个简要的引子,详细可看:官网写示例

https://www.yuque.com/easyexcel/doc/write

1、直接写

(1)常规写

java
   	/**
     * 实体类
     */
	@Data
    public class DemoData {
        @ExcelProperty("字符串标题")
        private String string;
        @ExcelProperty("日期标题")
        private Date date;
        @ExcelProperty("数字标题")
        private Double doubleData;
        /**
         * 忽略这个字段
         */
        @ExcelIgnore
        private String ignore;
    }
	/**
     * 最简单的写
     * <p>1. 创建excel对应的实体对象 参照{@link DemoData}
     * <p>2. 直接写即可
     */
    @Test
    public void simpleWrite() {
        // 写法1
        String fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
        // 如果这里想使用03 则 传入excelType参数即可
        EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());

        // 写法2—— 推荐
        fileName = TestFileUtil.getPath() + "simpleWrite" + System.currentTimeMillis() + ".xlsx";
        // 这里 需要指定写用哪个class去写
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(fileName, DemoData.class).build();
            WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
            excelWriter.write(data(), writeSheet);
        } finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

(2)自定义拦截器写

个人理解,EasyExcel 定义是简单、易用,但对于一些特殊的情况处理起来并不方便,且主要依赖拦截器实现

写法:自定义一个实现拦截器接口的类,在这个类中写自己需要的逻辑。

java
  	/**
     * 自定义实现拦截器接口的类
     */
	private static class RowHandler implements RowWriteHandler {
    
        @Override
        public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, 					Integer relativeRowIndex, Boolean isHead) {
		// 行创建之前执行逻辑代码
        }

        @Override
        public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer 						relativeRowIndex, Boolean isHead) {
		// 行创建之后执行逻辑代码
        }

        @Override
        public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer 						relativeRowIndex, Boolean isHead) {
        // 行处理完成后执行逻辑代码
        }
	}

2、模板写

Easyexcel的填充功能比较基础,适用于一些常规结构(基础列表型数据)Excel的处理,对于复杂的Excel处理更推荐JSLX进行处理。

模板填充功能官网示例:https://www.yuque.com/easyexcel/doc/fill

四、总结

EasyExcel 适用于对性能有要求且Excel常规结构(基础列表型数据)的情形,它的API使用简易,但对于复杂Excel的处理主要依赖在拦截器中写业务逻辑实现,使用并不简便。