1.EasyExcel介绍

​ Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,一个3M的excel用POI sax解析依然需要100M左右内存,改用easyexcel可以降低到几M,并且再大的excel也不会出现内存溢出;03版依赖POI的sax模式,在上层做了模型转换的封装,让使用者更加简单方便

官网地址:https://easyexcel.opensource.alibaba.com/

2.入门

2.1 引入依赖

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/com.alibaba/easyexcel -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.1</version>
</dependency>

2.2 创建与Excel表格对应的实体类,并在属性上加上注解

不用自己设置excel表中的表头信息,easyexcel会帮我们设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package test;

import com.alibaba.excel.annotation.ExcelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
* @author GongChangjiang
* @version 1.0
* @Date 2023/4/14
* @Description 与Excel表格对应的实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserData {

/**
* 注解中value 设置的是表头的信息
* index 设置的是这个属性在excel表格中的索引位置 列索引
*/

@ExcelProperty(value = "用户编号", index = 0)
private int uid;

@ExcelProperty(value = "用户名称", index = 1)
private String username;


}

2.3 读写操作

1.写操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package test;

import com.alibaba.excel.EasyExcel;

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

/**
* @author GongChangjiang
* @version 1.0
* @Date 2023/4/14
* @Description 测试对excel的操作
*/
public class TestEasyExcel {
public static void main(String[] args) {
//设置excel文件的路径和名称
String filename = "C:\\AlYun\\user.xlsx";

//构建一个数据的list集合,存放要保存在excel表中的数据
List<UserData> userDataList = new ArrayList<>();
userDataList.add(new UserData(1,"张三"));
userDataList.add(new UserData(2,"李四"));
userDataList.add(new UserData(3,"王五"));
userDataList.add(new UserData(4,"赵六"));

//调用方法实现写的操作
EasyExcel.write(filename,UserData.class)
.sheet("用户信息")
.doWrite(userDataList);

}
}

执行之后,空的excel表中会添加如下的数据

image-20230414131020923

2.读操作

1 .创建一个读操作的监听器

继承AnalysisEventListener T表示实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package test;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;

import java.util.Map;

/**
* @author GongChangjiang
* @version 1.0
* @Date 2023/4/14
* @Description 读操作的监听器
*/
public class ExcelLister extends AnalysisEventListener<UserData> {

/**
* 一行一行的读取 从第二行开始读取
*/
@Override
public void invoke(UserData data, AnalysisContext context) {
//打印输出读取到的数据
System.out.println(data);
}

/**
* 读取之后执行
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {

}


/**
* 非必须实现的方法
* 此方法可以读取表头的信息
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
//打印读取到的表头信息
System.out.println("表头信息:"+headMap);
}
}
5.编写方法测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package test;

import com.alibaba.excel.EasyExcel;

/**
* @author GongChangjiang
* @version 1.0
* @Date 2023/4/14
* @Description
*/
public class TestReadExcel {
public static void main(String[] args) {
//设置excel文件的路径和名称
String filename = "C:\\AlYun\\user.xlsx";
//调用方法实现读取操作
//new ExcelLister()自己创建的监听器
EasyExcel.read(filename,UserData.class,new ExcelLister())
.sheet()
.doRead();
}
}

3.监听器中实现对数据库的操作

解决listener中无法操作数据库的问题

3.1 通过构造器注入的方式

在进行读操作创建Listener的时候,注入mapper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.atguigu.yygh.cmn.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.atguigu.yygh.cmn.mapper.DictMapper;
import com.atguigu.yygh.model.cmn.Dict;
import com.atguigu.yygh.vo.cmn.DictEeVo;
import org.springframework.beans.BeanUtils;


/**
* @author GongChangjiang
* @version 1.0
* @Date 2023/4/14
* @Description
*/
public class DictListener extends AnalysisEventListener<DictEeVo> {

private DictMapper dictMapper;

public DictListener(DictMapper dictMapper) {
this.dictMapper = dictMapper;
}

@Override
public void invoke(DictEeVo data, AnalysisContext context) {
//调用mapper 添加数据
Dict dict = new Dict();
BeanUtils.copyProperties(data,dict);
dictMapper.insert(dict);

}

@Override
public void doAfterAllAnalysed(AnalysisContext context) {

}
}

3.2 使用注解加属性注入的方式

1
2
3
@Component
+
@Autowired