spring-boot - Springboot Batch 从 REST API 获取 CSV
问题描述
我有一个 Springboot 批处理应用程序的场景,我需要读取 CSV-11 并写入另一个 CSV-2,当我需要从 REST 端点获取 CSV-1 时出现问题,例如当我启动它的工作时应该从端点获取 CSV-1,然后继续批处理以写入 CSV-2。但似乎处理 CSV-1 我们需要在应用程序启动时提前提供“资源”[我对批处理相当陌生,所以不确定它是否 100% 正确]。谁能指导我正确的方法来解决这个问题?
编辑:添加代码,我能够解决它,但如果它是正确的做事方式需要建议(请忽略硬编码数据)。
@Configuration
@EnableBatchProcessing
public class BatchConfig {
@Autowired
private JobBuilderFactory jobbuilder;
@Autowired
private StepBuilderFactory stepbuilder;
@Autowired
private CSVProcessor processor;
@Autowired
private CustomSkipPolicy customSkipPolicy;
@Autowired
private CSVResponse response;
@Bean(name="csv")
public Job job_csv() throws Exception {
Step step = stepbuilder
.get("csv-step")
.<Person, Person>chunk(5)
.reader(new CSVReader(response.getResource()))
.processor(processor)
.writer(new CSVWriter().write(response.getFilename()))
.faultTolerant()
.skipPolicy(customSkipPolicy)
.listener(new StepListener())
.build();
return jobbuilder
.get("csv-job")
.incrementer(new RunIdIncrementer())
.listener(new JobListener())
.flow(step)
.end()
.build();
}
}
@Slf4j
public class CSVReader extends FlatFileItemReader<Person> {
public CSVReader(Resource resource) throws Exception {
super();
setResource(resource);
setStrict(false);
setLinesToSkip(1);
doOpen();
DelimitedLineTokenizer dlt = new DelimitedLineTokenizer();
dlt.setNames(new String[] {"id","first_name","last_name","email","gender","ip_address","dob"});
dlt.setDelimiter(",");
dlt.setStrict(false);
BeanWrapperFieldSetMapper<Person> fsp = new BeanWrapperFieldSetMapper<>();
fsp.setTargetType(Person.class);
DefaultLineMapper<Person> dlp = new DefaultLineMapper<>();
dlp.setLineTokenizer(dlt);
dlp.setFieldSetMapper(fsp);
setLineMapper(dlp);
}
}
public class CSVWriter {
private static final String DATA_PROCESSED = "C:/data/processed";
public FlatFileItemWriter<Person> write(String filename) throws Exception {
FlatFileItemWriter<Person> writer = new FlatFileItemWriter<>();
writer.setResource(resource(filename));
writer.setHeaderCallback(new Header());
BeanWrapperFieldExtractor<Person> fe = new BeanWrapperFieldExtractor<>();
fe.setNames(new String[] { "id", "first_name", "last_name", "age" });
DelimitedLineAggregator<Person> dla = new DelimitedLineAggregator<>();
dla.setDelimiter(",");
dla.setFieldExtractor(fe);
writer.setLineAggregator(dla);
return writer;
}
private Resource resource(String filename) throws IOException {
String processed_file = filename.replace(".csv", "").concat("_PROCESSED").concat(".csv");
if (Files.notExists(Paths.get(DATA_PROCESSED), new LinkOption[] { LinkOption.NOFOLLOW_LINKS })) {
Files.createDirectory(Paths.get(DATA_PROCESSED));
}
if (Files.notExists(Paths.get(DATA_PROCESSED + "/" + processed_file),
new LinkOption[] { LinkOption.NOFOLLOW_LINKS })) {
Files.createFile(Paths.get(DATA_PROCESSED + "/" + processed_file));
}
return new FileSystemResource(DATA_PROCESSED + "/" + processed_file);
}
}
@Component
@Slf4j
public class CSVResponse {
private static final String DATA_RECEIVE = "C:/data/receive";
private String filename;
public Resource getResource() throws IOException {
ResponseEntity<Resource> resp = new RestTemplate().getForEntity("http://localhost:8081/csv", Resource.class);
log.info("File Received : "+resp.getBody().getFilename());
setFilename(resp.getBody().getFilename());
Path path = Paths.get(DATA_RECEIVE);
if(!Files.exists(path, new LinkOption[]{ LinkOption.NOFOLLOW_LINKS})) {
Files.createDirectory(path);
}
Files.copy(resp.getBody().getInputStream(), Paths.get(DATA_RECEIVE + "/" +resp.getBody().getFilename()), StandardCopyOption.REPLACE_EXISTING);
return resp.getBody();
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
}
解决方案
您可以使用StepExecutionListener接口实现项目阅读器,并且您必须通过项目阅读器的beforeStep()方法中的RestTemplate实现获取 CSV-1 文件。
您可以从https://www.baeldung.com/rest-template参考如何使用 RestTemplate
推荐阅读
- javascript - 如何检查单击的 svg 路径是否有类?
- javascript - JavaScript:从 JSON 对象中提取属性
- python - 将 tensorflow 张量列解压缩为单独的变量
- python - 如何计算给定范围内的总质数
- tfs - 在 TFS 2017 构建中 - 如何从命令行步骤打印构建日志?
- arrays - 找到总和大于给定数字的最小子数组的长度
- laravel - laravel路由匿名函数中的echo和return有什么区别。返回页面并回显页面时,我看到了相同的输出
- qt - 在其他文件(mainwindow.cpp除外)中,如何操作ui组件?
- c# - EF 代码首次迁移问题
- android - 如何在循环之外获取字符串