Spring Batch中带@StepScope的PoiItemReader无法读取Excel文件求助
问题分析与解决方案
你遇到的问题其实是几个小细节的疏漏凑到了一起,咱们一步步拆解解决:
1. SpEL表达式语法错误
先看你excelStudentReader方法里的@Value注解:
@Value("# {jobParameters[filePath]}") String filePath
这里#和{之间多了个空格!SpEL表达式对格式要求很严格,这个空格会导致Spring无法正确解析JobParameter,最终filePath会是null,PoiItemReader找不到文件,任务自然直接结束。
修正成:
@Value("#{jobParameters[filePath]}") String filePath
2. Step中Reader的引用方式错误
在step1()方法里,你直接调用excelStudentReader(null)获取Reader实例,这完全违背了@StepScope的设计——带@StepScope的Bean是延迟初始化的,必须由Spring通过代理创建,不能手动传null调用方法。
正确做法是让Spring自动注入Reader:
@Bean public Step step1(ItemReader<StudentDTO> excelStudentReader) { return stepBuilderFactory.get("step1") .<StudentDTO, StudentDTO> chunk(10) .reader(excelStudentReader) .writer(writer()) .build(); }
3. 应用上下文重复创建的问题
你的Application类main方法里,先调用SpringApplication.run,又手动创建AnnotationConfigApplicationContext,这会生成两个独立的Spring上下文,JobLauncher和Job不在同一个上下文里,参数传递必然出问题。
改成只创建一次上下文:
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class}) @Import(BatchConfiguration.class) // 导入批处理配置类 public class Application { public static void main(String[] args) throws Exception { ApplicationContext context = SpringApplication.run(Application.class, args); try { JobParameters param = new JobParametersBuilder() .addString("filePath", "files/sample-data.xlsx") .addLong("time", System.currentTimeMillis()) .toJobParameters(); JobLauncher jobLauncher = context.getBean(JobLauncher.class); Job job = context.getBean("importUserJob", Job.class); jobLauncher.run(job, param); } catch (Exception e) { e.printStackTrace(); } } }
4. 额外小细节:Writer的Bean注解遗漏
你的writer()方法没有加@Bean注解,Spring无法将其识别为可注入的Bean,虽然当前代码能运行,但不符合Spring的规范,也可能引发潜在问题,补上:
@Bean public CustomWriter writer() { return new CustomWriter(); }
修正后的核心代码示例
BatchConfiguration.java
@Configuration @EnableBatchProcessing public class BatchConfiguration { @Autowired public JobBuilderFactory jobBuilderFactory; @Autowired public StepBuilderFactory stepBuilderFactory; @StepScope @Bean ItemReader<StudentDTO> excelStudentReader(@Value("#{jobParameters[filePath]}") String filePath) { PoiItemReader<StudentDTO> reader = new PoiItemReader<>(); reader.setResource(new ClassPathResource(filePath)); reader.setLinesToSkip(1); reader.setRowMapper(new StudentExcelRowMapper()); return reader; } @Bean public CustomWriter writer() { return new CustomWriter(); } @Bean public Job importUserJob() { return jobBuilderFactory.get("importUserJob") .incrementer(new RunIdIncrementer()) .flow(step1()) .end() .build(); } @Bean public Step step1(ItemReader<StudentDTO> excelStudentReader, CustomWriter writer) { return stepBuilderFactory.get("step1") .<StudentDTO, StudentDTO> chunk(10) .reader(excelStudentReader) .writer(writer) .build(); } }
Application.java
@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class,HibernateJpaAutoConfiguration.class}) @Import(BatchConfiguration.class) public class Application { public static void main(String[] args) throws Exception { ApplicationContext context = SpringApplication.run(Application.class, args); try { JobParameters param = new JobParametersBuilder() .addString("filePath", "files/sample-data.xlsx") .addLong("time", System.currentTimeMillis()) .toJobParameters(); JobLauncher jobLauncher = context.getBean(JobLauncher.class); Job job = context.getBean("importUserJob", Job.class); jobLauncher.run(job, param); } catch (Exception e) { e.printStackTrace(); } } }
做完这些修改后,PoiItemReader就能正确读取通过JobParameter传递的Excel文件了。
内容的提问来源于stack exchange,提问作者Benny
相关产品推荐
相关产品推荐

