0%

EasyExcel多层表头

EasyExcel实现多层表头:注解与列表两种方式详解

在复杂报表场景中,多层表头(如 “基础信息” 包含 “姓名”“手机号” 等子列)能更清晰地组织数据。EasyExcel 提供了简洁的 API 支持多层表头,本文将详细讲解两种实现方式(注解方式和列表方式),并对比其适用场景,帮助你快速实现类似 Excel 数据透视表的表头结构。

多层表头的核心原理

多层表头本质是多级列标题的合并与嵌套,例如 “基础信息” 作为一级标题,其下包含 “姓名”“手机号” 等二级标题。EasyExcel 通过以下方式实现:

  • 层级定义:用数组或列表的嵌套结构表示表头层级(如 {"基础信息", "姓名"} 表示两级表头);
  • 自动合并:相同的上级标题会自动合并单元格(如 “基础信息” 会跨列合并其所有子列)。

环境准备

引入 EasyExcel 依赖(兼容 2.x 和 3.x 版本):

1
2
3
4
5
<dependency>  
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.3.0</version>
</dependency>

实现方式详解

注解方式(推荐用于固定表头)

通过 @ExcelProperty 注解的 value 属性定义多层表头,适用于表头结构固定的场景(如实体类与表头一一对应)。

定义实体类

在实体类的字段上使用 @ExcelProperty(value = {一级标题, 二级标题, ...}) 定义多层表头:

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
import com.alibaba.excel.annotation.ExcelProperty;  
import lombok.Data;

@Data
public class UserInfo {
// 二级表头:基础信息 -> 姓名
@ExcelProperty(value = {"基础信息", "姓名"}, index = 0)
private String name;

// 二级表头:基础信息 -> 手机号
@ExcelProperty(value = {"基础信息", "手机号"}, index = 1)
private String phone;

// 二级表头:基础信息 -> 年龄
@ExcelProperty(value = {"基础信息", "年龄"}, index = 2)
private Integer age;

// 二级表头:其他信息 -> 教育经历
@ExcelProperty(value = {"其他信息", "教育经历"}, index = 3)
private String education;

// 二级表头:其他信息 -> 工作经历
@ExcelProperty(value = {"其他信息", "工作经历"}, index = 4)
private String workExperience;
}
  • value 属性:数组元素依次表示从一级到 N 级的表头名称;
  • index 属性:指定列的顺序(0 开始),确保表头按预期排列。
生成 Excel

直接将实体类作为表头类传入 EasyExcel.write() 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.alibaba.excel.EasyExcel;  
import java.util.ArrayList;
import java.util.List;

public class MultiLevelHeaderDemo {
public static void main(String[] args) {
String filePath = "多层表头_注解方式.xlsx";

// 准备测试数据(可选,此处为空列表仅生成表头)
List<UserInfo> dataList = new ArrayList<>();
// dataList.add(new UserInfo("张三", "13800138000", 25, "本科", "3年"));

// 写入 Excel,表头由 UserInfo 类的 @ExcelProperty 定义
EasyExcel.write(filePath, UserInfo.class)
.sheet("用户信息表") // Sheet 名称
.doWrite(dataList); // 写入数据(空列表则仅生成表头)

System.out.println("文件生成成功:" + filePath);
}
}

列表方式(推荐用于动态表头)

通过 List<List<String>> 手动定义表头层级,适用于表头结构动态生成的场景(如根据数据库配置动态调整表头)。

构建表头列表

外层 List 代表列的集合,内层 List 代表每列的多级表头:

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import com.alibaba.excel.EasyExcel;  
import java.util.ArrayList;
import java.util.List;

