我需要从数据库中获取数据,并根据数据库中给出的文件名将数据写入文件。
这是数据库中数据的定义方式:
Columns --> FILE_NAME, REC_ID, NAME
Data --> file_1.csv, 1, ABC
Data --> file_1.csv, 2, BCD
Data --> file_1.csv, 3, DEF
Data --> file_2.csv, 4, FGH
Data --> file_2.csv, 5, DEF
Data --> file_3.csv, 6, FGH
Data --> file_3.csv, 7, DEF
Data --> file_4.csv, 8, FGH
如您所见,基本上文件名和数据一起在数据库中定义,因此SpringBatch应该做的是获取此数据并将其写入数据库中指定的相应文件(即file_1.csv
只应该包含3条记录(1,2,3),file_2.csv
应仅包含记录4和5等。)
是否可以使用MultiResourceItemWriter
来满足此要求(请注意,整个文件名是动态的,需要从数据库中检索)。
答案 0 :(得分:3)
我不确定,但我认为没有一种简单的方法可以获得这个。您可以尝试像这样构建自己的ItemWriter:
public class DynamicItemWriter implements ItemStream, ItemWriter<YourEntry> {
private Map<String, FlatFileItemWriter<YourEntry>> writers = new HashMap<>();
private LineAggregator<YourEntry> lineAggregator;
private ExecutionContext executionContext;
@Override
public void open(ExecutionContext executionContext) throws ItemStreamException {
this.executionContext = executionContext;
}
@Override
public void update(ExecutionContext executionContext) throws ItemStreamException {
}
@Override
public void close() throws ItemStreamException {
for(FlatFileItemWriter f:writers.values()){
f.close();
}
}
@Override
public void write(List<? extends YourEntry> items) throws Exception {
for (YourEntry item : items) {
FlatFileItemWriter<YourEntry> ffiw = getFlatFileItemWriter(item);
ffiw.write(Arrays.asList(item));
}
}
public LineAggregator<YourEntry> getLineAggregator() {
return lineAggregator;
}
public void setLineAggregator(LineAggregator<YourEntry> lineAggregator) {
this.lineAggregator = lineAggregator;
}
public FlatFileItemWriter<YourEntry> getFlatFileItemWriter(YourEntry item) {
String key = item.FileName();
FlatFileItemWriter<YourEntry> rr = writers.get(key);
if(rr == null){
rr = new FlatFileItemWriter<>();
rr.setLineAggregator(lineAggregator);
try {
UrlResource resource = new UrlResource("file:"+key);
rr.setResource(resource);
rr.open(executionContext);
} catch (MalformedURLException e) {
e.printStackTrace();
}
writers.put(key, rr);
//rr.afterPropertiesSet();
}
return rr;
}
}
并将其配置为编写者:
<bean id="csvWriter" class="com....DynamicItemWriter">
<property name="lineAggregator">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value=","/>
<property name="fieldExtractor" ref="csvFieldExtractor"/>
</bean>
</property>
答案 1 :(得分:0)
在spring-batch中,您可以使用ClassifierCompositeItemWriter进行此操作。
由于ClassifierCompositeItemWriter
允许您在写入过程中访问对象,因此您可以编写自定义逻辑来指示spring写入不同的文件。
看看下面的示例。 ClassifierCompositeItemWriter
需要实现Classifier
接口。在下面,您可以看到我创建了一个lambda,用于实现classify()
接口的Classifier
方法。您可以在classify()
方法中创建ItemWriter
。在下面的示例中,我们创建了一个FlatFileItemWriter
,该文件从item
本身获取文件名,然后为其创建资源。
@Bean
public ClassifierCompositeItemWriter<YourDataObject> yourDataObjectItemWriter(
Classifier<YourDataObject, ItemWriter<? super YourDataObject>> itemWriterClassifier
) {
ClassifierCompositeItemWriter<YourDataObject> compositeItemWriter = new ClassifierCompositeItemWriter<>();
compositeItemWriter.setClassifier(itemWriterClassifier);
return compositeItemWriter;
}
@Bean
public Classifier<YourDataObject, ItemWriter<? super YourDataObject>> itemWriterClassifier() {
return yourDataObject -> {
String fileName = yourDataObject.getFileName();
BeanWrapperFieldExtractor<YourDataObject> fieldExtractor = new BeanWrapperFieldExtractor<>();
fieldExtractor.setNames(new String[]{"recId", "name"});
DelimitedLineAggregator<YourDataObject> lineAggregator = new DelimitedLineAggregator<>();
lineAggregator.setFieldExtractor(fieldExtractor);
FlatFileItemWriter<YourDataObject> itemWriter = new FlatFileItemWriter<>();
itemWriter.setResource(new FileSystemResource(fileName));
itemWriter.setAppendAllowed(true);
itemWriter.setLineAggregator(lineAggregator);
itemWriter.setHeaderCallback(writer -> writer.write("REC_ID,NAME"));
itemWriter.open(new ExecutionContext());
return itemWriter;
};
}
最后,您可以像通常附加ItemWriter一样,在批处理步骤中附加ClassifierCompositeItemWriter
。
@Bean
public Step myCustomStep(
StepBuilderFactory stepBuilderFactory
) {
return stepBuilderFactory.get("myCustomStep")
.<?, ?>chunk(1000)
.reader(myCustomReader())
.writer(yourDataObjectItemWriter(itemWriterClassifier(null)))
.build();
}