如何创建一个通用的 FlatFileItemReader 来读取具有不同 headers 的 CSV 文件?

How to create a generic FlatFileItemReader to read CSV files with different headers?

我正在创建一个作业,它将根据输入参数读取和处理不同的 .csv 文件。有 3 种不同类型的 .csv 文件,具有不同的 headers。我想使用通用 FlatFileItemReader 将文件的每一行映射到 POJO。

每种类型的文件都有自己的 POJO 实现,并且所有 "File Specific POJOs" 都是从抽象 GenericFilePOJO 继承而来的。

一个 tasklet 将首先读取输入参数来决定需要读取哪种文件类型,并构造一个具有适当 header 列的 LineTokenizer。它将此信息放在 infoHolder 中,以便在 reader 步骤检索。

@Bean
public FlatFileItemReader<GenericFilePOJO> reader() {
    FlatFileItemReader<RawFile> reader = new FlatFileItemReader<GenericFilePOJO>();
    reader.setLinesToSkip(1); // header

    reader.setLineMapper(new DefaultLineMapper() {
        {
            // The infoHolder will contain the file-specific LineTokenizer
            setLineTokenizer(infoHolder.getLineTokenizer());
            setFieldSetMapper(new BeanWrapperFieldSetMapper<GenericFilePOJO>() {
                {
                    setTargetType(GenericFilePOJO.class);
                }
            });
        }
    });
    return reader;
}

尽管返回 GenericFilePOJO,这个 reader 可以处理不同的文件特定 POJO 吗?

您写道:

A tasklet will first read the input parameter to decide which file type needs to be read.

因为 taskletinfoHolder 知道文件类型,您可以实现特定 FieldSetMapper 实例的创建。

这是一个如何实现的演示示例:

public class Solution<T extends GenericFilePOJO> {
    private InfoHolder infoHolder = new InfoHolder();

    @Bean
    public FlatFileItemReader<T> reader()
    {
        FlatFileItemReader<T> reader = new FlatFileItemReader<T>();
        reader.setLinesToSkip(1);

        reader.setLineMapper(new DefaultLineMapper() {
            {
                setLineTokenizer(infoHolder.getLineTokenizer());
                setFieldSetMapper(infoHolder.getFieldSetMapper());
            }
        });
        return reader;
    }

    private class InfoHolder {
        DelimitedLineTokenizer getLineTokenizer() {
            return <some already existent logic>;
        }

        FieldSetMapper<T> getFieldSetMapper() {
            if (some condition for specific file POJO 1){
                return new BeanWrapperFieldSetMapper<T>() {
                    {
                        setTargetType(FileSpecificPOJO_1.class);
                    }
                };
            } else if (some condition for specific file POJO 2){
                return new BeanWrapperFieldSetMapper<T>() {
                    {
                        setTargetType(FileSpecificPOJO_2.class);
                    }
                };
            }
        }
    }
}