一、数据读取
1. 模拟数据
首先先准备一个 Excel
数据文件,文件内容如下:
id name gender birthday
1 User-1 Male 2024-01-29
2 User-2 Male 2024-01-29
3 User-3 Male 2024-01-29
4 User-4 Male 2024-01-29
2. 实体读取
EasyExcel
支持匹配 Java
实体读取文件内容,文件的列名需要何 Java
类的字段名相对应。
如下示例中即读取第一步中的模拟数据最终返回一个列表集合。
public class ExcelUser {
private String id;
private String name;
private String gender;
private Date birthday;
}
public class ExcelReadTest {
@Test
public void readDemo2() {
String fileLocate = "src\\main\\resources\\info.xls";
try (InputStream in = Files.newInputStream(Paths.get(fileLocate))) {
List<ExcelUser> list = EasyExcel.read(in)
.head(ExcelUser.class)
.sheet()
.doReadSync();
System.out.println(list);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
3. 动态读取
EasyExcel
除了支持实体类读取之外还可以动态指定列名进行读取,返回的结果为 List<LinkedMap<Integer, Object>>
,其中每一个 LinkMap
对应文件内的一行数据。
需要注意这里传入的列头集合类型是 List<List<String>>
而非 List<String>
,即数据格式如:[["id"], ["name"]]
。同时 EasyExcel
支持多种读入方式,在上一点示例中通过 IO
方法读取,下述示例则直接传入文件路径,可根据需要选择。
public void readDemo1() {
String fileLocate = "src\\main\\resources\\info.xls";
List<List<String>> heads = Stream.of("id", "name", "gender", "birthday")
.map(Arrays::asList)
.collect(Collectors.toList());
List<LinkedMap<Integer, Object>> list = EasyExcel.read(fileLocate)
.head(heads)
.sheet()
.doReadSync();
System.out.println(list);
}
二、数据写入
1. 写入示例
EasyExcel
写入操作与读取类似,其中的 excelType
为文件类型,可选值有下述三类,对应三种不同的数据文件格式。
ExcelTypeEnum.CSV
ExcelTypeEnum.XLS
ExcelTypeEnum.XLSX
这里同样是采取实体字段名匹配的方式写入数据,示例代码如下:
public void readDemo1() {
List<ExcelUser> dataList = new ArrayList<>();
for (int i = 1; i < 5; i++) {
dataList.add(new ExcelUser(i + "", "User-" + i, "Male", new Date()));
}
String fileLocate = "src\\main\\resources\\info.xls";
EasyExcel.write(fileLocate)
.excelType(ExcelTypeEnum.XLS)
.head(ExcelUser.class)
.sheet("Test-data")
.doWrite(data);
}
2. Sheet管理
当需要写入多个 Sheet
到同一个 Excel
文件时,即可使用 ExcelWriterSheetBuilder
。
如下述示例中即创建两个 Sheet
页数据,Sheet
页名称分别为 Sheet-1
和 Sheet-2
。
public void multipleWrite() throws IOException {
List<ExcelUser> dataList = new ArrayList<>();
for (int i = 1; i < 5; i++) {
dataList.add(new ExcelUser(i + "", "User-" + i, "Male", new Date()));
}
String fileLocate = "src\\main\\resources\\info.xls";
ExcelWriter excelWriter = EasyExcel.write(fileLocate)
.excelType(ExcelTypeEnum.XLS)
.build();
// 循环创建两个 Sheet 页数据
for (int i = 1; i <= 2; i++) {
ExcelWriterSheetBuilder sheetBuilder = new ExcelWriterSheetBuilder(excelWriter);
sheetBuilder.sheetName("Sheet-" + i);
sheetBuilder.head(ExcelUser.class);
sheetBuilder.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy());
excelWriter.write(dataList, sheetBuilder.build());
}
excelWriter.finish();
}
3. 动态写入
在许多场景下数据是变动的通过实体匹配显然是不合适的,因此 EasyExcel 提供了动态写入的能力。
与上述提到的读取和写入类似,其列名通过 List<List<String>>
指定,但不同的是其数据的载体是 List<Object>
而非 List<Map>
,因此在写入时我们需要将后者数据格式转为 List<Object>
,对应的数据转化样例如下:
// List<Map<String, Object>>
[
{
"id": "1",
"name": "user-1",
"gender": "Male",
"birthday": "2023-01-01 00:00:01"
},
{
"id": "2",
"name": "user-2",
"gender": "Male",
"birthday": "2023-01-01 00:00:02"
}
]
// List<Object>
[
["1", "user-1", "Male", "2023-01-01 00:00:01"],
["2", "user-2", "Male", "2023-01-01 00:00:02"]
]
根据上述逻辑,其相对应的程序代码如下:
public void dynamicWrite() throws IOException {
List<Map<String, Object>> dataList = new ArrayList<>();
for (int i = 1; i < 5; i++) {
Map<String, Object> map = Map.of(
"id", i + "",
"name", "user-" + i,
"gender", "Male",
"birthday", new Date()
);
dataList.add(map)
}
// Convert "List<Map<?, ?>>" to "List<?>"
List<List<Object>> rowDatas = new ArrayList<>();
for (Map<String, Object> map : dataList) {
List<Object> row = new ArrayList<>();
for (String name : headList) {
row.add(map.get(name));
}
rowDatas.add(row);
}
// Excel head
List<List<String>> heads = Stream.of("id", "name", "gender", "birthday")
.map(Arrays::asList)
.collect(Collectors.toList());
// Writer data
String fileLocate = "src\\main\\resources\\info.xls";
EasyExcel.write(fileLocate)
.excelType(ExcelTypeEnum.XLS)
.head(heads)
.sheet("Test-data")
.doWrite(rowDatas);
}
三、注解使用
1. ExcelProperty
@ExcelProperty
注解存在 value
与 order
两个属性,前者用于设置别名,后者用于设置列顺序。
如下示例中则最后生成 Excel
文件中列名分别为 编号
与 姓名
,其中第一列为 编号
,第二列为 姓名
。
public class ExcelUser {
@ExcelProperty(value = "编号", order = 1)
private String id;
@ExcelProperty(value = "姓名", order = 2)
private String name;
}
2. ExcelIgnore
@ExcelIgnore
用于指定需要忽略的属性。
如下示例在读取或写入文件时将忽略 address
字段。
public class ExcelUser {
private String id;
@ExcelIgnore
private Date address;
}
3. DateTimeFormat
@DateTimeFormat
用于指定格式化字段时间
如下示例在读取或写入文件时将会格式化字段 birthday
字段 值为 yyy-MM-dd
格式。
public class ExcelUser {
private String id;
@DateTimeFormat("yyy-MM-dd")
private Date birthday;
}