基于EasyExcel实现一对多以及多层嵌套结构数据的导出
时间: 2025-06-02 16:32:37 浏览: 34
<think>嗯,用户之前已经问过关于EasyExcel的@ExcelCollection注解的使用,现在他们想进一步了解如何基于EasyExcel实现一对多和多层嵌套结构的数据导出。我需要确保回答详细且覆盖所有相关方面。
首先,用户可能已经知道@ExcelCollection的基本用法,但需要更深入的指导。我应该从基础开始,逐步深入,包括定义实体类、导出示例、多层嵌套的处理以及常见问题。
可能用户在实际项目中遇到了复杂的数据结构,比如订单和商品,或者部门、员工和项目这样的多层嵌套。需要提供具体的代码示例,这样用户可以直接参考。
需要注意版本兼容性,用户之前提到的是3.3.2版本,但可能需要确认当前EasyExcel的最新版本是否有变化,不过用户可能还在使用旧版本,所以保持示例在3.3.2有效。
另外,用户可能需要了解如何处理导出时的格式,比如合并表头、动态列,或者如何处理大量数据时的性能优化。此外,导入时的监听器设置也很重要,可能需要详细说明。
还要考虑用户可能遇到的问题,比如数据错位、集合为空或者性能问题,给出相应的解决建议。比如检查注解的order属性,确保表头匹配,使用分片读取等。
最后,确保回答结构清晰,分步骤说明,并给出注意事项和常见问题,帮助用户避免常见陷阱。同时,提醒用户如果需要更高级的功能,可以结合自定义处理器,比如动态表头或样式调整。</think>以下是基于 EasyExcel 实现 **一对多** 和 **多层嵌套结构数据导出** 的详细方法及示例,涵盖复杂数据场景的处理(如订单包含多个商品,商品又包含多个标签等)。
---
### **1. 数据结构定义**
假设需要导出以下嵌套结构的数据:
- **订单(Order)**:包含订单基础信息、商品列表(一对多)
- **商品(Item)**:包含商品信息、标签列表(一对多)
- **标签(Tag)**:标签名称和类型
---
### **2. 实体类注解配置**
#### **(1) 订单类(Order)**
```java
public class Order {
@ExcelProperty("订单号")
private String orderNo;
@ExcelProperty("创建时间")
private Date createTime;
// 一对多:订单 -> 商品列表
@ExcelCollection(name = "商品信息") // name 对应 Excel 中的分组表头
private List<Item> items;
}
```
#### **(2) 商品类(Item)**
```java
public class Item {
@ExcelProperty("商品名称")
private String name;
@ExcelProperty("单价")
private BigDecimal price;
// 多层嵌套:商品 -> 标签列表
@ExcelCollection(name = "标签信息")
private List<Tag> tags;
}
```
#### **(3) 标签类(Tag)**
```java
public class Tag {
@ExcelProperty("标签名称")
private String tagName;
@ExcelProperty("标签类型")
private String tagType;
}
```
---
### **3. 导出代码实现**
#### **(1) 准备测试数据**
```java
List<Order> orders = new ArrayList<>();
// 订单1
Order order1 = new Order();
order1.setOrderNo("NO_001");
order1.setCreateTime(new Date());
List<Item> items1 = new ArrayList<>();
items1.add(new Item("苹果", new BigDecimal("10.5"),
Arrays.asList(new Tag("水果", "分类"), new Tag("特价", "促销"))));
items1.add(new Item("手机", new BigDecimal("5000.0"),
Arrays.asList(new Tag("电子产品", "分类"), new Tag("新品", "状态"))));
order1.setItems(items1);
// 订单2(省略类似结构)
orders.add(order1);
orders.add(order2); // 假设 order2 已定义
```
#### **(2) 导出到 Excel**
```java
String fileName = "复杂订单.xlsx";
EasyExcel.write(fileName)
.head(Order.class) // 指定导出的模板类
.sheet("订单详情")
.doWrite(orders); // 直接写入订单列表
```
---
### **4. 导出效果说明**
生成的 Excel 结构如下(合并表头示意):
| 订单号 | 创建时间 | 商品名称 | 单价 | 标签名称 | 标签类型 | 标签名称 | 标签类型 |
|--------|----------|----------|------|----------|----------|----------|----------|
| NO_001 | 2023-01-01 | 苹果 | 10.5 | 水果 | 分类 | 特价 | 促销 |
| | | 手机 | 5000 | 电子产品 | 分类 | 新品 | 状态 |
**特点**:
- **自动合并父级字段**:订单号、创建时间在商品行重复时自动留空。
- **层级展开**:商品和标签的集合数据按行展开。
---
### **5. 关键配置技巧**
#### **(1) 控制列顺序**
通过 `@ExcelProperty(index = N)` 或 `@ExcelCollection(order = N)` 指定列位置:
```java
public class Item {
@ExcelProperty(value = "商品名称", index = 2) // 列位置从0开始
private String name;
@ExcelCollection(name = "标签信息", order = 3) // 集合整体位置
private List<Tag> tags;
}
```
#### **(2) 动态表头(复杂场景)**
若嵌套层级动态变化(如不确定嵌套层数),需自定义 `WriteHandler`:
```java
EasyExcel.write(fileName, Order.class)
.registerWriteHandler(new CellWriteHandler() {
@Override
public void afterCellDispose(WriteSheetHolder sheetHolder, WriteTableHolder tableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
// 动态调整表头合并逻辑
if (isHead && head.getFieldName().equals("tags")) {
// 自定义合并策略
}
}
})
.sheet().doWrite(orders);
```
---
### **6. 导入嵌套数据**
导入时需使用 **监听器** 处理嵌套集合:
```java
public class OrderListener extends AnalysisEventListener<Order> {
private Order currentOrder;
@Override
public void invoke(Order order, AnalysisContext context) {
// 每次读取到一个 Order 对象(自动映射嵌套数据)
this.currentOrder = order;
// 保存到数据库或其他处理
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {}
}
// 读取 Excel
EasyExcel.read("复杂订单.xlsx", Order.class, new OrderListener())
.sheet()
.doRead();
```
---
### **7. 注意事项**
1. **表头一致性**:导出和导入的表头名称必须与 `@ExcelProperty` 和 `@ExcelCollection` 的 `name` 严格匹配。
2. **性能优化**:
- 大数据量导出时启用 `web` 模式(分片写入):`.web(true)`。
- 避免深度嵌套导致内存溢出,建议单层集合不超过 10 万行。
3. **空值处理**:通过 `@ExcelIgnore` 忽略字段,或 `@ExcelProperty(defaultValue = "N/A")` 设置默认值。
4. **样式自定义**:通过 `RegisterHandler` 调整单元格合并、颜色等样式。
---
### **8. 常见问题解决**
- **Q1: 导出时嵌套集合的列重复出现?**
**A**: 检查 `@ExcelCollection` 的 `name` 是否唯一,或通过 `index` 强制指定列位置。
- **Q2: 导入时嵌套集合数据丢失?**
**A**: 确保 Excel 中嵌套数据的表头层级与实体类一致,且监听器正确解析对象关联。
- **Q3: 如何导出树形结构(如部门-员工-任务)?**
**A**: 使用多级 `@ExcelCollection` 注解,并确保每层实体类定义正确。
---
通过上述方法,可以高效处理 Excel 中一对多和多层嵌套数据的导出与导入,适用于复杂业务报表、数据迁移等场景。
阅读全文
相关推荐

















