一.概述

EasyExcel是alibaba开源的一个excel处理框架,以使用简单,节省内存著称,EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。

1.应用场景

1.数据导入:减轻录入的工作量
2.数据导出:统计信息归档
3.数据传输:异构系统之间数据传输

2.EasyPoi和EasyExcel的区别:

EasyPoi和EasyExcel都是基于Apache POI进行二次开发的。
不同点在于:

  1. EasyPoi 在读写数据的时候,优先是先将数据写入内存,优点是读写性能非常高,但是当数据量很大的时候,会出现OOM,当然它也提供了 sax 模式的读写方式,需要调用特定的方法实现。它主要的特点就是将更多重复的工作,全部简单化,避免编写重复的代码!
  2. EasyExcel 基于sax模式一行一行解析进行读写数据,不会出现OOM情况,在并发量很大的情况下,程序在经过高并发场景的验证下,依然能稳定运行!相对于 EasyPoi 来说,读写性能稍慢!

OOM(Out Of Memory) 翻译成中文就是”内存用完了”

SAX(simple API for XML) 是一种XML解析的替代方法。相比于DOM,SAX是一种速度更快,更有效的方法。它逐行扫描文档,一边扫描一边解析。而且相比于DOM,SAX可以在解析文档的任意时刻停止解析,但任何事物都有其相反的一面,对于SAX来说就是操作复杂。

二.快速入门

1.导包

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. <optional>true</optional>
  5. </dependency>
  6. <dependency>
  7. <groupId>com.alibaba</groupId>
  8. <artifactId>easyexcel</artifactId>
  9. <version>2.1.1</version>
  10. </dependency>

2.读取操作

读取excel需要先写一个监听器继承AnalysisEventListener

实体类:

  1. @Data
  2. public class DemoData {
  3. //设置excel表头名称
  4. @ExcelProperty(value = "学生编号",index = 0)
  5. private Integer sno;
  6. @ExcelProperty(value = "学生姓名",index = 1)
  7. private String sname;
  8. }

第一种方式:

单独定义一个类去继承AnalysisEventListener

(1)配置
  1. public class ExcelListener extends AnalysisEventListener<DemoData> {
  2. //一行一行读取excel内容
  3. @Override
  4. public void invoke(DemoData data, AnalysisContext analysisContext) {
  5. System.out.println("****"+data);
  6. }
  7. //读取表头内容
  8. @Override
  9. public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
  10. System.out.println("表头:"+headMap);
  11. }
  12. //读取完成之后
  13. @Override
  14. public void doAfterAllAnalysed(AnalysisContext analysisContext) { }
  15. }

(2)代码
  1. public class TestEasyExcelRead {
  2. public static void main(String[] args) {
  3. //实现excel读操作
  4. String filename = "D:\\Desktop\\write.xlsx";
  5. EasyExcel.read(filename,DemoData.class,new ExcelListener()).sheet().doRead();
  6. }
  7. }

(3)运行结果

image.png

第二种方式:

使用匿名内部类取代配置类

(1)代码:
  1. @Test
  2. public void read2() {
  3. List<DemoData> list = new ArrayList<>();
  4. //实现excel读操作
  5. String filename = "D:\\Desktop\\write.xlsx";
  6. // write方法两个参数:第一个参数文件路径名称,第二个参数实体类class
  7. EasyExcel.read(filename, DemoData.class, new AnalysisEventListener<DemoData>() {
  8. //重写子类方法
  9. @Override
  10. public void invoke(DemoData demoData, AnalysisContext analysisContext) {
  11. list.add(demoData);
  12. }
  13. //重写子类方法
  14. @Override
  15. public void doAfterAllAnalysed(AnalysisContext analysisContext) {
  16. }
  17. @Override
  18. public void invokeHeadMap(Map headMap, AnalysisContext context) {
  19. System.out.println("表头:" + headMap);
  20. }
  21. }).sheet().doRead();
  22. //遍历
  23. for (DemoData data : list) {
  24. System.out.println(data);
  25. }
  26. }

3.写入操作

(1)实体类

①表头设置

  1. @Data
  2. public class DemoData {
  3. //value:设置表头名称
  4. //index:设置对应的列编号,标记对应列关系
  5. @ExcelProperty(value = "学生编号",index = 0)
  6. private Integer sno;
  7. @ExcelProperty(value = "学生姓名",index = 1)
  8. private String sname;
  9. }

②复杂表头
添加该实体列的注释就可以实现如下:

  1. @Data
  2. public class DemoData {
  3. //设置excel表头名称
  4. @ExcelProperty({"主标题","学生编号"})
  5. private Integer id;
  6. @ExcelProperty({"主标题","学生姓名"})
  7. private String name;
  8. }

效果:
image.png

③列宽 行高

  1. @Data
  2. @HeadRowHeight(30) //表头行高
  3. @ContentRowHeight(20) //数据行高
  4. @ColumnWidth(25) //列宽
  5. public class DemoData {
  6. //设置excel表头名称
  7. @ExcelProperty({"主标题","学生编号"})
  8. private Integer id;
  9. //局部定义
  10. @ColumnWidth(50)
  11. @ExcelProperty({"主标题","学生姓名"})
  12. private String name;
  13. }

效果:
image.png

(2)代码

  1. package com.example.easyexceldemo.controller;
  2. import com.alibaba.excel.EasyExcel;
  3. import com.example.easyexceldemo.entity.DemoData;
  4. import java.util.ArrayList;
  5. import java.util.List;
  6. public class TestEasyExcelWrite {
  7. public static void main(String[] args) {
  8. //实现excel写的操作
  9. //1 设置写入文件夹地址和excel文件名称
  10. String filename = "D:\\Desktop\\write.xlsx";
  11. // 2 调用easyexcel里面的方法实现写操作
  12. // write方法两个参数:第一个参数文件路径名称,第二个参数实体类class
  13. EasyExcel.write(filename,DemoData.class).
  14. sheet("学生列表").
  15. doWrite(getData());
  16. }
  17. //创建方法返回list集合
  18. private static List<DemoData> getData() {
  19. List<DemoData> list = new ArrayList<>();
  20. for (int i = 0; i < 10; i++) {
  21. DemoData data = new DemoData();
  22. data.setId(i);
  23. data.setName("lucy"+i);
  24. list.add(data);
  25. }
  26. return list;
  27. }
  28. }

(3)运行结果

image.png


三.常用注解

1.读取操作
●ExcelProperty
指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第
一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用
名字 去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。
● ExcelIgnore
默认所有字段都会和excel去匹配,加了这个注解会忽略该字段
● DateTimeFormat
日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照 java.text.SimpleDateFormat
● NumberFormat
数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照 java.text.DecimalFormat
● ExcelIgnoreUnannotated
默认不加ExcelProperty 的注解的都会参与读写,加了不会参与

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