EasyExcel简单实例
- 准备工作
- 场景一:读取 Student 表
- 需求1:简单读取
- 需求2:读取到异常信息时不中断
- 需求3:读取所有的sheet工作表
- 需求4:读取指定的sheet工作表
- 需求5:从指定的行开始读取
- 场景二:写入 Student 表
- 需求1:简单写入
- 需求2:写入指定列
- 需求3:指定写入列的名称和顺序
- 需求4:写入多级表头
- 需求5:重复写入
- 需求6:往多个工作簿写入相同数据
- 需求7:往多个工作簿写入不同数据
准备工作
导入easyExcel依赖,注意版本:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.1</version>
</dependency>
场景一:读取 Student 表
需求1:简单读取
源表:
1. 编写实体类
可以使用 @ExcelProperty
指定数据封装为实体类对象的规则,后面可以跟index 和 列名(二选一);
若不加注解则按照默认封装规则: ①根据 Excel 列与实体类属性的顺序②根据 Excel 列的单元格式与对象字段类型匹配。
@Data
public class Student {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年级")
private String grade;
@ExcelProperty("年龄")
private int age;
}
2. 监听器
invoke()
:每读取一行就执行的方法,每一行数据会被封装成一个 student 对象(invoke方法的第一个参数);
doAfterAllAnalysed()
:读取结束后执行的方法;
class studentListener implements ReadListener<Student> {
int i=1;
@Override
public void invoke(Student student, AnalysisContext context) {
System.out.println("读取到第 "+(i++)+" 行:"+student);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("\nxlsx文件读取结束");
}
}
3. 测试类
read()
:读取workbook工作簿,传入文件路径、实体类、监听器;
sheet()
:选定读取的工作表,默认读取第一个;
doRead()
:执行读操作;
public class easyExcelTest {
@Test
public void readTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
EasyExcel.read(filePath,
Student.class,
new studentListener()).
sheet().
doRead();
}
}
打印效果:
需求2:读取到异常信息时不中断
源表:
当出现了不符合数据类型的数据时,希望不中断读取
1. 实体类:
不变;
2. 监听器:
只需要调整监听器,在监听器加入 onException()
方法;
class studentListener implements ReadListener<Student> {
int i = 1;
@Override
public void invoke(Student student, AnalysisContext context) {
System.out.println("读取到第 " + (i++) + " 行:" + student);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("\nxlsx文件读取结束");
}
@Override
public void onException(Exception exception, AnalysisContext context) throws Exception {
System.out.println("读取异常:"+exception);
}
}
3. 测试类:
不变;
打印效果:
异常数据被打印,且不中断读取;
需求3:读取所有的sheet工作表
源表:
此时多个sheet都有数据;
1. 实体类
不变;
2. 监听器
不变;
3. 测试类
将sheet().doRead改为 doReadAll()
;
public class easyExcelTest {
@Test
public void readTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
EasyExcel.read(filePath,
Student.class,
new studentListener()).
doReadAll();
}
}
效果:
读取到了两个sheet的数据:
需求4:读取指定的sheet工作表
源表:
此时多个sheet都有数据;
1. 实体类
不变;
2. 监听器
不变;
3. 测试类
在sheet()中传递指定sheet的index索引或者名称即可:
public class easyExcelTest {
@Test
public void readTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
EasyExcel.read(filePath,
Student.class,
new studentListener()).
sheet("Sheet2").
doRead();
EasyExcel.read(filePath,
Student.class,
new studentListener()).
sheet("Sheet1").
doRead();
}
}
效果:
此时先指定读取sheet2,再读取sheet1;
需求5:从指定的行开始读取
源表:
假设此时有多行表头,内容需要从第3行开始读取;
1. 实体类
不变;
2. 监听器
不变;
3. 测试类
使用 headRowNumber()
,参数中填写开始读取的行数;(默认从第2行开始读取,即headRowNumber()默认参数是索引1);
此时读取的内容要从第3行开始,索引为2,所以填入headRowNumber()的参数为2!
public class easyExcelTest {
@Test
public void readTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
EasyExcel.read(filePath,
Student.class,
new studentListener()).
sheet("Sheet1").
headRowNumber(2).
doRead();
}
}
效果:
场景二:写入 Student 表
需求1:简单写入
1. 实体类
需要比读取excel多添加实体类的构造函数;
@Data
public class Student {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("年级")
private String grade;
@ExcelProperty("年龄")
private int age;
public Student(){}
public Student(String name, String grade, int age) {
this.name = name;
this.grade = grade;
this.age = age;
}
}
2. 模拟建数据的类
将每一行数据封装为Student对象,并放入一个List集合中;
class CreateData{
public static List<Student> create(){
List<Student> datas = Arrays.asList(
new Student("张三","一年级",23),
new Student("里斯","一年级",19),
new Student("王五","一年级",22),
new Student("赵六","一年级",21)
);
return datas;
}
}
3. 测试类
写的时候会自动将实体类的属性作为excel表的表头;
sheet()的参数为写入的工作表;
doWrite()的参数为要写入的数据,要求格式为Collection集合类型;
- 写法1
public class easyExcelTest {
@Test
public void writeTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
EasyExcel.write(filePath,
Student.class).
sheet("学生表1").
doWrite(CreateData.create()); // doWrite()的参数为 Collection 集合
}
- 写法2:
适合写多个sheet;
public class easyExcelTest {
@Test
public void writeTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
try(ExcelWriter excelWriter=EasyExcel.write(filePath,Student.class).build()){
WriteSheet writeSheet=EasyExcel.writerSheet("学生表2").build();
excelWriter.write(CreateData.create(),writeSheet);
}
}
效果:
成功生成指定sheet表的数据!
需求2:写入指定列
-
方法1:注解排除某列
不写哪列就在对应的属性加上@ExcelIgnore
属性;
-
方法2:给
excludeColumnFieldNames()
传入不包含的列
注意:set中方的列明是实体类的属性名,而不是表格中的列名!
-
方法3:给
includeColumnFieldNames()
传入所有要写的列
效果:
年龄age一列没有写入excel;
需求3:指定写入列的名称和顺序
1. 实体类
同样使用 @ExcelProperty 注解来指定写入列的名称和索引!
注意:顺序 index是从0开始的;
2. 模拟建数据的类
不变;
3. 测试类
不变;
效果:
需求4:写入多级表头
目标样式:
此时有多级表头;
- 实体类
在@ExcelProperty
注解中对表头进行分级!上层表头相同的属性就会归到一块!
2. 模拟建数据的类
不变;
3. 测试类
不变;
效果:
需求5:重复写入
1. 实体类
不变;
2. 模拟建数据的类
不变;
3. 测试类
使用循环来实现重复写入;
public class easyExcelTest {
@Test
public void writeTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
try (ExcelWriter excelWriter = EasyExcel.write(filePath, Student.class).build()) {
WriteSheet writeSheet = EasyExcel.writerSheet("学生表1").build();
for (int i = 0; i < 3; i++) {
excelWriter.write(CreateData.create(), writeSheet);
}
}
}
}
效果:
重复写入了3次;
需求6:往多个工作簿写入相同数据
1. 实体类
不变;
2. 模拟建数据的类
不变;
3. 测试类
使用循环来实现重复写入;
public class easyExcelTest {
@Test
public void writeTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
try (ExcelWriter excelWriter = EasyExcel.write(filePath, Student.class).build()) {
for (int i = 1; i <= 3; i++) {
WriteSheet writeSheet = EasyExcel.writerSheet("学生表"+i).build();
excelWriter.write(CreateData.create(), writeSheet);
}
}
}
}
效果:
三个sheet都有相同的数据;
需求7:往多个工作簿写入不同数据
此时要在不同的sheet写入 student 和 teacher两个不同的表!
1. 实体类
新增 Teacher 实体类;
@Data
public class Teacher {
@ExcelProperty("姓名")
private String name;
@ExcelProperty("科目")
private String subject;
@ExcelProperty("年龄")
private int age;
public Teacher(){}
public Teacher(String name, String subject, int age) {
this.name = name;
this.subject = subject;
this.age = age;
}
}
2. 模拟建数据的类
新增教师数据;
class CreateData {
public static List<Student> createStudent() {
List<Student> datas = Arrays.asList(
new Student("张三", "一年级", 23),
new Student("里斯", "一年级", 19),
new Student("王五", "一年级", 22),
new Student("赵六", "一年级", 21)
);
return datas;
}
public static List<Teacher> createTeacher() {
List<Teacher> datas = Arrays.asList(
new Teacher("张老师", "政治", 41),
new Teacher("李老师", "高数", 42),
new Teacher("王老师", "线代", 39),
new Teacher("赵老师", "英语", 40)
);
return datas;
}
}
3. 测试类
建立不同的sheet对象来写入;
public class easyExcelTest {
@Test
public void writeTest() {
String filePath = "C:\\Users\\liziq\\Desktop\\student.xlsx";
// 此时 EasyExcel.write() 的参数不传入实体类.class
try (ExcelWriter excelWriter = EasyExcel.write(filePath).build()) {
//1. 创建不同的 sheet
WriteSheet studentSheet = EasyExcel.writerSheet("学生表").head(Student.class).build();
WriteSheet teacherSheet = EasyExcel.writerSheet("教师表").head(Teacher.class).build();
//2. 向不同的sheet写入数据
excelWriter.write(CreateData.createStudent(), studentSheet);
excelWriter.write(CreateData.createTeacher(), teacherSheet);
}
}
}
效果:
在两个sheet分别写入了不同的数据;