跳到主要内容

填充

本章节介绍如何使用 Fesod 来填充数据到文件中。

占位符语法

模板通过 {} 占位符标记需要填充的单元格,大括号里的内容决定了填充方式:

占位符含义由谁填充
{name}单个变量doFill(object)doFill(map)
{.name}列表中每一项的 name 属性doFill(list)fill(list, ...)
{data1.name}同上,但取自名为 data1 的列表fill(new FillWrapper("data1", list), ...)
\{name\}\ 转义,不会被解析不填充

开头的 . 决定了单元格会按列表的每一项重复:默认向下重复,也可以通过 FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL) 向右重复。. 之前的文字指明数据来自哪个列表,因此一个模板中可以并存多个列表。

一个单元格里可以混合多个占位符和普通文本,例如 {name}今年{number}岁了。填充时没有提供的占位符会被清空,而不是原样留在表格里:用列表填充 {name},或者用单个对象填充 {.name},都会清空该单元格,只保留周围的文本。

转义只是让大括号不被解析,而 \ 本身只有在同一个单元格里还存在真实占位符时才会被去掉。如果单元格里没有别的内容,\{name\} 会原样写出,包括反斜杠。

简单填充

概述

基于模板文件,通过对象或 Map 填充数据到电子表格中。

POJO 类

@Getter
@Setter
@EqualsAndHashCode
public class FillData {
private String name;
private double number;
private Date date;
}

数据列表

private List<FillData> data() {
List<FillData> list = ListUtils.newArrayList();
for (int i = 0; i < 10; i++) {
FillData fillData = new FillData();
fillData.setName("张三" + i);
fillData.setNumber(5.2);
fillData.setDate(new Date());
list.add(fillData);
}
return list;
}

代码示例

@Test
public void simpleFill() {
String templateFileName = "path/to/simple.xlsx";

// 方案1:基于对象填充
FillData fillData = new FillData();
fillData.setName("张三");
fillData.setNumber(5.2);
FesodSheet.write("simpleFill.xlsx")
.withTemplate(templateFileName)
.sheet()
.doFill(fillData);

// 方案2:基于 Map 填充
Map<String, Object> map = new HashMap<>();
map.put("name", "张三");
map.put("number", 5.2);
FesodSheet.write("simpleFillMap.xlsx")
.withTemplate(templateFileName)
.sheet()
.doFill(map);
}

模板

ABCDE
1姓名数字复杂忽略
2{name}{number}{name}今年{number}岁了\{name\}忽略,{name}空{.empty}

结果

ABCDE
1姓名数字复杂忽略
2张三5.2张三今年5.2岁了{name}忽略,张三

填充列表

概述

填充多个数据项到模板列表中,支持内存批量操作和文件缓存分批填充。

代码示例

@Test
public void listFill() {
String templateFileName = "path/to/list.xlsx";

// 方案1:一次性填充所有数据
FesodSheet.write("listFill.xlsx")
.withTemplate(templateFileName)
.sheet()
.doFill(data());

// 方案2:分批填充
try (ExcelWriter writer = FesodSheet.write("listFillBatch.xlsx").withTemplate(templateFileName).build()) {
WriteSheet writeSheet = FesodSheet.writerSheet().build();
writer.fill(data(), writeSheet);
writer.fill(data(), writeSheet);
}
}

模板

ABC
1姓名数字日期
2{.name}{.number}{.date}

结果

方案1:

ABC
1姓名数字日期
2张三05.22026-07-31 19:55:44
3张三15.22026-07-31 19:55:44
4张三25.22026-07-31 19:55:44
11张三95.22026-07-31 19:55:44

方案2:

ABC
1姓名数字日期
2张三05.22026-07-31 19:55:44
11张三95.22026-07-31 19:55:44
12张三05.22026-07-31 19:55:44
21张三95.22026-07-31 19:55:44

复杂填充

概述

在模板中填充多种数据类型,包括列表和普通变量。

代码示例

@Test
public void complexFill() {
String templateFileName = "path/to/complex.xlsx";

try (ExcelWriter writer = FesodSheet.write("complexFill.xlsx").withTemplate(templateFileName).build()) {
WriteSheet writeSheet = FesodSheet.writerSheet().build();

// 填充列表数据,开启 forceNewRow
FillConfig config = FillConfig.builder().forceNewRow(true).build();
writer.fill(data(), config, writeSheet);

// 填充普通变量
Map<String, Object> map = new HashMap<>();
map.put("date", "2024年11月20日");
map.put("total", 1000);
writer.fill(map, writeSheet);
}
}

模板

