当前位置: 首页 > 知识库问答 >
问题:

Spring批处理:未读取文件

施越彬
2023-03-14

我正在尝试创建一个应用程序,该应用程序使用spring-batch-excel扩展名来读取用户通过web界面上传的Excel文件,以便解析Excel文件中的地址。

代码运行时,没有错误,但我得到的只是我日志中的以下内容。即使我的处理器和Writer中都有log/syso(它们从未被调用过,我所能想象的是它没有正确读取文件,也没有返回要处理/写入的数据)。是的,这个文件有数据,实际上有几千条记录。

Job: [FlowJob: [name=excelFileJob]] launched with the following parameters: [{file=Book1.xlsx}]
Executing step: [excelFileStep]
Job: [FlowJob: [name=excelFileJob]] completed with the following parameters: [{file=Book1.xlsx}] and the following status: [COMPLETED]
@Configuration
@EnableBatchProcessing
public class AddressExcelJobConfig {

    @Bean
    public BatchConfigurer configurer(EntityManagerFactory entityManagerFactory) {
        return new CustomBatchConfigurer(entityManagerFactory);
    }

    @Bean
    Step excelFileStep(ItemReader<AddressExcel> excelAddressReader,
                       ItemProcessor<AddressExcel, AddressExcel> excelAddressProcessor,
                       ItemWriter<AddressExcel> excelAddressWriter, 
                       StepBuilderFactory stepBuilderFactory) {
        return stepBuilderFactory.get("excelFileStep")
                .<AddressExcel, AddressExcel>chunk(1)
                .reader(excelAddressReader)
                .processor(excelAddressProcessor)
                .writer(excelAddressWriter)
                .build();
    }

    @Bean
    Job excelFileJob(JobBuilderFactory jobBuilderFactory, 
                     @Qualifier("excelFileStep") Step excelAddressStep) {
        return jobBuilderFactory.get("excelFileJob")
                .incrementer(new RunIdIncrementer())
                .flow(excelAddressStep)
                .end()
                .build();
    }
}

下面是我的AddressExcelReader的后期装订工作很好,没有错误。除了创建新的ClassPathResource和FileSystemResource之外,我还尝试加载给定文件名的资源。都给了我同样的结果。

@Component
@StepScope
public class AddressExcelReader implements ItemReader<AddressExcel> {

    private PoiItemReader<AddressExcel> itemReader = new PoiItemReader<AddressExcel>();

    @Override
    public AddressExcel read()
            throws Exception, UnexpectedInputException, ParseException, NonTransientResourceException {
        return itemReader.read();
    }

    public AddressExcelReader(@Value("#{jobParameters['file']}") String file, StorageService storageService) {
        //Resource resource = storageService.loadAsResource(file);
        //Resource testResource = new FileSystemResource("upload-dir/Book1.xlsx");
        itemReader.setResource(new ClassPathResource("/upload-dir/Book1.xlsx"));
        itemReader.setLinesToSkip(1);
        itemReader.setStrict(true);
        itemReader.setRowMapper(excelRowMapper());
    }

    public RowMapper<AddressExcel> excelRowMapper() {
        BeanWrapperRowMapper<AddressExcel> rowMapper = new BeanWrapperRowMapper<>();
        rowMapper.setTargetType(AddressExcel.class);
        return rowMapper;
    }

}

下面是我的地址ExcelProcessor

@Component
public class AddressExcelProcessor implements ItemProcessor<AddressExcel, AddressExcel> {

    private static final Logger log = LoggerFactory.getLogger(AddressExcelProcessor.class);

    @Override
    public AddressExcel process(AddressExcel item) throws Exception {
        System.out.println("Converting " + item);
        log.info("Convert {}", item);
        return item;
    }

}

同样,这一点从未发挥作用(没有生成日志)。如果重要的话,这就是我从@PostMapping(“/”)的FileUploadController启动作业的方式,以处理文件上载,首先存储文件,然后运行作业:

@PostMapping("/")
public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) {

    storageService.store(file);

    try {
        JobParameters jobParameters = new JobParametersBuilder()
                .addString("file", file.getOriginalFilename().toString()).toJobParameters();
        jobLauncher.run(job, jobParameters);
    } catch (JobExecutionAlreadyRunningException | JobRestartException | JobInstanceAlreadyCompleteException
            | JobParametersInvalidException e) {
        e.printStackTrace();
    }

    redirectAttributes.addFlashAttribute("message",
            "You successfully uploaded " + file.getOriginalFilename() + "!");

    return "redirect:/";
}
import lombok.Data;

@Data
public class AddressExcel {

    private String address1;
    private String address2;
    private String city;
    private String state;
    private String zip;

    public AddressExcel() {}

}

更新(10/13/2016)根据Nghia Do的评论,我还创建了自己的RowMapper,而不是使用BeanWrapper来查看这是否是问题所在。结果还是一样。

public class AddressExcelRowMapper implements RowMapper<AddressExcel> {

    @Override
    public AddressExcel mapRow(RowSet rs) throws Exception {
        AddressExcel temp = new AddressExcel();

        temp.setAddress1(rs.getColumnValue(0));
        temp.setAddress2(rs.getColumnValue(1));
        temp.setCity(rs.getColumnValue(2));
        temp.setState(rs.getColumnValue(3));
        temp.setZip(rs.getColumnValue(4));

        return temp;
    }

}

共有1个答案

闽哲
2023-03-14

看来我所需要的只是在我的ItemReader中添加以下内容:

itemReader.afterPropertiesSet();
itemReader.open(new ExecutionContext());
 类似资料:
  • 我正在使用JpaPagingItemReaderBuilder查询一个DB,结果被插入到另一个DB中。 查询返回的结果没有任何问题,但我得到了一个错误与读取器的返回,在处理器中,您可以检查我的编码和错误下面。 有谁能给我一点启示吗?为什么我不能处理结果?

  • 我知道匹配模式解析器,这是Spring批处理提供的。我需要关于如何构造批处理作业的帮助,以便它可以读取循环中的记录类型5和记录类型6。

  • 我需要从多个目录中读取文件,并处理数据并将其存储到DB中。目前我正在使用块多资源阅读器,它适用于1个目录。但现在我必须从多个目录中读取文件。如何使用Spring批处理来做到这一点

  • 我有一个批处理步骤 读取器和处理器流程如何工作?读取器是读取块并等待处理器处理它,还是一次读取所有块。

  • 在Spring批处理中,我试图读取CSV文件,并希望将每一行分配给一个单独的线程并对其进行处理。我试图通过使用TaskExecutor来实现它,但所有线程都在一次拾取同一行。我还尝试使用Partioner实现这个概念,同样的事情也发生了。请参阅下面我的配置Xml。 步骤说明 我尝试过不同类型的任务执行器,但它们的行为方式都是一样的。如何将每一行分配给单独的线程?