public class DynamicHeaderDemo {
public static void main(String[] args) {
String filePath = "多层表头_列表方式.xlsx";

// 1. 构建多层表头(List<List<String>>)
List<List<String>> headers = new ArrayList<>();

// 第一列:基础信息 -> 姓名
List<String> col1 = new ArrayList<>();
col1.add("基础信息");
col1.add("姓名");
headers.add(col1);

// 第二列:基础信息 -> 手机号
List<String> col2 = new ArrayList<>();
col2.add("基础信息");
col2.add("手机号");
headers.add(col2);

// 第三列:基础信息 -> 年龄
List<String> col3 = new ArrayList<>();
col3.add("基础信息");
col3.add("年龄");
headers.add(col3);

// 第四列:其他信息 -> 教育经历
List<String> col4 = new ArrayList<>();
col4.add("其他信息");
col4.add("教育经历");
headers.add(col4);

// 第五列:其他信息 -> 工作经历
List<String> col5 = new ArrayList<>();
col5.add("其他信息");
col5.add("工作经历");
headers.add(col5);

// 2. 准备数据(数据结构需与表头列顺序对应)
List<List<Object>> dataList = new ArrayList<>();
// 示例数据行:[姓名, 手机号, 年龄, 教育经历, 工作经历]
List<Object> dataRow = new ArrayList<>();
dataRow.add("张三");
dataRow.add("13800138000");
dataRow.add(25);
dataRow.add("本科");
dataRow.add("3年");
dataList.add(dataRow);

// 3. 写入 Excel,表头由 headers 定义
EasyExcel.write(filePath)
.head(headers) // 设置动态表头
.sheet("用户信息表") // Sheet 名称
.doWrite(dataList); // 写入数据

System.out.println("文件生成成功:" + filePath);
}
}
  • 数据结构List<List<Object>> 中,内层 List 的元素顺序需与表头列顺序一致;
  • 灵活性:可根据业务需求动态增删表头列(如从数据库查询表头配置后构建 headers 列表)。

扩展:三级及以上表头

EasyExcel 支持任意层级的表头,只需在注解数组或列表中增加层级即可。

示例:三级表头

注解方式
1
2
3
4
5
6
7
8
9
10
@Data  
public class OrderInfo {
// 三级表头:订单信息 -> 基本信息 -> 订单号
@ExcelProperty(value = {"订单信息", "基本信息", "订单号"}, index = 0)
private String orderNo;

// 三级表头:订单信息 -> 金额信息 -> 总金额
@ExcelProperty(value = {"订单信息", "金额信息", "总金额"}, index = 1)
private BigDecimal totalAmount;
}
列表方式
1
2
3
4
5
6
7
8
List<List<String>> headers = new ArrayList<>();  
// 三级表头:订单信息 -> 基本信息 -> 订单号
List<String> col1 = new ArrayList<>();
col1.add("订单信息");
col1.add("基本信息");
col1.add("订单号");
headers.add(col1);
// ... 其他列

两种方式的对比与适用场景

实现方式 优点 缺点 适用场景
注解方式 代码简洁,与实体类绑定,可读性强 表头固定,无法动态修改 表头结构固定的报表(如固定模板)
列表方式 支持动态生成表头,灵活性高 代码较繁琐,需手动维护列顺序 表头动态变化的场景(如配置化报表)

常见问题与解决方案

1. 表头合并异常(上级标题未跨列合并)

  • 原因:同级表头的上级标题名称不一致(如 “基础信息” 与 “基础信息 ”(含空格)被视为不同标题);
  • 解决:确保同一组的上级标题字符串完全一致(无空格、大小写差异)。

2. 数据与表头列顺序不匹配

  • 原因:注解方式中 index 属性未按顺序设置,或列表方式中数据行元素顺序与表头列顺序不一致;
  • 解决
    • 注解方式:严格按列顺序设置 index = 0, 1, 2...
    • 列表方式:数据行 List<Object> 的元素顺序必须与 headers 列表的列顺序一一对应。

3. 表头层级显示错乱

  • 原因:表头层级深度不一致(如部分列是二级,部分列是三级);
  • 解决:确保所有列的表头层级深度统一,或接受不同层级的显示效果(EasyExcel 会自动对齐空白单元格)。

欢迎关注我的其它发布渠道

表情 | 预览
Powered By Valine
v1.3.10