从 spring 批处理 itemReader 中的流而不是文件读取

Reading from streams instead of files in spring batch itemReader

我收到一个 csv 文件作为网络服务调用,需要加载。现在我将它保存在临时目录中以将其作为 setResource 提供给 Reader.

有没有办法按原样提供 stream(byte[]) 而不是先保存文件?

ItemReader 的方法setResourceorg.springframework.core.io.Resource 作为参数。 class 有一些开箱即用的实现,您可以在其中找到 org.springframework.core.io.InputStreamResource。这个 class' 构造函数采用 java.io.InputStream 可以由 java.io.ByteArrayInputStream 实现。

所以从技术上讲,是的,您可以在 ItemReader.

中使用 byte[] 参数

现在,关于如何实际做到这一点,这里有一些想法:

1) 创建您自己的 FlatFileItemReader(因为 CSV 是平面文件)并使其实现 StepExecutionListener

public class CustomFlatFileItemReader<T> extends FlatFileItemReader<T> implements StepExecutionListener {
}

2) 覆盖 beforeStep 方法,在其中执行您的网络服务调用并将结果保存在变量中

private byte[] stream;

@Override
public void beforeStep(StepExecution stepExecution) {

     // your webservice logic
     stream = yourWebservice.results();

}

3) 覆盖 setResource 方法以将此 stream 作为实际资源传递。

@Override
public void setResource(Resource resource) {

    // Convert byte array to input stream
    InputStream is = new ByteArrayInputStream(stream);

    // Create springbatch input stream resource
    InputStreamResource res = new InputStreamResource(is);

    // Set resource
    super.setResource(res);
}

此外,如果您不想在 ItemReader 中调用您的网络服务,您可以简单地将字节数组存储在 JobExecutionContext 中,然后在 beforeStep 方法中使用 stepExecution.getJobExecution().getExecutionContext().get("key");

我现在正在使用 FlatFileItemReader,从 Google 存储中读取文件。无需扩展:

    @Bean
@StepScope
public FlatFileItemReader<MyDTO> itemReader(@Value("#{jobParameters['filename']}") String filename) {
    
    InputStream stream = googleStorageService.getInputStream(GoogleStorage.UPLOADS, filename);
    
    return new FlatFileItemReaderBuilder<MyDTO>()
            .name("myItemReader")
            .resource(new InputStreamResource(stream)) //InputStream here
            .delimited()
            .names(FIELDS)
            .lineMapper(lineMapper()) // Here is mapped like a normal File
            .fieldSetMapper(new BeanWrapperFieldSetMapper<MyDTO>() {{
                setTargetType(MyDTO.class);
            }})
            .build();
}