EasyExcel自定义处理器处理单元格空值转换问题(适用全局设置)

前言:在工作中使用EasyExcel处理复杂的大数据量时,会遇到从数据库查询的数据字段存在空值的问题,分享解决思路和解决方案

一开始查询百度的解决方案是使用EasyExcel的内置转换器进行自定义封装处理,代码如下:

import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author edward
 * @className NullConverter
 * @description:
 * @date 2022/6/14 16:51
 **/
public class NullConverter implements Converter<String> {

    /**
     * 回到 Java 中的对象类型
     *
     * @return 支持 Java 类
     */
    @Override
    public Class supportJavaTypeKey() {
        return String.class;
    }

    /**
     * * 返回 excel 中的对象枚举
     * * @return 支持 {@link Cell DataTypeEnum}
     * */
    @Override
    public CellDataTypeEnum supportExcelTypeKey() {
        return CellDataTypeEnum.STRING;
    }

    /**
     * 将excel对象转换为Java对象
     *
     * @param cellData
     * Excel 单元格数据。NotNull。
     * @param contentProperty
     * 内容属性。可空。
     * @param globalConfiguration
     * 全局配置。NotNull。
     * @return 要放入 Java 对象的数据
     * @抛出异常
     *             例外。
     */
    @Override
    public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return "-".equals(cellData.getStringValue())?null:cellData.getStringValue();
    }

    /**
     * 将 Java 对象转换为 excel 对象
     *
     * @参数值
     * Java 数据.NotNull。
     * @param contentProperty
     * 内容属性。可空。
     * @param globalConfiguration
     * 全局配置。NotNull。
     * @return 数据放入 Excel
     * @抛出异常
     *             例外。
     */
    @Override
    public CellData convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
        return new CellData<>(null == value?"-":value);
    }
}

应用:

/**
     * ID
     */
    @ExcelProperty(converter = NullConverter.class)
    private Integer id;

说明:转换主要看convertToExcelData()方法,在这里将null值转换成“-”,但通过转换器的方式有两个弊端:
      1.每个字段都要添加@ExcelProperty(converter = NullConverter.class)代码,如果遇到大量的数据字段去填充处理会增加很多工作量。
      2.转换器仅支持需要被处理的数据字段,也就是适用于从数据库查询出来已有的数据,如日期格式或性别字段做转换时才生效,对于本身有些字段就是null值时并不能进入到该方法,所以这种解决方案不适用

第二种就是从数据库查询出来的数据,每个数据字段都进行处理,但也是大数据量时工作量很大,当时就想过能否用EasyExcel的监听器去监听处理每个Sheet工作表对象,但研究过后发现并不适用这种场景。所以这种解决方案也不适用

第三种就是EasyExcel内置处理器去自定义封装,当时就想既然查询出来的数据都是要填充到每个单元格的,那么每个单元格都需要做判断处理,那EasyExcel有没有提供相对应的Handler呢,于是就有了下面的解决方案,代码如下:

import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import java.util.List;

/**
 * @author edward
 * @className NullWriteHandler
 * @description: 自定义写入处理器(处理空值)
 * @date 2022/6/8 20:24
 **/
public class CustomizeWriteHandler implements CellWriteHandler {

    /**
     * 在创建单元格之前调用
     *
     * @param writeSheetHolder
     * @param writeTableHolder
     * Nullable。不使用表写入为空。
     * @param row
     * @param head
     * Nullable。填充数据且不带head的情况下为null。
     * @param columnIndex
     * @param relativeRowIndex
     * Nullable。填充数据时为null。
     * @param isHead
     * 填充数据时始终为假。
     */
    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {

    }

    /**
     * 创建单元格后调用
     *
     * @param writeSheetHolder
     * @param writeTableHolder
     * Nullable。不使用表写入为空。
     * @param cell
     * @param head
     * Nullable。填充数据且不带head的情况下为null。
     * @param relativeRowIndex
     * Nullable。填充数据时为null。
     * @param isHead
     * 填充数据时始终为假。
     */
    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
    }

    /**
     * 单元格数据转换后调用
     *
     * @param writeSheetHolder
     * @param writeTableHolder
     * Nullable。不使用表写入为空。
     * @param cell
     * @param head
     * Nullable。填充数据且不带head的情况下为null。
     * @param cellData
     * 可空,添加头时为空。
     * @param relativeRowIndex
     * Nullable。填充数据时为null。
     * @param isHead
     * 填充数据时始终为假。
     */
    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {

    }

    /**
     * 在单元格上的所有操作都完成后调用
     *
     * @param writeSheetHolder
     * @param writeTableHolder
     * Nullable。不使用表写入为空。
     * @param cell
     * @param head
     * Nullable。填充数据且不带head的情况下为null。
     * @param cellDataList
     * Nullable。添加header时为null。填充数据时可能有多个。
     * @param relativeRowIndex
     * Nullable。填充数据时为null。
     * @param isHead
     * 填充数据时始终为假。
     */
    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
        /* 判断是否有进行填充数据的操作 */
        if(!isHead){
            /* 获取当前单元格的类型 */
            switch (cell.getCellType()){
                /* 当为String类型是判断是否为null或者"",是的话统一设置成指定值 */
                case Cell.CELL_TYPE_STRING:
                    String stringCellValue = cell.getStringCellValue();
                    if(null == stringCellValue || "".equals(stringCellValue)){
                        cell.setCellValue("-");
                    }
                    break;
            }
        }
    }
}

说明:前三个默认就行,还是使用最后面的方法,在单元格的所有操作都完成后调用该方法,每个单元格去判断是否为String类型,如果是并且是null值的话在重新设置值到cell对象中,实测问题解决!

应用如下图:这里通过链式调用注册一个处理器作用到一个工作表中,如果遇到多个工作表的话需要对每个工作表进行注册,在全局设置下也能保证对每个工作表和单元格的控制
在这里插入图片描述

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
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 ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值