easyexcel 希望赋予程序员自定义DefaultAnalysisEventProcessor的能力

ncecgwcz  于 4个月前  发布在  其他
关注(0)|答案(1)|浏览(40)

我粗略查看过EasyExcel源码,在读取Excel完成每行数据与实体的映射的实现应该是在DefaultAnalysisEventProcessor类的一个dealDatafan方法完成映射的吧。在开发中,比如说读取某一些模板的数据,也许只会读取第几行到第几行的数据(因为再往下读取就可以会出现一些非法数据,比如模板最下面有个时间,会导致映射出现问题,然后程序报错),这时候肯定会使用ReadListener的hasNext来控制读取的行数,但是一旦提前结束读Excel,doAfterAllAnalysed就不会被执行。这样就会出现需要程序员自己去判断是否完成已经完成处理表格,然后再把剩余存储在内存的数据存进数据库,doAfterAllAnalysed失去了其本身的作用,显得有点鸡肋。
对于这个场景,虽然程序员靠自己判断是否“完成”读取进而处理剩余的数据,但是我希望EasyExcel可以提供给我们程序员自定义AnalysisEventProcessor的能力,就像Spring的拦截器一样,让我们可以通过判断某些条件是否成立,进而判断是否将行数据与Clas实体进行映射,避免了映射失败出现报错的情况,也可以使得最后面excel读取完成,顺利调用doAfterAllAnalysed方法去处理内存剩余的数据,不需要程序员自己去判断,使得doAfterAllAnalysed不再那么鸡肋。
当然,这只是我个人的想法,可以会存在很多错误的地方,欢迎作者大大一起交流指教!!!

ha5z0ras

ha5z0ras1#

import com.alibaba.excel.analysis.v03.handlers.AbstractXlsRecordHandler;
import com.alibaba.excel.analysis.v07.handlers.AbstractXlsxRecordHandler;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventProcessor;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelAnalysisException;
import com.alibaba.excel.metadata.Sheet;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.support.ExcelTypeEnum;

import java.util.Iterator;
import java.util.List;

public class CustomEventListener<T> extends AnalysisEventListener<T> {

    private final AnalysisEventProcessor eventProcessor;
    private boolean stopRead = false;

    public CustomEventListener(AnalysisEventProcessor eventProcessor) {
        this.eventProcessor = eventProcessor;
    }

    @Override
    public void invoke(T data, AnalysisContext context) {
        if (!stopRead) {
            eventProcessor.process(data, context);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if (!stopRead) {
            // Handle remaining data in memory after all data is analyzed
            // This method will be called regardless of whether all data is processed or not
            // You can handle the remaining data here
        }
    }

    @Override
    public void invokeHead(Map<Integer, CellData> headMap, AnalysisContext context) {
        // If you need to handle header data, you can override this method
    }

    @Override
    public boolean hasNext(AnalysisContext context) {
        if (stopRead) {
            return false;
        }
        boolean hasNext = super.hasNext(context);
        if (!hasNext) {
            // If hasNext returns false, it means all data has been read
            // You can perform additional operations here, such as processing remaining data in memory
            // For example, you can check whether the last row meets certain conditions, 
            // if not, you can handle the remaining data here
            stopRead = true;
        }
        return hasNext;
    }

    @Override
    public void parseExcel(AnalysisContext context) {
        while (hasNext(context)) {
            // Loop through each row and parse
            try {
                ReadRowHolder readRowHolder = readRowHolder(context);
                if (readRowHolder == null) {
                    break;
                }
                parseRow(readRowHolder, context);
            } catch (Exception e) {
                if (e instanceof ExcelAnalysisException) {
                    // Handle ExcelAnalysisException if needed
                }
            }
        }
    }

    private void parseRow(ReadRowHolder readRowHolder, AnalysisContext context) {
        // Your logic to determine whether to map the row data to entity
        // For example, you can check the row number and decide whether to map the data
        if (shouldMap(readRowHolder.getRowIndex(), context)) {
            eventProcessor.process(readRowHolder, context);
        }
    }

    private boolean shouldMap(int rowIndex, AnalysisContext context) {
        // Your logic to determine whether to map the row data to entity
        // For example, you can check the row number and decide whether to map the data
        return rowIndex >= context.readSheetHolder().getReadSheet().getHeadRowNumber()
                && rowIndex <= context.readSheetHolder().getReadSheet().getHeadRowNumber() + 10; // Example condition
    }
}

相关问题