EasyExcel系列:读取空数据行的问题

该文章已生成可运行项目,

        定义Excel模板时,会生产空行问问题,可以自定义监听器过滤空行。以PageReadListener为例。


/**
 * 自定义读取监听器,解决无法空行问题
 *
 */
@Slf4j
public class MyPageReadListener<T> extends PageReadListener<T> {
 
 
    @Override
    public void invoke(T data, AnalysisContext context) {
        // 如果一行Excel数据均为空值,则不装载该行数据
        if (isLineNullValue(data)) {
            return;
        }
        ...
    }
 
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        ...
    }
 
    /**
     * 判断整行单元格数据是否均为空
     */
    private boolean isLineNullValue(T data) {
        if (data instanceof String) {
            return Objects.isNull(data);
        }
        try {
            List<Field> fields = Arrays.stream(data.getClass().getDeclaredFields())
                    .filter(f -> f.isAnnotationPresent(ExcelProperty.class))
                    .collect(Collectors.toList());
            List<Boolean> lineNullList = new ArrayList<>(fields.size());
            for (Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(data);
                if (Objects.isNull(value)) {
                    lineNullList.add(Boolean.TRUE);
                } else {
                    lineNullList.add(Boolean.FALSE);
                }
            }
            return lineNullList.stream().allMatch(Boolean.TRUE::equals);
        } catch (Exception e) {
            log.error("读取数据行[{}]解析失败: {}", data, e.getMessage());
        }
        return true;
    }
 
}

