首页 > 解决方案 > 如何使用 Spring Batch 读取多行阅读器

问题描述

我想从固定格式的输入数据文件中读取数据,如下所示,每条记录包含多行,以 XYZ 开头是记录的开头,子序列行是 ABC 和 DEF 也是相同的记录。再次以 XYZ 开头是新记录,

我可以知道哪个最好使用 Spring 批处理 ItemReader 或 ItemStream 以及它会有所帮助的任何示例。提前谢谢

XYZ$19801234567S     2011234500001                                               
ABC$II9J234565443                                                                 
DEF$00095834753                                                                    
XYZ$198003453S       212345300003                                               
ABC$II43534503                                                                 
DEF$00035345303 

标签: spring-batch

解决方案


当我们必须在一个文件中处理多种记录类型时,这是一种常见的情况。查看此处的文档https://docs.spring.io/spring-batch/docs/4.2.x/reference/html/readersAndWriters.html#prefixMatchingLineMapper

在您的情况下,您可以为 ItemReader 定义一个映射器PatternMatchingCompositeLineMapper,您必须为每种情况定义不同的标记器。

例子:

@Bean
public PatternMatchingCompositeLineMapper patternMatchingLineMapper() {
    PatternMatchingCompositeLineMapper lineMapper = new PatternMatchingCompositeLineMapper();

   Map<String, LineTokenizer> tokenizers = new HashMap<>(3);
   tokenizers.put("XYZ*", xyzTokenizer());
   tokenizers.put("ABC*", abcTokenizer());
   tokenizers.put("DEF*", defTokenizer());

   lineMapper.setTokenizers(tokenizers);

   Map<String, FieldSetMapper> mappers = new HashMap<>(2);
   mappers.put("XYZ*", xyzFieldSetMapper());
   mappers.put("ABC*", abcFieldSetMapper());
   mappers.put("DEF*", defFieldSetMapper());

   lineMapper.setFieldSetMappers(mappers);

   return lineMapper;
}

您可以使用其他解决方案PatternMatchingCompositeLineTokenizer。在这种情况下,您可以按如下方式配置您的线路标记器:

@Bean
public LineTokenizer patternCompositeLineTokenizer() throws Exception {
    FixedLengthTokenizer recordTypeXYZ = new FixedLengthTokenizer();
    ...

    FixedLengthTokenizer recordTypeABC = new FixedLengthTokenizer();
    ...

    FixedLengthTokenizer recordTypeDEF = new FixedLengthTokenizer();
    ...

    Map<String, LineTokenizer> tokenizers = new HashMap(3);
    tokenizers.put("XYZ*", recordTypeXYZ);
    tokenizers.put("ABC*", recordTypeABC);
    tokenizers.put("DEF*", recordTypeDEF);

    PatternMatchingCompositeLineTokenizer lineTokenizer = new PatternMatchingCompositeLineTokenizer();
    lineTokenizer.setTokenizers(tokenizers);

    return lineTokenizer;
}

@Bean
public FieldSetMapper<YourDomain> fieldSetMapper() { 
    return fieldSet -> {
        switch (fieldSet.readString("yourField")) {
            case XYZ: return new XyzDomain(...); 
            case ABC: return new AbcDomain(...);
            case DEF: return new DefDomain(...) 

            default: throw new IllegalArgumentException("Invalid record type ");
        } 
    };
}

@Bean
@StepScope
public FlatFileItemReader<YourDomain> itemReader() throws Exception {
    return new FlatFileItemReaderBuilder<YourDomain>()
            .name("itemReader")
            .resource(yourResource)
            .lineTokenizer(patternCompositeLineTokenizer())
            .fieldSetMapper(fieldSetMapper())
            .build();
}

推荐阅读