easy excel往指定的模板文件里的第一个sheet设置多级表头并填充数据
时间: 2025-07-27 15:21:46 浏览: 10
<think>我们使用EasyExcel操作Excel文件,特别是处理多级表头和填充数据。步骤:1.准备模板文件:第一个Sheet已经设计好表头(可能有多级)和固定的样式,但数据区域为空。2.定义数据模型:在Java中创建与表头对应的实体类(可能需要使用注解来匹配多级表头)。3.使用EasyExcel的填充功能:读取模板文件,将数据填充到指定位置。多级表头的设置:在模板文件中,我们通常会在第一行开始设置多级表头,例如:第一行:一级表头1,一级表头2,...第二行:二级表头1-1,二级表头1-2,...,二级表头2-1,...在实体类中,我们可以使用@ExcelProperty注解来指定多级表头。例如:@ExcelProperty({"一级表头1","二级表头1-1"})private Stringfield1;@ExcelProperty({"一级表头1","二级表头1-2"})private Stringfield2;@ExcelProperty({"一级表头2", "二级表头2-1"})privateString field3;填充数据:我们可以使用EasyExcel的填充器(ExcelWriter)来填充数据。有两种方式:a.简单填充:使用map,键为模板中的变量名(如{{name}}),值为填充的数据。b.列表填充:模板中设置变量{{.}},然后填充一个集合。但是,如果我们要在模板的第一个Sheet中填充,并且模板已经有多级表头,那么我们需要:-读取模板文件,定位到第一个Sheet。-使用填充功能,将数据填充到表头下面的数据区域。具体步骤:1.创建填充模板的ExcelWriter对象:ExcelWriter excelWriter =EasyExcel.write(outputStream).withTemplate(templateInputStream).build();2.创建FillConfig对象,设置填充模式(比如是否强制使用模板样式,是否换行填充等):FillConfigfillConfig= FillConfig.builder().forceNewRow(Boolean.TRUE).build();3.填充数据:-如果填充单个对象(比如单个数据或Map),使用fill方法:excelWriter.fill(data, fillConfig,writeSheet);-如果填充多个对象(比如多个数据区域),可以多次调用fill。-如果填充列表(多行数据),使用fill方法并传入集合:excelWriter.fill(newFillWrapper("data", list), fillConfig,writeSheet);注意:模板中需要设置变量,例如:{{.}}表示整行填充,{{属性名}}表示具体属性。4.关闭流:excelWriter.finish();注意:模板文件中的多级表头已经存在,我们只需要在实体类中定义好与表头对应的关系,然后填充数据即可。填充的数据可以是实体类对象的列表,也可以使用Map。但是,如果我们要在已有的模板文件(第一个Sheet)中填充,那么模板文件中的表头位置是固定的,我们只需要在数据区域(表头下面的行)填充数据。例如,模板文件第一个Sheet中:第1行:一级表头1,一级表头2第2行:二级表头1-1,二级表头2-1第3行:留空(用于填充数据)那么我们在填充时,需要从第3行开始填充。在模板中,我们可以在第3行的单元格里写上变量,例如:A3:{{field1}}B3:{{field2}}然后,我们填充一个List<MyData>,每个MyData对象有field1和field2属性。或者,我们可以使用水平填充(横向填充)的方式,但通常我们使用垂直填充(纵向填充,即向下填充多行)。具体代码示例:假设模板文件路径:templatePath,输出文件路径:outputPath。1.定义数据类:public classMyData{@ExcelProperty({"一级表头1", "二级表头1-1"})privateString field1;@ExcelProperty({"一级表头2","二级表头2-1"})private Stringfield2;// gettersand setters}2.准备数据列表:List<MyData> dataList =...;3.执行填充:try(InputStreamtemplate =new FileInputStream(templatePath);OutputStreamoutput =new FileOutputStream(outputPath)){ExcelWriterexcelWriter= EasyExcel.write(output).withTemplate(template).build();WriteSheetwriteSheet= EasyExcel.writerSheet(0).build(); //第一个sheet//填充数据,使用FillWrapper包装列表,并指定列表名称(模板中对应{{.}}或指定名称)//注意:如果模板中变量是{{field1}},则不需要使用FillWrapper,直接填充对象即可。但这里我们填充列表,所以模板中需要设置好变量,并且指定行。//模板中第3行(数据开始行)的每个单元格有变量,如{{field1}}, {{field2}},然后我们填充一个列表,每行对应一个对象。//方式1:使用对象列表填充,模板中变量按照属性名匹配excelWriter.fill(dataList,fillConfig, writeSheet);//方式2:如果模板中变量是{{.field1}},则可以使用FillWrapper,并指定列表名称为"data"(或其他),然后模板中变量为{{data.field1}}。但这里我们直接使用属性名。//注意:默认情况下,填充列表会从模板中设置变量的行开始向下填充多行。excelWriter.finish();}但是,如果模板中已经有多级表头,并且数据区域是空的,那么我们在模板中需要将数据区域的单元格设置为变量。例如,在第三行的第一个单元格写{{field1}},第二个单元格写{{field2}}。另外,如果表头有多级,我们可能需要在模板中合并单元格,但这是模板设计时的事情,EasyExcel填充时不会改变表头。总结步骤:1.设计模板:在第一个Sheet中设计好多级表头(合并单元格等),并在表头下方预留一行(或多行)作为数据行,在数据行的单元格中写入变量(如{{field1}})。2.定义数据类:使用@ExcelProperty注解,注解值是一个字符串数组,对应多级表头的每一级。3.读取模板,创建ExcelWriter。4.填充数据(单个对象或列表)。5.关闭ExcelWriter。注意:如果模板中变量所在行下面还有行(比如合计行),那么填充列表时可能会覆盖下面的行。为了避免这种情况,我们可以在模板中把数据区域设置为一个单独的表格,或者使用插入行的方式(但EasyExcel的填充功能默认是覆盖,不会插入行)。因此,模板中数据区域下面不要有内容,或者使用换行填充(FillConfig.forceNewRow(true))并确保数据区域下面有足够的空间。如果希望动态插入行,可以使用ListFill模式,并设置换行(forceNewRow=true),这样当数据行数超过模板中预留的行数时,会自动向下插入行。问题:如何避免覆盖模板中数据区域以下的内容?答案:在模板中,将数据区域以下的内容放在数据区域之后足够远的地方(比如数据区域预留100行,那么合计行放在第104行),这样即使填充100条数据也不会覆盖。或者,我们可以通过计算数据量来动态调整模板,但这比较复杂。因此,通常的做法是:模板中数据区域只保留一行(带变量),然后使用换行填充(forceNewRow=true),这样填充时会自动向下复制样式并填充数据,不会覆盖下面的行(只要下面没有内容)。如果模板中数据区域下面有内容(比如合计行),那么我们需要预留足够的空行(比如在数据行和合计行之间留100行空行,然后设置forceNewRow=true,这样填充时会在空行上填充,而不会覆盖合计行)。另一种做法:使用追加模式,但EasyExcel的填充功能不支持在已有数据的末尾追加,它只能覆盖变量行和向下扩展(复制样式)。所以,我们可以在模板中把数据区域下面的内容放在很远的行(比如第1000行),然后数据区域从第3行开始,中间都是空行,这样填充数据时就会在空行上填充。参考代码:假设模板文件第一个Sheet中:第1-2行:多级表头第3行:数据行(变量行),如A3:{{field1}},B3:{{field2}}第4行及以下:空行(直到第100行)第101行:合计行这样,填充100条数据时,会从第3行开始填充,然后向下填充到第102行(但不会覆盖第101行,因为填充是从第3行开始,向下填充100行,到第102行,而合计行在第101行,所以不会覆盖)。但是,如果数据超过98条(因为模板中第3行到第100行只有98行空行),那么第99条数据会覆盖第101行的合计行。因此,我们需要确保预留的空行足够多,或者动态调整模板(这比较困难)。因此,更安全的做法是:将合计行放在另一个Sheet,或者使用程序在填充完数据后再写入合计行(但这样需要再次操作Excel,比较麻烦)。所以,如果数据量不大,预留足够空行即可。如果数据量很大且不可预知,建议使用其他方式生成合计行(比如填充完数据后,再在内存中计算并写入合计行)。现在,我们给出一个完整的示例代码:1.模板文件:template.xlsxSheet1:A1:一级表头1(合并A1:B1)C1:一级表头2(合并C1:D1)...A2:二级表头1-1B2:二级表头1-2C2:二级表头2-1D2:二级表头2-2A3: {{field1}}B3: {{field2}}C3: {{field3}}D3: {{field4}}2.数据类:publicclass MultiLevelHeaderData {@ExcelProperty({"一级表头1","二级表头1-1"})private Stringfield1;@ExcelProperty({"一级表头1", "二级表头1-2"})privateString field2;@ExcelProperty({"一级表头2","二级表头2-1"})private Stringfield3;@ExcelProperty({"一级表头2", "二级表头2-2"})privateString field4;//gettersand setters}3.填充代码:StringtemplatePath ="template.xlsx";String outputPath ="output.xlsx";List<MultiLevelHeaderData> dataList =getDataList(); //获取数据try(InputStreamtemplate =new FileInputStream(templatePath);OutputStreamoutput =new FileOutputStream(outputPath)){ExcelWriterexcelWriter= EasyExcel.write(output).withTemplate(template).build();WriteSheetwriteSheet= EasyExcel.writerSheet(0).build();FillConfig fillConfig =FillConfig.builder().forceNewRow(true).build();//设置换行填充//填充列表excelWriter.fill(dataList,fillConfig, writeSheet);excelWriter.finish();}这样,数据就会填充到模板的第一个Sheet中,并且保留多级表头。注意:如果模板中变量不是使用属性名,而是使用其他名称,那么我们可以使用@ExcelProperty的value值来匹配,但通常我们直接使用属性名作为变量名。另外,如果变量名不匹配,则填充失败(不会报错,但单元格为空)。因此,确保模板中的变量名与数据类的属性名一致(或者使用Map的key)。如果使用Map填充,则变量名就是Map的key。例如:Map<String,Object>data =new HashMap<>();data.put("field1","值1");data.put("field2", "值2");//然后填充单个Map(一行):excelWriter.fill(data, writeSheet);但是,填充多行数据时,我们需要使用一个List<Map>,然后使用FillWrapper:List<Map<String,Object>>list =...;excelWriter.fill(newFillWrapper("data", list), fillConfig,writeSheet);此时,模板中的变量应该是{{data.field1}},{{data.field2}}等。注意,FillWrapper的第一个参数是列表的名称,在模板中需要加上这个名称作为前缀。因此,我们通常更推荐使用对象列表填充,因为更简单。最后,如果模板中变量行下面有需要保留的内容(比如公式),那么我们可以使用上面的预留空行方法,或者使用其他方式(如先填充,再通过读取输出文件来添加合计行,但这会增加复杂度)。以上就是使用EasyExcel在指定模板文件的第一个Sheet中设置多级表头并填充数据的方法。相关问题:1.如何在EasyExcel中处理合并单元格的多级表头?2.填充数据时如何避免覆盖模板中的固定内容(如合计行)?3.如何使用Map来填充EasyExcel模板?4.EasyExcel填充数据时如何动态插入行而不覆盖已有内容?5.如何为EasyExcel模板设置多个数据区域?</think>### 使用EasyExcel设置多级表头并填充数据
#### 实现步骤
1. **准备模板文件**
创建Excel模板文件(如`template.xlsx`),在第一个Sheet中预留数据填充区域(保留表头,删除示例数据行)。
2. **定义数据模型**
使用`@ExcelProperty`注解绑定多级表头:
```java
public class MultiHeaderData {
// 一级表头"部门", 二级表头"名称"
@ExcelProperty({"部门", "名称"})
private String deptName;
// 一级表头"部门", 二级表头"ID"
@ExcelProperty({"部门", "ID"})
private String deptId;
// 一级表头"业绩", 二级表头"Q1"
@ExcelProperty({"业绩", "Q1"})
private BigDecimal q1Revenue;
// 一级表头"业绩", 二级表头"Q2"
@ExcelProperty({"业绩", "Q2"})
private BigDecimal q2Revenue;
// getters & setters
}
```
3. **填充数据到模板**
```java
public void fillTemplate(String templatePath, String outputPath) {
// 1. 数据准备
List<MultiHeaderData> dataList = Arrays.asList(
new MultiHeaderData("研发部", "D001", new BigDecimal("1200.50"), new BigDecimal("1500.75")),
new MultiHeaderData("市场部", "D002", new BigDecimal("890.25"), new BigDecimal("1300.40"))
);
// 2. 执行填充
try (ExcelWriter excelWriter = EasyExcel.write(outputPath)
.withTemplate(templatePath)
.build()) {
WriteSheet writeSheet = EasyExcel.writerSheet(0).build(); // 操作第一个Sheet
FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
// 填充列表数据(自动匹配表头)
excelWriter.fill(dataList, fillConfig, writeSheet);
}
}
```
#### 关键说明
1. **表头绑定规则**
- `@ExcelProperty`的数组参数对应表头层级:
`{"一级标题", "二级标题", ...}`
- 数组长度必须与模板中的表头层级完全一致
2. **模板设计要点**
- 模板中需**预先合并单元格**(如合并`A1:B1`作为"部门")
- 预留数据行:在表头下方留空行用于填充数据
- 示例模板结构:
```
| A1:部门(合并A1:B1) | C1:业绩(合并C1:D1) |
| A2:名称 | B2:ID | C2:Q1 | D2:Q2 |
| A3: | B3: | C3: | D3: | <-- 数据从这里开始填充
```
3. **动态表头场景**
若表头需要动态生成,使用`List<List<String>>`构建表头:
```java
List<List<String>> head = Arrays.asList(
Arrays.asList("部门", "名称"),
Arrays.asList("部门", "ID"),
Arrays.asList("业绩", "Q1"),
Arrays.asList("业绩", "Q2")
);
EasyExcel.write(fileName)
.head(head)
.sheet()
.doWrite(dataList);
```
#### 常见问题解决
1. **表头错位问题**
- 确保模板中的合并单元格范围与注解层级匹配
- 使用`@ContentStyle`自定义表头样式
2. **填充性能优化**
- 大数据量时启用分片写入:
```java
FillConfig fillConfig = FillConfig.builder()
.bufferSize(1000) // 设置批处理大小
.build();
```
3. **保留模板样式**
- 使用`.withTemplate()`时会自动继承模板的样式和格式
- 复杂样式建议在模板中预定义,避免代码设置
> 完整示例代码参考:[EasyExcel官方文档-填充示例](https://www.yuque.com/easyexcel/doc/fill)[^1]
---
### 相关问题
1. **EasyExcel如何处理动态变化的表头层级?**
2. **填充数据时如何跳过某些预留行?**
3. **如何向同一个Sheet的多个区域填充不同数据集?**
4. **EasyExcel与POI的性能对比有何差异?**
5. **如何导出时自动调整多级表头的列宽?**
阅读全文
相关推荐


