ABCD
1统计
2时间:{date}
3姓名数字姓名数字
4{.name}{.number}{.name}{.number}
5统计:{total}

结果

ABCD
1统计
2时间:2024年11月20日
3姓名数字姓名数字
4张三05.2张三05.2
5张三15.2张三15.2
6张三25.2张三25.2
13张三95.2张三95.2
14统计:1000

大数据量填充

概述

优化大数据量填充性能,确保模板列表在最后一行,后续数据通过 WriteTable 填充。

代码示例

@Test
public void complexFillWithTable() {
String templateFileName = "path/to/complexFillWithTable.xlsx";

try (ExcelWriter writer = FesodSheet.write("complexFillWithTable.xlsx").withTemplate(templateFileName).build()) {
WriteSheet writeSheet = FesodSheet.writerSheet().build();

// 填充列表数据
writer.fill(data(), writeSheet);

// 填充其他变量
Map<String, Object> map = new HashMap<>();
map.put("date", "2024年11月20日");
writer.fill(map, writeSheet);

// 填充统计信息
List<List<String>> totalList = new ArrayList<>();
totalList.add(Arrays.asList(null, null, null, "统计: 1000"));
writer.write(totalList, writeSheet);
}
}

模板

ABCD
1统计
2时间:{date}
3姓名数字姓名数字
4{.name}{.number}{.name}{.number}

结果

最终文件与上面的复杂填充相同,区别在于生成方式:模板到列表行为止,不再为 {total} 预留一行,统计信息在填充之后通过 writer.write(...) 追加,因此列表可以任意增长,下方没有需要被顶下去的行。

ABCD
1统计
2时间:2024年11月20日
3姓名数字姓名数字
4张三05.2张三05.2
5张三15.2张三15.2
6张三25.2张三25.2
13张三95.2张三95.2
14统计: 1000

横向填充

概述

将列表数据横向填充,适用于动态列数场景。

代码示例

@Test
public void horizontalFill() {
String templateFileName = "path/to/horizontal.xlsx";

try (ExcelWriter writer = FesodSheet.write("horizontalFill.xlsx").withTemplate(templateFileName).build()) {
WriteSheet writeSheet = FesodSheet.writerSheet().build();

FillConfig config = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
writer.fill(data(), config, writeSheet);

Map<String, Object> map = new HashMap<>();
map.put("date", "2024年11月20日");
writer.fill(map, writeSheet);
}
}

模板

ABC
1统计姓名{.name}
2数字{.number}
3姓名{.name}
4数字{.number}
5时间:{date}

结果

ABCDEL
1统计姓名张三0张三1张三2张三9
2数字5.25.25.25.2
3姓名张三0张三1张三2张三9
4数字5.25.25.25.2
5时间:2024年11月20日

多列表组合填充

概述

支持多个列表同时填充,列表之间通过前缀区分。

代码示例

@Test
public void compositeFill() {
String templateFileName = "path/to/composite.xlsx";

try (ExcelWriter writer = FesodSheet.write("compositeFill.xlsx").withTemplate(templateFileName).build()) {
WriteSheet writeSheet = FesodSheet.writerSheet().build();

// 使用 FillWrapper 进行多列表填充
// data1 在模板中是横向排列的,因此使用横向填充
FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
writer.fill(new FillWrapper("data1", data()), fillConfig, writeSheet);
writer.fill(new FillWrapper("data2", data()), writeSheet);
writer.fill(new FillWrapper("data3", data()), writeSheet);

Map<String, Object> map = new HashMap<>();
map.put("date", new Date());
writer.fill(map, writeSheet);
}
}

模板

ABCDE
1统计姓名{data1.name}
2数字{data1.number}
3姓名{data1.name}
4数字{data1.number}
5时间:{date}
6
7
8姓名数字
9{data2.name}{data2.number}
10姓名数字
11{data3.name}{data3.number}

结果

  • data1 采用横向填充,十条数据在四个模板行上从 C 列排到 L 列。
  • data2data3 则是纵向填充,分别占据第 9 到 18 行的 A/B 列和第 11 到 20 行的 D/E 列。
  • 用同一个列表名调用 fill 会接着往后追加,参见填充列表
ABCDEL
1统计姓名张三0张三1张三2张三9
2数字5.25.25.25.2
3姓名张三0张三1张三2张三9
4数字5.25.25.25.2
5时间:2026-07-31 20:04:59
6
7
8姓名数字
9张三05.2
10张三15.2姓名数字
11张三25.2张三05.2
12张三35.2张三15.2
18张三95.2张三75.2
19张三85.2
20张三95.2