问题很简单:如何将ItemReader
内只知道的值(例如当前文件名)传递给ItemProcessor
?
@Bean
@JobScope
public ItemReader<String> reader(@Value("#{jobParameters['path]}") String path) {
FlatFileItemReader<String> delegate = new FlatFileItemReader<>();
delegate.setLineMapper(new PassThroughLineMapper());
Resource[] res = new PathMatchingResourcePatternResolver().getResources("file:" + path);
MultiResourceItemReader<String> r = new MultiResourceItemReader<>();
r.setResources(res);
r.setDelegate(delegate);
return r;
}
@Bean
public ItemProcessor<String, String> processor() {
return new ItemProcessor<String, String>() {
@Override
public String process(String item) throws Exception {
//TODO I need the filename that is currently processed. HOW?
return null;
}
};
}
答案 0 :(得分:1)
为了安全起见,您应该将文件名添加到阅读器返回的对象中。为此,您必须实现自己的包装器Reader。像这样:
public class MyReader {
private MultiResourceItemReader delegatereader;
public MyContainerDto read() {
String line = delegatereader.read();
if (line==null) return null;
Resource currentResource = delegatereader.getCurrentResource();
MyContainerDto container = MyContainerDto();
container.setLine(line);
container.setResourceName(currentResource.getFileName());
return container;
}
...
}
(此代码未经过测试,只是说明了我将采取的方法)
在我的笔记本电脑上,我能够在一秒钟内创建100万个对象,因此创建对象所需的额外性能并不会影响整体性能。
问题是,读者读取的数量与chunksize定义的数量相同。之后,它会为处理器中的每个项目调用处理器。因此,在一个块中,其中的项可能已从不同的文件中读取。因此,除了在阅读器中将行和文件名绑定在一起之外别无他法。
另见https://blog.codecentric.de/en/2012/03/transactions-in-spring-batch-part-1-the-basics/
答案 1 :(得分:0)
最好为读者介绍一个dto。
public class ResourceAwareString implements ResourceAware {
private String content;
private Resource res;
@Override
public void setResource(Resource res) {
this.res = res;
}
}
然后MultiResourceItemReader<ResourceAwareString>
将自动检测到它并将资源写入dto。
其他方法是同时制作ItemReader
和ItemProcessor
@StepScope
并使用@BeforeStep
来访问当前的StepExection
上下文。然后就可以设置/获取一个值,从而将值从读取器传输到处理器,甚至传输到编写器。
请注意@BeforeStep
仅适用于公共类,而不适用于匿名方法:
new FlatFileItemReader<String>() {
@BeforeStep
public void before(StepExecution stepEx) {
//this will never be called! don't do this.
}
};