简体   繁体   English

Spring Batch:如何使用FlatFileItemReader读取CSV文件的页脚和验证

[英]Spring Batch : How to read footer of CSV file and validation using FlatFileItemReader

I am using Spring Batch and FlatFileItemReader to read a .CSV file. 我使用Spring BatchFlatFileItemReader来读取.CSV文件。 A file have a header(first line), details and footer(last line). 文件有标题(第一行),详细信息和页脚(最后一行)。 So, I want to validate total number of details by a footer line. 所以,我想通过页脚行验证详细信息的总数。

This is my example .csv file. 这是我的示例.csv文件。

movie.csv movie.csv

Name|Type|Year 名称|类型|年
Notting Hill|romantic comedy|1999 诺丁山|浪漫喜剧| 1999
Toy Story 3|Animation|2010 玩具总动员3 |动画| 2010
Captain America: The First Avenger|Action|2011 美国队长:第一复仇者|行动| 2011
3 3

from example file 来自示例文件
First line is a header (and I ignore it). 第一行是标题(我忽略它)。
At line 2-4 is a detail lines, and last is a footer. 第2-4行是细节线,最后是页脚。

I want to read footer and get value (last line = 3) 我想读取页脚并获取值(最后一行= 3)
and after, get total number recod of details (in this case we have 3 lines) 之后,获取详细信息的总数(在这种情况下,我们有3行)
and last I'll validation total from footer (3) and total number record of details (3) is equals? 并且最后我将从页脚(3)验证总数并且详细信息(3)的总数记录是等于?


and this is my code. 这是我的代码。

@Bean
@StepScope
public FlatFileItemReader<Movie> movieItemReader(String filePath) {
        FlatFileItemReader<Movie> reader = new FlatFileItemReader<>();
        reader.setLinesToSkip(1);   //skip header line
        reader.setResource(new PathResource(filePath));

        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer("|");
        DefaultLineMapper<Movie> movieLineMapper = new DefaultLineMapper<>();
        FieldSetMapper<Movie> movieMapper = movieFieldSetMapper();

        movieLineMapper.setLineTokenizer(tokenizer);
        movieLineMapper.setFieldSetMapper(movieFieldSetMapper);
        movieLineMapper.afterPropertiesSet();
        reader.setLineMapper(movieLineMapper);
        return reader;
}

public FieldSetMapper<Movie> movieFieldSetMapper() {
        BeanWrapperFieldSetMapper<Movie> movieMapper = new BeanWrapperFieldSetMapper<>();
        movieMapper.setTargetType(Movie.class);
        return movieMapper;
}

You can use a chunk oriented step as a validation step before your job's business logic. 在作业的业务逻辑之前,您可以使用面向块的步骤作为验证步骤。 This step would use a ItemReadListener to save the last item and a StepExecutionListener for the validation. 此步骤将使用ItemReadListener保存最后一项,并使用StepExecutionListener进行验证。 Here is a quick example: 这是一个简单的例子:

import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.ItemReadListener;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.PassThroughLineMapper;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ByteArrayResource;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    @StepScope
    public FlatFileItemReader<String> itemReader() {
        FlatFileItemReader<String> reader = new FlatFileItemReader<>();
        reader.setLinesToSkip(1);   //skip header line
        reader.setResource(new ByteArrayResource("header\nitem1\nitem2\n2".getBytes()));
        reader.setLineMapper(new PassThroughLineMapper());
        return reader;
    }

    @Bean
    public ItemWriter<String> itemWriter() {
        return items -> {
            for (String item : items) {
                System.out.println("item = " + item);
            }
        };
    }

    @Bean
    public Step step1() {
        MyListener myListener = new MyListener();
        return steps.get("step1")
                .<String, String>chunk(5)
                .reader(itemReader())
                .writer(itemWriter())
                .listener((ItemReadListener<String>) myListener)
                .listener((StepExecutionListener) myListener)
                .build();
    }

    @Bean
    public Step step2() {
        return steps.get("step2")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("Total count is ok as validated by step1");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(step1())
                .next(step2())
                .build();
    }

    static class MyListener extends StepExecutionListenerSupport implements ItemReadListener<String> {

        private String lastItem;

        @Override
        public void beforeRead() {
        }

        @Override
        public void afterRead(String item) {
            this.lastItem = item;
        }

        @Override
        public void onReadError(Exception ex) {

        }

        @Override
        public ExitStatus afterStep(StepExecution stepExecution) {
            int readCount = stepExecution.getReadCount();
            int totalCountInFooter = Integer.valueOf(this.lastItem); // TODO sanity checks (number format, etc)
            System.out.println("readCount = " + (readCount - 1)); // substract footer from the read count
            System.out.println("totalCountInFooter = " + totalCountInFooter);
            // TODO do validation on readCount vs totalCountInFooter
            return ExitStatus.COMPLETED; // return appropriate exit status according to validation result
        }
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        jobLauncher.run(job, new JobParameters());
    }

}

This example prints: 此示例打印:

item = item1
item = item2
item = 2
readCount = 2
totalCountInFooter = 2
Total count is ok as validated by step1

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在Spring批处理中使用FlatFileItemReader忽略CSV中不需要的列 - How to ignore unwanted columns in CSV using FlatFileItemReader in spring batch Spring 使用 FlatFileItemReader 批量空文件 xML - Spring Batch empty file using FlatFileItemReader xML 读取 CSV 中的换行符,这些换行符在 spring 批处理的 FlatfileItemReader 中的文件中引用 - Reading line breaks in CSV which are quoted in the file in FlatfileItemReader of spring batch Spring批处理FlatfileitemReader读取格式错误的行 - Spring batch FlatfileitemReader to read malformed lines 在Spring Batch中更新FlatFileItemReader之后的文件 - Update file after FlatFileItemReader in Spring Batch Spring Batch:固定长度 FlatFileItemReader 期望页脚行或失败 - Spring Batch: fixed length FlatFileItemReader expect a footer line or fail Spring Batch-写入时将读取行FlatFileItemReader拆分为多行 - Spring Batch - Split a read line FlatFileItemReader into multiple lines while writing 如何在Spring Batch中使用不同的文件名多次调用FlatFileItemReader? - How do I call FlatFileItemReader multiple times with different file names in Spring Batch? 使用FlatFileItemReader读取一个csv文件,遇到空列抛出异常 - Read a csv file using FlatFileItemReader, throwing an exception when encountering an empty column Spring 批处理 FlatFileItemReader 令牌错误 - Spring batch FlatFileItemReader token error
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM