Spring Batch如何避免IllegalStateException:输入资源必须存在
解决方案
要实现输入文件缺失时不终止批处理且生成指定输出文件的需求,可以通过流程分支判断+专用处理步骤来实现,具体如下:
1. 新增文件存在性判断决策器
创建JobExecutionDecider实现类,用于在作业启动前判断输入文件是否存在,以此决定后续执行的流程:
@Component public class InputFileDecider implements JobExecutionDecider { @Value("${inputFolder}") // 注入配置的输入文件夹路径 private String inputFolder; @Override public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) { File inputFile = new File(inputFolder.concat(File.separator).concat("my-input-file.csv")); boolean isFileValid = inputFile.exists() && inputFile.isFile(); return isFileValid ? new FlowExecutionStatus("FILE_EXISTS") : new FlowExecutionStatus("FILE_MISSING"); } }
2. 定义两种流程的Step
2.1 正常处理Step(文件存在时执行)
保留你原有的reader、processor和writer配置,构建标准的读-处理-写Step:
@Bean public Step normalStep(StepBuilderFactory stepBuilderFactory, FlatFileItemReader<MyClass> reader, ItemProcessor<MyClass, MyClass> processor, FlatFileItemWriter<MyClass> normalOutputWriter) { return stepBuilderFactory.get("normalStep") .<MyClass, MyClass>chunk(100) // 根据实际需求调整chunk大小 .reader(reader) .processor(processor) .writer(normalOutputWriter) .build(); } // 正常输出文件的Writer @Bean public FlatFileItemWriter<MyClass> normalOutputWriter(@Value("${outputFolder}") String outputFolder) { return new FlatFileItemWriterBuilder<MyClass>() .name("normalOutputWriter") .resource(new FileSystemResource(outputFolder.concat(File.separator).concat("normal-output.csv"))) .delimited() .names("field1", "field2") .build(); }
2.2 文件缺失处理Step(文件不存在时执行)
创建一个TaskletStep,专门用于生成文件缺失时的输出文件:
@Bean public Step noInputStep(StepBuilderFactory stepBuilderFactory, @Value("${outputFolder}") String outputFolder) { return stepBuilderFactory.get("noInputStep") .tasklet((contribution, chunkContext) -> { String outputPath = outputFolder.concat(File.separator).concat("no-input-output.csv"); File outputFile = new File(outputPath); // 写入自定义内容(比如表头+提示信息) try (PrintWriter writer = new PrintWriter(outputFile)) { writer.println("field1,field2"); writer.println("无输入数据,无输入数据"); } catch (FileNotFoundException e) { throw new RuntimeException("生成无输入输出文件失败", e); } return RepeatStatus.FINISHED; }) .build(); }
3. 配置Job的流程分支
将决策器和两个Step整合到Job中,实现分支逻辑:
@Bean public Job batchJob(JobBuilderFactory jobBuilderFactory, Step normalStep, Step noInputStep, InputFileDecider inputFileDecider) { return jobBuilderFactory.get("batchJob") .start(inputFileDecider) .on("FILE_EXISTS").to(normalStep) // 文件存在时执行正常处理流程 .on("FILE_MISSING").to(noInputStep) // 文件缺失时执行专用生成流程 .end() .build(); }
4. 保留原Reader的Strict模式(可选)
由于决策器已经确保只有文件存在时才会执行normalStep,你原有的reader可以保留strict模式(默认开启),这样如果正常流程中文件意外丢失,会及时抛出异常,避免静默处理带来的风险:
@SuppressWarnings("unchecked") @Bean public FlatFileItemReader<MyClass> reader(@Value("${inputFolder}") String inputFolder) { BeanWrapperFieldSetMapper beanWrapperMapper = new BeanWrapperFieldSetMapper<MyClass>(); beanWrapperMapper.setTargetType(MyClass.class); return new FlatFileItemReaderBuilder<MyClass>() .name("MyClassReader") .resource(new FileSystemResource(inputFolder.concat(File.separator).concat("my-input-file.csv"))) .delimited() .names("field1", "field2") .fieldSetMapper(beanWrapperMapper) // 无需修改strict模式,默认true,确保正常流程中文件必须存在 .build(); }
工作流程说明
- 作业启动后,首先通过
InputFileDecider判断输入文件是否存在; - 若文件存在,执行正常的读-处理-写Step,生成常规输出文件;
- 若文件缺失,直接执行
noInputStep,生成指定的无输入提示文件; - 两种流程都会正常结束批处理,不会因文件缺失抛出异常。
内容的提问来源于stack exchange,提问作者wishyouwerehere
相关产品推荐
相关产品推荐

