EasyExcel动态表头基础用法及最佳实践详解

 更新时间:2026年03月12日 10:21:10   作者:Zhu_S W  
EasyExcel是阿里巴巴开源的一个基于Java的简单、省内存的读写Excel工具,在处理大量数据时,它能极大地减少内存占用提高性能,这篇文章主要介绍了EasyExcel动态表头基础用法及最佳实践的相关资料,需要的朋友可以参考下

什么是动态表头?

动态表头是指在运行时根据业务需求动态生成Excel表格的列标题,而不是在代码中预先定义固定的表头结构。这在以下场景中非常有用:

  • 根据用户选择的字段生成不同的报表

  • 处理数据库中动态字段的导出

  • 生成多级复杂表头

  • 实现可配置的数据导出功能

基础用法

1. 简单动态表头

public class DynamicHeaderExample {
    
    public void writeWithDynamicHeader() {
        String fileName = "dynamic_header.xlsx";
        
        // 动态构建表头
        List<List<String>> head = new ArrayList<>();
        head.add(Arrays.asList("姓名"));
        head.add(Arrays.asList("年龄"));
        head.add(Arrays.asList("邮箱"));
        head.add(Arrays.asList("部门"));
        
        // 准备数据
        List<List<Object>> dataList = new ArrayList<>();
        dataList.add(Arrays.asList("张三", 25, "zhangsan@example.com", "技术部"));
        dataList.add(Arrays.asList("李四", 30, "lisi@example.com", "产品部"));
        dataList.add(Arrays.asList("王五", 28, "wangwu@example.com", "设计部"));
        
        // 写入Excel
        EasyExcel.write(fileName)
                .head(head)
                .sheet("员工信息")
                .doWrite(dataList);
    }
}

2. 多级表头

public void writeWithMultiLevelHeader() {
    String fileName = "multi_level_header.xlsx";
    
    // 构建多级表头
    List<List<String>> head = new ArrayList<>();
    // 第一列:基本信息->个人信息->姓名
    head.add(Arrays.asList("基本信息", "个人信息", "姓名"));
    // 第二列:基本信息->个人信息->年龄
    head.add(Arrays.asList("基本信息", "个人信息", "年龄"));
    // 第三列:基本信息->联系方式->邮箱
    head.add(Arrays.asList("基本信息", "联系方式", "邮箱"));
    // 第四列:基本信息->联系方式->电话
    head.add(Arrays.asList("基本信息", "联系方式", "电话"));
    // 第五列:工作信息->部门
    head.add(Arrays.asList("工作信息", "部门"));
    // 第六列:工作信息->职位
    head.add(Arrays.asList("工作信息", "职位"));
    
    // 准备数据
    List<List<Object>> dataList = new ArrayList<>();
    dataList.add(Arrays.asList("张三", 25, "zhangsan@example.com", "13800138000", "技术部", "Java工程师"));
    dataList.add(Arrays.asList("李四", 30, "lisi@example.com", "13900139000", "产品部", "产品经理"));
    
    EasyExcel.write(fileName)
            .head(head)
            .sheet("员工详细信息")
            .doWrite(dataList);
}

高级应用

1. 根据数据库字段动态生成表头

@Service
public class DynamicExportService {
    
    @Autowired
    private FieldConfigService fieldConfigService;
    
    public void exportUserData(List<String> selectedFields) {
        String fileName = "user_export_" + System.currentTimeMillis() + ".xlsx";
        
        // 根据选中字段构建表头
        List<List<String>> head = buildDynamicHeader(selectedFields);
        
        // 获取数据
        List<List<Object>> dataList = buildDataList(selectedFields);
        
        EasyExcel.write(fileName)
                .head(head)
                .sheet("用户数据")
                .doWrite(dataList);
    }
    
