java - 将 Spring Batch Tasklet 失败消息传递给报告步骤。

标签 java spring spring-boot spring-batch

我正在使用带有 OpenCSV 的 Spring Batch Tasklet 来读取我的 CSV 文件。在问这个问题之前,我知道 block ,但是在后面的步骤中文件之间有交叉验证,所以我必须继续使用 Tasklet。

我正在尝试做的是向我的报告步骤报告丢失的文件或解析错误。我不确定向我的下一步报告失败的正确方法应该是什么。我有以下代码。

读取文件的初始步骤。

public class CsvBatchReader<T> implements Tasklet, StepExecutionListener {

    private final Logger logger = LoggerFactory.getLogger(CsvBatchReader.class);

    private List batch;

    private final Class<T> clazz;

    private Path path;

    public CsvBatchReader(Class<T> clazz, Path path) {
        this.clazz = clazz;
        this.path = path;
    }

    @Override
    public void beforeStep(StepExecution stepExecution) {
        logger.info("Reader initialized - " + clazz.getSimpleName());

        batch = new ArrayList();
    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        logger.info("Reader ended - " + clazz.getSimpleName());
        return ExitStatus.COMPLETED;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws UnexpectedJobExecutionException {
        logger.info("Reader execute - " + clazz.getSimpleName());


        ICsvToBean csvToBean = new CsvToBean(clazz, path);

        try {
            batch = csvToBean.readCsv();
        } catch(IOException ex) {
            // error message being caught from my csvToBean class. 
            throw new UnexpectedJobExecutionException("Invalid file " + ex.getMessage());
        }

        return RepeatStatus.FINISHED;
    }

}

报告步骤

我不确定如何传递异常消息,或者是否有定义的方法在不使用步骤执行上下文的情况下传递失败消息。

public class CsvBatchReporting implements Tasklet, StepExecutionListener {

    private final Logger logger = LoggerFactory.getLogger(CsvBatchCrossValidation.class);

    private List errorMessages;
    private List skippedInserts;

    @Override
    public void beforeStep(StepExecution stepExecution) {
        logger.info("Reporting initialized");

        ExecutionContext executionContext = stepExecution
                .getJobExecution()
                .getExecutionContext();

        System.out.println("description " + stepExecution.getStatus());


    }

    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        logger.info("Reporting ended");
        return ExitStatus.COMPLETED;
    }

    @Override
    public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        logger.info("Reporting execute");

        //Email Error 

        return RepeatStatus.FINISHED;
    }

}

作业配置

@Bean
public Job primaryCareJob(@Qualifier("reportingStep") Step reportingStep, @Qualifier("crossValidationStep") Step crossValidationStep) {
    logger.info("Start PrimaryCare Job");

    return jobs.get("primaryCareJob")
            .start(readPrimaryCareStep()).on("FAILED").to(reportingStep)
            .from(readPrimaryCareStep()).on("*").to(readPrimaryCareDetailStep())

            .from(readPrimaryCareDetailStep()).on("FAILED").to(reportingStep)
            .from(readPrimaryCareDetailStep()).on("*").to(processPrimaryCareStep())

            .from(processPrimaryCareStep()).on("INVALID").to(reportingStep)
            .from(processPrimaryCareStep()).on("*").to(processPrimaryCareDetailStep())

            .from(processPrimaryCareDetailStep()).on("INVALID").to(reportingStep)
            //Other steps

            .from(reportingStep).on("*").end()
            .from(reportingStep).on("*").fail()

            .build()
        .build();
}

我开始将我的作业模式更改为失败,而不是将其定义为无效以获取异常以自动调用失败的步骤。我使用无效的其他步骤正在使用以下代码在我的 afterStep 中定义。

if(!errorMessages.isEmpty()) {
            chunkContext.getStepContext().getStepExecution().setExitStatus(new ExitStatus("INVALID"));
}

如何从阅读器获取 CSV 异常消息以将其传递到我的报告步骤,以便我可以将其作为电子邮件发送?

最佳答案

I'm not sure how to pass in the exception message or if there is defined method to passing in the failure message without using the Step Execution Context.

您可以访问作业执行中上一步抛出的异常。这是一个例子:

import java.util.List;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
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 MyJob {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Bean
    public Step step1() {
        return steps.get("step1")
                .tasklet((contribution, chunkContext) -> {
                    System.out.println("hello");
                    throw new Exception("Boom!");
                })
                .build();
    }

    @Bean
    public Step step2() {
        return steps.get("step2")
                .tasklet((contribution, chunkContext) -> {
                    JobExecution jobExecution = chunkContext.getStepContext().getStepExecution().getJobExecution();
                    StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next(); // TODO properly get the stepExecution of the previous step
                    List<Throwable> failureExceptions = stepExecution.getFailureExceptions();
                    if (!failureExceptions.isEmpty()) {
                        Throwable throwable = failureExceptions.get(0);
                        System.out.println("Looks like step1 has thrown an exception: " + throwable.getMessage());
                    }
                    System.out.println("world");
                    return RepeatStatus.FINISHED;
                })
                .build();
    }

    @Bean
    public Job job() {
        return jobs.get("job")
                    .flow(step1())
                    .on("*").to(step2())
                    .build()
                .build();
    }

    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());
    }

}

此示例打印:

hello
Looks like step1 has thrown an exception: Boom!
world

显然,您需要确保在所有情况下 step1 都流向 step2(因此有流定义)。

希望这对您有所帮助。

关于java - 将 Spring Batch Tasklet 失败消息传递给报告步骤。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52408082/

相关文章:

java - 如何在 Spring JDBCTemplate 中正确使用准备好的语句?

spring - 如何使用 Kotlin 在 Spring Test 类中注入(inject)服务组件?

javascript - 为什么 Cesium 查看器在我添加时不显示模型?

java - 如何将 JsonString 转换为 String?

java - 存储和显示 ₹(卢比符号)html (xslt) -> java -> Sql Server 2016

java - 如何在 Eclipse 中设置主要 Java 类型?

java - Tomcat 7 受限 (ContainerServlet) 错误

java - 基于java的配置中的Spring导入

spring - 无法连接到本地 Spring boot 中 docker 上运行的 redis sentinel

java - App Engine - 如何将 JSON 传递到队列