Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Springboot批量读取/验证多个不同格式的csv文件_Java_Spring_Spring Boot_Spring Batch - Fatal编程技术网

Java Springboot批量读取/验证多个不同格式的csv文件

Java Springboot批量读取/验证多个不同格式的csv文件,java,spring,spring-boot,spring-batch,Java,Spring,Spring Boot,Spring Batch,我正在评估一个特定项目的springbatch,在网上搜索了很多之后,我还没有找到一个满足我需求的springbatch解决方案 我想知道SpringBatch是否能够在一个作业中读取由不同格式组成的多个CSV文件?例如,假设Person.csv和Address.csv都由不同的格式组成,但相互依赖 我需要阅读、处理数据更正(如toUpperCase等),并验证每个记录 如果出现验证错误,我需要将错误记录到某种类型的对象数组中,在验证完成后,该数组将在稍后提供,并通过电子邮件发送给最终用户进行更

我正在评估一个特定项目的springbatch,在网上搜索了很多之后,我还没有找到一个满足我需求的springbatch解决方案

我想知道SpringBatch是否能够在一个作业中读取由不同格式组成的多个CSV文件?例如,假设Person.csv和Address.csv都由不同的格式组成,但相互依赖

我需要阅读、处理数据更正(如toUpperCase等),并验证每个记录

如果出现验证错误,我需要将错误记录到某种类型的对象数组中,在验证完成后,该数组将在稍后提供,并通过电子邮件发送给最终用户进行更正

一旦两个文件中的所有数据都已验证,并且两个文件中均未发生验证错误,请继续使用批处理编写器。如果两个文件中的任何一个出现错误,我需要停止整个作业。如果写入程序在发生错误时已开始写入数据库,则无论错误是否存在于相反的文件中,都需要回滚整个作业

如果两个CSV文件中的任何一个存在任何类型的验证错误,我将无法插入其中任何一个。必须将错误通知最终用户。这些错误将用于在重新处理文件之前进行任何必要的更正

SpringBoot 2中的Spring批处理是否能够实现这种行为

示例

Person.csv

BatchId, personId, firstName, lastName
Address.csv

BatchId, personId, address1
在上面的示例中,两个文件之间的关系是batchId和personId。如果两个文件中的任何一个存在任何类型的验证错误,我必须使整个批处理失败。我想完成对这两个文件的验证,这样我就可以对所有错误做出响应,但不能写入数据库

我想知道SpringBatch是否能够在一个作业中读取由不同格式组成的多个CSV文件

是的,您可以有一个包含多个步骤的单个作业,每个步骤处理给定类型的文件。关键是如何设计作业。可以应用的一种技术是使用暂存表。批处理作业可以创建临时暂存表,在其中加载所需的所有数据,然后在完成后将其删除

在您的情况下,可以通过两个步骤将每个文件加载到特定的暂存表中。每个步骤都可以应用特定于每个文件的验证逻辑。如果这些步骤中有一个失败了,那么你的工作就失败了。暂存表可以有一个无效记录的标记列(这对于报告很有用)

完成这两个准备步骤后,您可以在另一个步骤中从两个暂存表读取数据,并对连接的数据应用交叉验证规则(例如,从两个表中选择并通过
BatchId
PersonId
)连接)。如果此步骤失败,则表示作业失败。否则,您将在适当的位置写入数据

这种技术的优点是,在整个作业期间,数据可以在临时表中使用。因此,每当验证步骤失败时,可以使用流将失败的步骤重定向到“报告步骤”(读取无效数据并发送报告),然后使作业失败。下面是一个您可以使用的独立示例:

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
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.launch.JobLauncher;
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;

@Configuration
@EnableBatchProcessing
public class FlowJobSample {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public Step personLoadingStep() {
        return steps.get("personLoadingStep")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("personLoadingStep");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step addressLoadingStep() {
        return steps.get("addressLoadingStep")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("addressLoadingStep");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step crossValidationStep() {
        return steps.get("crossValidationStep")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("crossValidationStep");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Step reportingStep() {
        return steps.get("reportingStep")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("reportingStep");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                .start(personLoadingStep()).on("INVALID").to(reportingStep())
                    .from(personLoadingStep()).on("*").to(addressLoadingStep())
                    .from(addressLoadingStep()).on("INVALID").to(reportingStep())
                    .from(addressLoadingStep()).on("*").to(crossValidationStep())
                    .from(crossValidationStep()).on("INVALID").to(reportingStep())
                    .from(crossValidationStep()).on("*").end()
                    .from(reportingStep()).on("*").fail()
                    .build()
                .build();
    }

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

}
要使其中一个步骤失败,请将退出状态设置为无效,例如:

@Bean
public Step personLoadingStep() {
    return steps.get("personLoadingStep")
            .tasklet((contribution, chunkContext) -> {
                System.out.println("personLoadingStep");
                chunkContext.getStepContext().getStepExecution().setExitStatus(new ExitStatus("INVALID"));
                return RepeatStatus.FINISHED;
            })
            .build();
}

我希望这能有所帮助。

文件之间如何相互依赖?你能显示一些记录以及域模型来查看它们之间的关系吗?@MahmoudBenHassine当然,我在上面提供了一个CSV示例,其中address.CSV包含personId和batchId,必须包含在person.CSV中。如果有如此多的必填字段,如名字或地址,我必须使整个批处理失败,并回滚任何db提交。感谢澄清,我添加了一个带有示例的答案。希望有帮助。顺便说一句,如果由我决定,作业将在linux/unix操作系统上运行,我将通过
BatchId
PersonId
SystemCommandTasklet
中使用
join
命令加入文件。这将极大地简化作业的设计。非常感谢,我实际上已经开始考虑这一点,但是有了临时文件,我更喜欢你的临时表想法。谢谢你的例子。您能否详细介绍SystemCommandTasklet,以及它将如何简化作业的设计?这是一个新项目,我可以自由做出任何最合适的设计决策。ThanksA第一步是执行命令的
SystemCommandTasklet
join person.csv address.csv
(您需要查看join的选项)。其思想是,
SystemCommandTasklet
是一个准备步骤,它输出一个格式为:
BatchId、personId、firstName、lastName、address
的文件。然后,您可以执行第二个面向块的步骤,读取此文件并将其映射到域对象
Person
,该域对象拥有应用验证规则所需的一切(在处理器中实现)。这样,您只有两个步骤,不需要使用暂存表。