    private List<List<String>> buildDynamicHeader(List<String> selectedFields) {
        List<List<String>> head = new ArrayList<>();
        
        for (String fieldCode : selectedFields) {
            FieldConfig config = fieldConfigService.getByCode(fieldCode);
            if (config != null) {
                // 支持分组表头
                if (config.getGroupName() != null) {
                    head.add(Arrays.asList(config.getGroupName(), config.getFieldName()));
                } else {
                    head.add(Arrays.asList(config.getFieldName()));
                }
            }
        }
        
        return head;
    }
    
    private List<List<Object>> buildDataList(List<String> selectedFields) {
        List<User> users = userService.getAllUsers();
        List<List<Object>> dataList = new ArrayList<>();
        
        for (User user : users) {
            List<Object> row = new ArrayList<>();
            for (String fieldCode : selectedFields) {
                Object value = getFieldValue(user, fieldCode);
                row.add(value);
            }
            dataList.add(row);
        }
        
        return dataList;
    }
    
    private Object getFieldValue(User user, String fieldCode) {
        // 使用反射或Map方式获取字段值
        switch (fieldCode) {
            case "name": return user.getName();
            case "age": return user.getAge();
            case "email": return user.getEmail();
            case "department": return user.getDepartment();
            case "createTime": return user.getCreateTime();
            default: return "";
        }
    }
}
​
// 字段配置实体
@Data
public class FieldConfig {
    private String fieldCode;
    private String fieldName;
    private String groupName;
    private Integer sortOrder;
}

2. 配置化动态表头

@Component
public class ConfigurableDynamicHeader {
    
    public void exportWithConfig(ExportConfig config) {
        String fileName = config.getFileName() + ".xlsx";
        
        // 根据配置构建表头
        List<List<String>> head = buildHeaderFromConfig(config);
        
        // 根据配置获取数据
        List<List<Object>> dataList = buildDataFromConfig(config);
        
        // 应用样式
        HorizontalCellStyleStrategy styleStrategy = buildStyleFromConfig(config);
        
        EasyExcel.write(fileName)
                .head(head)
                .registerWriteHandler(styleStrategy)
                .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                .sheet(config.getSheetName())
                .doWrite(dataList);
    }
    
    private List<List<String>> buildHeaderFromConfig(ExportConfig config) {
        List<List<String>> head = new ArrayList<>();
        
        for (HeaderConfig headerConfig : config.getHeaders()) {
            List<String> headerPath = new ArrayList<>();
            
            // 支持多级表头
            if (headerConfig.getLevel1() != null) {
                headerPath.add(headerConfig.getLevel1());
            }
            if (headerConfig.getLevel2() != null) {
                headerPath.add(headerConfig.getLevel2());
            }
            if (headerConfig.getLevel3() != null) {
                headerPath.add(headerConfig.getLevel3());
            }
            
            head.add(headerPath);
        }
        
        return head;
    }
}
​
// 导出配置类
@Data
public class ExportConfig {
    private String fileName;
    private String sheetName;
    private List<HeaderConfig> headers;
    private StyleConfig styleConfig;
}
​
@Data
public class HeaderConfig {
    private String fieldCode;
    private String level1;
    private String level2;
    private String level3;
    private Integer width;
}

3. 动态表头与数据验证结合

public class DynamicHeaderWithValidation {
    
