java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > EasyExcel动态表头

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

作者: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动态表头内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文