【问题标题】:Saving file information in Spring batch MultiResourceItemReader在 Spring 批处理 MultiResourceItemReader 中保存文件信息
【发布时间】:2020-03-17 19:43:03
【问题描述】:

我有一个包含文本文件的目录。我想处理文件并将数据写入数据库。我通过使用MultiResourceItemReader 做到了这一点。

我有一个场景,比如每当文件到来时,第一步是在日志表(自定义表)中保存文件信息,如文件名、文件中的记录计数。

由于我使用MultiResourceItemReader,它只加载一次所有文件,并且我编写的代码在服务器启动时执行一次。我尝试使用 getCurrentResource() 方法,但它返回 null。

请参考以下代码。

NetFileProcessController.java

@Slf4j
@RestController
@RequestMapping("/netProcess")
public class NetFileProcessController {

    @Autowired
    private JobLauncher jobLauncher;

    @Autowired
    @Qualifier("netFileParseJob")
    private Job job;

    @GetMapping(path = "/process")
    public @ResponseBody StatusResponse process() throws ServiceException {
        try {
            Map<String, JobParameter> parameters = new HashMap<>();
            parameters.put("date", new JobParameter(new Date()));

            jobLauncher.run(job, new JobParameters(parameters));
            return new StatusResponse(true);

        } catch (Exception e) {
            log.error("Exception", e);
            Throwable rootException = ExceptionUtils.getRootCause(e);
            String errMessage = rootException.getMessage();
            log.info("Root cause is instance of JobInstanceAlreadyCompleteException --> "+(rootException instanceof JobInstanceAlreadyCompleteException));
            if(rootException instanceof JobInstanceAlreadyCompleteException){
                log.info(errMessage);
                return new StatusResponse(false, "This job has been completed already!");
            } else{
                throw new ServiceException(errMessage);
            }
        }
    }
}

BatchConfig.java

@Configuration
@EnableBatchProcessing
public class BatchConfig {

    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    public void setJobBuilderFactory(JobBuilderFactory jobBuilderFactory) {
        this.jobBuilderFactory = jobBuilderFactory;
    }

    @Autowired
    StepBuilderFactory stepBuilderFactory;

    @Value("file:${input.files.location}${input.file.pattern}")
    private Resource[] netFileInputs;

    @Value("${net.file.column.names}")
    private String netFilecolumnNames;

    @Value("${net.file.column.lengths}")
    private String netFileColumnLengths;


    @Autowired
    NetFileInfoTasklet netFileInfoTasklet;

    @Autowired
    NetFlatFileProcessor netFlatFileProcessor;

    @Autowired
    NetFlatFileWriter netFlatFileWriter;

    @Bean
    public Job netFileParseJob() {
        return jobBuilderFactory.get("netFileParseJob")
                .incrementer(new RunIdIncrementer())
                .start(netFileStep())
                .build();
    }

    public Step netFileStep() {
        return stepBuilderFactory.get("netFileStep")
                .<NetDetailsDTO, NetDetailsDTO>chunk(1)
                .reader(new NetFlatFileReader(netFileInputs, netFilecolumnNames, netFileColumnLengths))
                .processor(netFlatFileProcessor)
                .writer(netFlatFileWriter)
                .build();
    }

}

NetFlatFileReader.java

    @Slf4j
    public class NetFlatFileReader extends MultiResourceItemReader<NetDetailsDTO> {

        public netFlatFileReader(Resource[] netFileInputs, String netFilecolumnNames, String netFileColumnLengths) {
            setResources(netFileInputs);
            setDelegate(reader(netFilecolumnNames, netFileColumnLengths));
        }

        private FlatFileItemReader<NetDetailsDTO> reader(String netFilecolumnNames, String netFileColumnLengths) {
            FlatFileItemReader<NetDetailsDTO> flatFileItemReader = new FlatFileItemReader<>();
            FixedLengthTokenizer tokenizer = CommonUtil.fixedLengthTokenizer(netFilecolumnNames, netFileColumnLengths);
            FieldSetMapper<NetDetailsDTO> mapper = createMapper();
            DefaultLineMapper<NetDetailsDTO> lineMapper = new DefaultLineMapper<>();
            lineMapper.setLineTokenizer(tokenizer);
            lineMapper.setFieldSetMapper(mapper);
            flatFileItemReader.setLineMapper(lineMapper);
            return flatFileItemReader;
        }

        /*
         * Mapping column data to DTO
        */
        private FieldSetMapper<NetDetailsDTO> createMapper() {
            BeanWrapperFieldSetMapper<NetDetailsDTO> mapper = new BeanWrapperFieldSetMapper<>();
            try {
                mapper.setTargetType(NetDetailsDTO.class);
            } catch(Exception e) {
                log.error("Exception in mapping column data to dto ", e);
            }
            return mapper;
        }

    }

我被困在这种情况下,感谢任何帮助

【问题讨论】:

    标签: spring spring-batch batch-processing


    【解决方案1】:

    我认为MultiResourceItemReader 不适合您的情况。出于让一件事做一件事并做好的所有原因,我会为每个文件运行一个作业:

    • 您的准备​​步骤将按设计进行
    • 并行运行多个作业并提高文件摄取吞吐量会更容易
    • 万一失败,您只需为失败的文件重新启动作业

    编辑:添加示例

    Resource[] netFileInputs = ... // same code that looks for file as currently in your reader
    for (Resource netFileInput : netFileInputs) {
        Map<String, JobParameter> parameters = new HashMap<>();
        parameters.put("netFileInput", new JobParameter(netFileInput.getFilename()));
    
        jobLauncher.run(job, new JobParameters(parameters));
    }
    

    【讨论】:

    • 感谢您的回答@Mahmoud Ben Hassine,即使我也这么认为,但如果我有 10 个相同格式的文件,最好将作业写入每个文件
    • 是的,您将拥有一个作业定义和 10 个作业实例。文件的数量真的不是问题(即使你有很多文件),这就是我将使用的方式,原因是上述原因。
    • 就我而言,文件名并不总是相同。这些可能会有所不同。因为,文件从第三方接收并放置在目录中
    • 这不是问题(文件总是有不同的名称),文件名应该是创建不同作业实例的作业参数。
    • 请编辑您的问题并添加您用于启动作业的代码,我将通过示例相应地编辑答案。
    猜你喜欢
    • 2016-01-11
    • 2020-11-08
    • 1970-01-01
    • 1970-01-01
    • 2021-05-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多