    public void writeWithValidation() {
        String fileName = "validated_dynamic.xlsx";
        
        // 构建表头
        List<List<String>> head = Arrays.asList(
            Arrays.asList("姓名"),
            Arrays.asList("年龄"),
            Arrays.asList("邮箱"),
            Arrays.asList("手机号")
        );
        
        // 准备数据
        List<List<Object>> dataList = new ArrayList<>();
        dataList.add(Arrays.asList("张三", 25, "zhangsan@example.com", "13800138000"));
        dataList.add(Arrays.asList("李四", 30, "lisi@example.com", "13900139000"));
        
        // 创建下拉选择处理器
        DropDownWriteHandler dropDownHandler = new DropDownWriteHandler();
        
        EasyExcel.write(fileName)
                .head(head)
                .registerWriteHandler(dropDownHandler)
                .sheet("带验证的数据")
                .doWrite(dataList);
    }
}
​
// 自定义下拉选择处理器
public class DropDownWriteHandler implements SheetWriteHandler {
    
    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, 
                                WriteSheetHolder writeSheetHolder) {
        
        Sheet sheet = writeSheetHolder.getSheet();
        Workbook workbook = writeWorkbookHolder.getWorkbook();
        
        // 创建数据验证规则
        DataValidationHelper validationHelper = sheet.getDataValidationHelper();
        
        // 为年龄列添加数字验证(假设年龄在B列)
        CellRangeAddressList ageRange = new CellRangeAddressList(1, 1000, 1, 1);
        DataValidationConstraint ageConstraint = validationHelper
            .createIntegerConstraint(DataValidationConstraint.OperatorType.BETWEEN, "0", "150");
        DataValidation ageValidation = validationHelper.createValidation(ageConstraint, ageRange);
        ageValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
        ageValidation.createErrorBox("年龄错误", "年龄必须在0-150之间");
        sheet.addValidationData(ageValidation);
    }
}

实际应用场景

1. 报表系统中的可配置导出

@RestController
@RequestMapping("/api/export")
public class ExportController {
    
    @Autowired
    private DynamicExportService exportService;
    
    @PostMapping("/users")
    public ResponseEntity<String> exportUsers(@RequestBody ExportRequest request) {
        try {
            String fileName = exportService.exportUserData(
                request.getSelectedFields(),
                request.getStartDate(),
                request.getEndDate()
            );
            
            return ResponseEntity.ok(fileName);
        } catch (Exception e) {
            return ResponseEntity.badRequest().body("导出失败:" + e.getMessage());
        }
    }
}
​
@Data
public class ExportRequest {
    private List<String> selectedFields;
    private LocalDate startDate;
    private LocalDate endDate;
    private String groupBy;
}

2. 动态报表生成

public class DynamicReportGenerator {
    
    public void generateReport(ReportTemplate template, Map<String, Object> params) {
        String fileName = template.getName() + "_" + 
                         LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + 
                         ".xlsx";
        
        // 根据模板构建表头
        List<List<String>> head = buildHeaderFromTemplate(template);
        
        // 根据参数查询数据
        List<List<Object>> dataList = queryDataByTemplate(template, params);
        
        // 应用模板样式
        List<WriteHandler> handlers = buildWriteHandlers(template);
        
        ExcelWriterBuilder builder = EasyExcel.write(fileName).head(head);
        
        // 注册所有处理器
        for (WriteHandler handler : handlers) {
            builder.registerWriteHandler(handler);
        }
        
        builder.sheet(template.getSheetName()).doWrite(dataList);
    }
}

最佳实践

1. 性能优化

public class OptimizedDynamicExport {
    
    public void exportLargeData(List<String> fields) {
        String fileName = "large_data_export.xlsx";
        
        // 构建表头
        List<List<String>> head = buildHeader(fields);
        
        // 使用ExcelWriter进行流式写入
        try (ExcelWriter excelWriter = EasyExcel.write(fileName).head(head).build()) {
            WriteSheet writeSheet = EasyExcel.writerSheet("数据").build();
            
            // 分批处理大量数据
            int pageSize = 10000;
            int pageNum = 1;
            List<List<Object>> batchData;
            
            do {
                batchData = queryDataByPage(fields, pageNum, pageSize);
                if (!batchData.isEmpty()) {
                    excelWriter.write(batchData, writeSheet);
                }
                pageNum++;
            } while (batchData.size() == pageSize);
        }
    }
}

2. 错误处理

public class SafeDynamicExport {
    
    public void safeExport(List<String> fields) {
        try {
            validateFields(fields);
            
            List<List<String>> head = buildHeader(fields);
            List<List<Object>> dataList = buildData(fields);
            
            EasyExcel.write("safe_export.xlsx")
                    .head(head)
                    .sheet("数据")
                    .doWrite(dataList);
                    
        } catch (IllegalArgumentException e) {
            log.error("字段验证失败:{}", e.getMessage());
            throw new BusinessException("导出字段配置错误");
        } catch (Exception e) {
            log.error("导出过程中发生错误:", e);
            throw new BusinessException("数据导出失败");
        }
    }
    