本文章已经生成可运行项目
<think>好的,我现在需要解决用户提出的EasyExcel读取Excel时出现数据问题。根据用户提供的引用内容,我需要先理解问题的具体情况和已有的解决方案。 首先,用户提到在引用[1]中,当Excel中的列不存在对应的注解时,数据读取为null。解决方法包括删除多余的注解或在Excel中添加对应的列。这可能意味着当实体类的字段与Excel列不匹配时,会导致数据问题。因此,我需要考虑如何处理列映射的问题,避免未匹配的列导致值。 接下来,引用[2]提到EasyExcel是逐读取的,可能用户在处理大文件时遇到空行读取的情况。需要检查是否有被解析为数据,导致出现数据对象。此时,可能需要通过事件监听器或自定义过滤器来跳过空行。 引用[3]和[4]分别讨论了数据类型转换和表头匹配的问题,虽然用户当前的问题是关于数据的,但可能表头匹配问题也会导致某些字段为。例如,如果表头大小写不一致或顺序变化,可能导致部分字段无法正确映射,从而出现数据。因此,需要确保表头匹配正确,可能使用@ExcelProperty的index属性或名称匹配策略。 用户的问题具体是读取Excel时数据问题,可能包括两种情况:一是整数据,但仍被读取为对象;二是部分列为导致对象中某些字段为null。需要分别处理这两种情况。 根据引用[1]的解决方法,删除多余注解或添加列可以解决列不匹配的问题。这可能意味着在实体类中定义的字段多于Excel中的列,导致多余的字段被填充为null。因此,用户需要检查实体类与Excel列是否一一对应,确保注解正确。 另外,如果存在完全白的,可能需要使用监听器在读取时跳过这些。例如,在监听器的invoke方法中判断当前数据是否全部为,如果是则跳过不处理。 可能还需要考虑使用EasyExcel提供的ReadListener接口,在读取每一时进自定义处理。例如,在afterRead方法中检查数据对象的属性是否全为null,如果是则忽略该。 此外,用户可能需要使用自定义的Converter来处理特定字段的值情况,或者调整读取时的参数,如ignoreEmptyRow(但需确认EasyExcel是否支持该参数)。 总结解决方案步骤: 1. 检查实体类与Excel列映射是否正确,删除多余注解或添加列。 2. 使用监听器在读取时过滤空行判断数据是否全为并跳过。 3. 调整表头匹配策略,确保字段正确映射,避免部分字段为。 4. 使用自定义Converter或读取参数忽略空行。 需要验证这些步骤的有效性,确保解决方案覆盖用户的问题场景,并参考提供的引用内容进支持。</think>### EasyExcel 读取 Excel 数据解决方案 #### 问题原因分析 1. **列映射不匹配** - 当实体类注解(如 `@ExcelProperty`)与 Excel 列名或顺序不一致时,会导致字段无法正确映射,读取结果中部分字段为 `null`[^1][^4]。 - 若 Excel 中存在未被注解声明的列,或实体类中存在多余的注解,可能生成数据。 2. **被解析为数据** - EasyExcel 默认逐读取,若 Excel 中包含完全(无任何内容),可能被解析为数据对象,但所有字段为 `null`[^2]。 3. **数据部分字段为** - Excel 中某的某些单元格为,对应的实体类字段会填充 `null`,可能被误判为“数据”。 --- #### 解决方案步骤 ##### 1. **检查列映射配置** - **删除多余注解**:确保实体类中的 `@ExcelProperty` 注解仅对应 Excel 中存在的列,避免未匹配的注解生成 `null` 字段。 示例: ```java // 错误示例:多余的注解会导致字段为 null public class DemoData { @ExcelProperty("姓名") private String name; @ExcelProperty("未存在的列") // 删除此注解 private String unusedField; } ``` - **使用 `index` 属性**:若表头顺序变化或大小写不一致,通过 `@ExcelProperty(index = 0)` 按列索引映射。 ##### 2. **过滤** - **自定义监听器**:通过实现 `ReadListener` 接口,在 `invoke` 方法中判断数据是否全为: ```java public class EmptyRowListener implements ReadListener<DemoData> { @Override public void invoke(DemoData data, AnalysisContext context) { // 检查所有字段是否均为 null 或字符串 if (isRowEmpty(data)) { return; // 跳过 } // 处理有效数据 } private boolean isRowEmpty(DemoData data) { return data.getName() == null && data.getAge() == null && data.getEmail() == null; } } ``` - **注册监听器**: ```java EasyExcel.read(file, DemoData.class, new EmptyRowListener()).sheet().doRead(); ``` ##### 3. **调整读取参数** - **忽略表头大小写**:通过 `headRowNumber` 和 `head` 配置灵活匹配表头: ```java EasyExcel.read(file) .head(DemoData.class) .sheet() .headRowNumber(1) // 指定表头 .doRead(); ``` - **使用 `Converter` 处理值**:自定义转换器将字符串转为 `null` 或默认值。 ##### 4. **处理部分字段** - **默认值注解**:结合 `@ColumnDefault` 或 Lombok 的 `@Builder.Default` 为字段设置默认值: ```java public class DemoData { @ExcelProperty("姓名") @Builder.Default private String name = "未知"; } ``` --- #### 代码示例 ```java // 实体类定义(确保注解与Excel列一致) public class DemoData { @ExcelProperty(index = 0) private String name; @ExcelProperty(index = 1) private Integer age; } // 读取时过滤 EasyExcel.read("data.xlsx", DemoData.class, new PageReadListener<DemoData>(dataList -> { dataList.removeIf(data -> data.getName() == null && data.getAge() == null); // 处理非数据 })).sheet().doRead(); ``` --- #### 相关参考问题 1. **如何优化 EasyExcel 读取数据量 Excel 的性能?** - 利用逐读取特性,避免全量加载到内存。 2. **如何处理 EasyExcel 读取时的数据类型转换错误?** - 使用自定义 `Converter` 或升级到 2.2.6+ 版本修复数字格式问题[^3]。 3. **如何动态匹配不同结构的 Excel 表头?** - 结合 `@ExcelProperty` 的 `index` 和名称匹配策略,或使用 `Map<Integer, String>` 接收数据: 删除多余注解或添加列解决列不匹配问题 :读取避免内存溢出 : 版本升级修复数字格式 [^4]: 索引和名称匹配策略
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值