深入解析EasyExcel自定义列样式:基于AbstractVerticalCellStyleStrategy的灵活实现
1. 为什么需要自定义列样式在实际开发中我们经常遇到这样的需求导出的Excel表格需要根据不同列的内容类型设置不同的样式。比如文字列需要居中显示数字列需要右对齐金额列可能需要特殊格式和颜色标注。这种需求在产品经理眼中再正常不过了但对开发者来说却是个不小的挑战。EasyExcel作为阿里巴巴开源的优秀Excel处理工具虽然提供了丰富的注解方式来定义样式但当我们需要动态生成表格比如从数据库查询结果直接导出时注解方式就显得力不从心了。这时候就需要用到AbstractVerticalCellStyleStrategy这个利器。我最近在一个财务系统中就遇到了类似需求导出的报表需要根据30多列的不同数据类型设置不同的样式。通过深入研究AbstractVerticalCellStyleStrategy最终完美解决了这个问题。下面就把我的实战经验分享给大家。2. 理解AbstractVerticalCellStyleStrategy2.1 核心作用与优势AbstractVerticalCellStyleStrategy是EasyExcel提供的一个抽象类专门用于处理垂直方向即列方向的单元格样式。与HorizontalCellStyleStrategy处理行样式不同它允许我们为每一列设置独立的样式这正是我们需要的功能。这个策略类的最大优势在于灵活性可以根据列索引动态设置不同样式解耦性样式逻辑与数据生成逻辑分离复用性同一套样式策略可以应用于多个导出场景2.2 关键方法解析要实现自定义列样式主要需要重写两个核心方法// 设置表头单元格样式 protected abstract WriteCellStyle headCellStyle(Head head); // 设置内容单元格样式 protected abstract WriteCellStyle contentCellStyle(Head head);这两个方法都会传入Head对象通过head.getColumnIndex()可以获取当前列的索引这是我们实现差异化样式的关键。3. 实战实现动态列样式3.1 基础实现步骤让我们通过一个完整示例来演示如何实现动态列样式。假设我们要导出一个员工信息表要求姓名、部门列居中工龄、薪资列右对齐入职日期列特殊格式首先创建一个自定义样式策略类public class CustomVerticalCellStyleStrategy extends AbstractVerticalCellStyleStrategy { private ListHorizontalAlignment alignments; public CustomVerticalCellStyleStrategy(ListHorizontalAlignment alignments) { this.alignments alignments; } Override protected WriteCellStyle headCellStyle(Head head) { WriteCellStyle style new WriteCellStyle(); // 设置表头样式这里简单处理为统一样式 style.setHorizontalAlignment(HorizontalAlignment.CENTER); return style; } Override protected WriteCellStyle contentCellStyle(Head head) { WriteCellStyle style new WriteCellStyle(); int columnIndex head.getColumnIndex(); // 根据列索引设置不同的对齐方式 style.setHorizontalAlignment(alignments.get(columnIndex)); // 特殊处理日期列 if(columnIndex 4) { style.setDataFormat((short)22); // 设置日期格式 } return style; } }3.2 使用自定义策略在导出时注册我们的样式策略// 定义各列对齐方式 ListHorizontalAlignment alignments Arrays.asList( HorizontalAlignment.CENTER, // 姓名 HorizontalAlignment.CENTER, // 部门 HorizontalAlignment.RIGHT, // 工龄 HorizontalAlignment.RIGHT, // 薪资 HorizontalAlignment.CENTER // 入职日期 ); // 创建并注册样式策略 CustomVerticalCellStyleStrategy styleStrategy new CustomVerticalCellStyleStrategy(alignments); // 构建写入器 ExcelWriter excelWriter EasyExcel.write(outputStream) .registerWriteHandler(styleStrategy) .head(headList) .build(); // 写入数据 WriteSheet writeSheet EasyExcel.writerSheet(员工信息).build(); excelWriter.write(dataList, writeSheet); excelWriter.finish();4. 高级技巧与优化4.1 支持更复杂的样式配置上面的示例只设置了简单的对齐方式实际上我们可以配置更多样式属性WriteCellStyle style new WriteCellStyle(); style.setHorizontalAlignment(alignments.get(columnIndex)); style.setVerticalAlignment(VerticalAlignment.CENTER); style.setBorderLeft(BorderStyle.THIN); style.setBorderRight(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN); style.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex()); style.setFillPatternType(FillPatternType.SOLID_FOREGROUND); style.setWrapped(true); // 自动换行 // 设置字体 WriteFont font new WriteFont(); font.setFontName(微软雅黑); font.setFontHeightInPoints((short)11); style.setWriteFont(font);4.2 动态样式决策我们可以根据列内容动态决定样式而不仅仅是根据列索引。例如对于薪资列可以设置不同颜色if(columnIndex 3) { // 薪资列 BigDecimal salary (BigDecimal)cellData.getNumberValue(); if(salary.compareTo(new BigDecimal(10000)) 0) { style.setFillForegroundColor(IndexedColors.LIGHT_GREEN.getIndex()); } else { style.setFillForegroundColor(IndexedColors.LIGHT_YELLOW.getIndex()); } }4.3 性能优化建议当处理大量数据时样式设置可能会影响性能。可以考虑以下优化方案样式复用相同样式的单元格共享同一个WriteCellStyle实例缓存机制将常用样式缓存起来避免重复创建批量处理对于大数据量导出考虑分批次处理5. 常见问题与解决方案5.1 样式不生效的可能原因在实际使用中可能会遇到样式不生效的情况。常见原因包括没有正确注册WriteHandler样式属性冲突比如同时设置了多个样式处理器列索引计算错误特别是使用了复杂表头时我遇到过最棘手的问题是表头合并单元格导致的列索引错乱。解决方案是在headCellStyle方法中打印出列索引进行调试System.out.println(Processing column: head.getColumnIndex() - head.getHeadNameList());5.2 与其它WriteHandler的配合使用当同时使用多个WriteHandler时需要注意执行顺序。EasyExcel会按照注册顺序执行处理器。如果发现样式被覆盖可以调整注册顺序或合并样式处理逻辑。例如同时使用列宽处理器和样式处理器// 先设置列宽 excelWriter.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()); // 再设置样式 excelWriter.registerWriteHandler(styleStrategy);5.3 复杂表头的处理对于多级表头head.getColumnIndex()返回的是最底层列的索引。如果需要根据表头层级设置不同样式可以通过head.getHeadNameList()获取表头名称列表来判断层级if(head.getHeadNameList().size() 1) { // 这是二级表头 style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); }6. 实际项目中的应用案例最近在一个电商后台系统中我们需要导出订单明细报表包含30多个字段每个字段都需要特定的样式订单号、商品名称等文本字段居中显示灰色背景数量、单价等数字字段右对齐保留两位小数金额字段右对齐红色加粗显示日期字段特定日期格式状态字段根据状态值显示不同颜色通过CustomVerticalCellStyleStrategy我们完美实现了这些需求。关键代码如下public class OrderCellStyleStrategy extends AbstractVerticalCellStyleStrategy { private static final MapString, Short STATUS_COLORS new HashMap(); static { STATUS_COLORS.put(待付款, IndexedColors.RED.getIndex()); STATUS_COLORS.put(已付款, IndexedColors.BLUE.getIndex()); STATUS_COLORS.put(已发货, IndexedColors.GREEN.getIndex()); STATUS_COLORS.put(已完成, IndexedColors.GREY_50_PERCENT.getIndex()); } Override protected WriteCellStyle contentCellStyle(Head head) { WriteCellStyle style new WriteCellStyle(); int columnIndex head.getColumnIndex(); // 文本列 if(columnIndex 5) { style.setHorizontalAlignment(HorizontalAlignment.CENTER); style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); style.setFillPatternType(FillPatternType.SOLID_FOREGROUND); } // 数字列 else if(columnIndex 10) { style.setHorizontalAlignment(HorizontalAlignment.RIGHT); style.setDataFormat((short)4); // #,##0.00 } // 金额列 else if(columnIndex 11) { style.setHorizontalAlignment(HorizontalAlignment.RIGHT); style.setDataFormat((short)4); WriteFont font new WriteFont(); font.setBold(true); font.setColor(IndexedColors.RED.getIndex()); style.setWriteFont(font); } // 状态列 else if(columnIndex 12) { style.setHorizontalAlignment(HorizontalAlignment.CENTER); // 实际项目中会根据单元格值动态设置颜色 // 这里简化处理 style.setFillForegroundColor(STATUS_COLORS.get(待付款)); style.setFillPatternType(FillPatternType.SOLID_FOREGROUND); } return style; } }这个案例充分展示了AbstractVerticalCellStyleStrategy的强大灵活性无论多么复杂的样式需求都能通过合理的代码组织来实现。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2459590.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!