    private void validateFields(List<String> fields) {
        if (fields == null || fields.isEmpty()) {
            throw new IllegalArgumentException("导出字段不能为空");
        }
        
        List<String> validFields = getValidFields();
        for (String field : fields) {
            if (!validFields.contains(field)) {
                throw new IllegalArgumentException("无效的字段:" + field);
            }
        }
    }
}

总结

EasyExcel的动态表头功能非常强大,主要优势包括:

  • 灵活性强:可根据运行时条件动态生成表头

  • 支持多级:能够创建复杂的多级表头结构

  • 易于扩展:可与其他功能(样式、验证等)结合使用

  • 性能优良:即使处理大量数据也能保持良好性能

在实际使用中,建议:

  • 合理设计表头结构,避免过于复杂

  • 注意数据类型匹配,确保数据与表头对应

  • 对用户输入进行验证,防止恶意或错误的字段配置

  • 在处理大量数据时使用分批处理机制

通过动态表头功能,可以轻松实现灵活的数据导出需求,大大提升系统的可配置性和用户体验。

到此这篇关于EasyExcel动态表头基础用法及最佳实践的文章就介绍到这了,更多相关EasyExcel动态表头内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • idea上提交项目到gitee 最后出现 Push rejected的问题处理方法

    idea上提交项目到gitee 最后出现 Push rejected的问题处理方法

    这篇文章主要介绍了idea上面提交项目到gitee 最后出现 Push rejected的问题处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • 详解java实现HTTP请求的三种方式

    详解java实现HTTP请求的三种方式

    这篇文章主要介绍了java实现HTTP请求的三种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-04-04
  • 使用maven如何将项目中的test代码打包进jar中

    使用maven如何将项目中的test代码打包进jar中

    这篇文章主要介绍了使用maven如何将项目中的test代码打包进jar中,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 高分面试从Hotspot源码层面剖析java多态实现原理

    高分面试从Hotspot源码层面剖析java多态实现原理

    这篇文章主要为大家介绍了在面试中从Hotspot源码层面来剖析java多态的实现原理,这样回答薪资随你开,有需要的朋友可以借鉴参考下,希望大家多多加薪
    2022-01-01
  • Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

    Spring Boot + MyBatis Plus 高效开发实战从入

    本文将详细介绍 Spring Boot + MyBatis Plus 的完整开发流程,并深入剖析分页查询、批量操作、动态 SQL、乐观锁、代码优化等实战技巧,感兴趣的朋友一起看看吧
    2025-04-04
  • 解决SpringBoot运行Test时报错:SpringBoot Unable to find

    解决SpringBoot运行Test时报错:SpringBoot Unable to find

    这篇文章主要介绍了SpringBoot运行Test时报错:SpringBoot Unable to find a @SpringBootConfiguration,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • Spring Cache和EhCache实现缓存管理方式

    Spring Cache和EhCache实现缓存管理方式

    这篇文章主要介绍了Spring Cache和EhCache实现缓存管理方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java设计模式之java原型模式详解

    Java设计模式之java原型模式详解

    这篇文章主要介绍了Java设计模式之原型模式详解,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下
    2021-09-09
  • Springboot详解如何整合使用Thymeleaf

    Springboot详解如何整合使用Thymeleaf

    这篇文章主要分享了Spring Boot整合使用Thymeleaf,Thymeleaf是新一代的Java模板引擎,类似于Velocity、FreeMarker等传统引擎,关于其更多相关内容,需要的小伙伴可以参考一下
    2022-06-06
  • struts2静态资源映射代码示例

    struts2静态资源映射代码示例

    这篇文章主要介绍了struts2静态资源映射的相关内容,涉及了具体代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09

最新评论