EasyExcel合并单元格,通过注解方式实现自定义合并策略

EasyExcel合并单元格,通过注解方式实现自定义合并策略

简介

今天博主探讨如何实现EasyExcel自定义实现单元格合并策略,考虑需要抽象代码、适用于更多的业务场景,提供了两个工具类,参考过很多博主的方案,并整合优化了一下。
主要思路提供的博主:十一技术斩

代码

  • 首先自定义注解CustomMerge,用于标记哪些属性需要合并,哪个是主键**(这里做了一个优化,可以标记多个主键)**
/**
 * 自定义注解,用于判断是否需要合并以及合并的主键
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CustomMerge {
 
    /**
     * 是否需要合并单元格
     */
    boolean needMerge() default false;
 
    /**
     * 是否是主键,即该字段相同的行合并
     */
    boolean isPk() default false;
}
  • 再创建自定义单元格合并策略类CustomMergeStrategy,当Excel中两列主键相同时,合并被标记需要合并的列**(当前类增加多主键判断是否需要合并)**
/**
 * 自定义单元格合并策略
 */
public class CustomMergeStrategy implements RowWriteHandler {
    /**
     * 主键下标集合
     */
    private List<Integer> pkColumnIndex = new ArrayList<>();
 
    /**
     * 需要合并的列的下标集合
     */
    private List<Integer> needMergeColumnIndex = new ArrayList<>();
 
    /**
     * DTO数据类型
     */
    private Class<?> elementType;
 
    public CustomMergeStrategy(Class<?> elementType) {
        this.elementType = elementType;
    }
 
    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        // 如果是标题,则直接返回
        if (isHead) {
            return;
        }
 
        // 获取当前sheet
        Sheet sheet = writeSheetHolder.getSheet();
 
        // 获取标题行
        Row titleRow = sheet.getRow(0);
 
        if (pkColumnIndex.isEmpty()) {
            this.lazyInit(writeSheetHolder);
        }
 
        // 判断是否需要和上一行进行合并
        // 不能和标题合并,只能数据行之间合并
        if (row.getRowNum() <= 1) {
            return;
        }
        // 获取上一行数据
        Row lastRow = sheet.getRow(row.getRowNum() - 1);
        // 将本行和上一行是同一类型的数据(通过主键字段进行判断),则需要合并
        boolean margeBol = true;
        for (Integer pkIndex : pkColumnIndex) {
        	String lastKey = lastRow.getCell(pkIndex).getCellType() == CellType.STRING ? lastRow.getCell(pkIndex).getStringCellValue() : String.valueOf(lastRow.getCell(pkIndex).getNumericCellValue());
        	String currentKey = row.getCell(pkIndex).getCellType() == CellType.STRING ? row.getCell(pkIndex).getStringCellValue() : String.valueOf(row.getCell(pkIndex).getNumericCellValue());
        	if (!StringUtils.equalsIgnoreCase(lastKey, currentKey)) {
        		margeBol = false;
        		break;
        	}
        }
        if (margeBol) {
            for (Integer needMerIndex : needMergeColumnIndex) {
                CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum() - 1, row.getRowNum(),
                        needMerIndex, needMerIndex);
                sheet.addMergedRegionUnsafe(cellRangeAddress);
            }
        }
    }
 
    /**
     * 初始化主键下标和需要合并字段的下标
     */
    private void lazyInit(WriteSheetHolder writeSheetHolder) {
 
        // 获取当前sheet
        Sheet sheet = writeSheetHolder.getSheet();
 
        // 获取标题行
        Row titleRow = sheet.getRow(0);
        // 获取DTO的类型
        Class<?> eleType = this.elementType;
 
        // 获取DTO所有的属性
        Field[] fields = eleType.getDeclaredFields();
 
 		int i = 0;
        // 遍历所有的字段,因为是基于DTO的字段来构建excel,所以字段数 >= excel的列数
        for (Field theField : fields) {
            // 获取@ExcelProperty注解,用于获取该字段对应在excel中的列的下标
            ExcelProperty easyExcelAnno = theField.getAnnotation(ExcelProperty.class);
            // 为空,则表示该字段不需要导入到excel,直接处理下一个字段
            if (null == easyExcelAnno) {
                continue;
            }
            // 获取自定义的注解,用于合并单元格
            CustomMerge customMerge = theField.getAnnotation(CustomMerge.class);
 
            // 没有@CustomMerge注解的默认不合并
            if (null == customMerge) {
                continue;
            }
            
            // 判断是否有主键标识
            if (customMerge.isPk()) {
                pkColumnIndex.add(i);
            }
			
			// 判断是否需要合并
            if (customMerge.needMerge()) {
                needMergeColumnIndex.add(i);
            }
            i++;
        }
 
        // 没有指定主键,则异常
        if (pkColumnIndex.isEmpty()) {
            throw new IllegalStateException("使用@CustomMerge注解必须指定主键");
        }
 
    }
}

导出结果图

导出配置
导出结果

总结

实现效果可以参考上面十一技术斩
,这里主要对博主的自定义策略做了一些小小的优化,希望能帮到更多需要同学。

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
EasyExcel中,自定义合并单元格策略可以通过实现`com.alibaba.excel.metadata.CellStrategy`接口来实现。可以参考上面提到的技术斩博主的自定义策略进行优化。 具体步骤如下: 1. 创建一个类,实现`CellStrategy`接口,并重写`merge(CellRangeAddress cellRangeAddress, Sheet sheet)`方法。 2. 在`merge()`方法中,根据自定义合并单元格规则,通过`cellRangeAddress`参数来确定需要合并单元格范围,然后通过`sheet`对象进行单元格合并操作。 3. 根据需要,在自定义策略中添加其他的处理逻辑,例如设置合并单元格的样式等。 4. 在使用EasyExcel进行导出时,通过`excelWriter.setCustomCellWriteHandler()`方法来设置自定义合并单元格策略。 请注意,以上步骤仅是一种实现自定义合并单元格策略的方法,具体的实现方式可能会因项目需求而有所不同。<span class="em">1</span><span class="em">2</span> #### 引用[.reference_title] - *1* [利用easyExcel导出上万条数据,自定义策略合并单元格](https://download.csdn.net/download/qq_32734167/13408705)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [EasyExcel合并单元格,通过注解方式实现自定义合并策略](https://blog.csdn.net/q1468051413/article/details/127832071)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值