
스프링 배치에서 파일을 읽고 처리하고 다시 파일에 쓰는 작업을 수행하기 위한 예시코드이다.
@RequiredArgsConstructor
@Configuration
public class FileDataReadWriteConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean
public Job fileReadWriteJob(Step fileReadWriteStep) {
jobBuilderFactory.get("fileReadWriteJob")
.incrementer(new RunIdIncrementer())
.start(fileReadWriteStep)
.build();
}
@Bean
@JobScope
public Step fileReadWriteStep(ItemReader playerItemReader,
ItemProcessor playerItemProcessor,
ItemWriter playerItemWriter
) {
return stepBuilderFactory.get("fileReadWriteStep")
.<Player, PlayerYears>chunk(5)
.reader(playerItemReader)
.processor(playerItemProcessor)
.writer(playerItemWriter)
.build();
}
@StepScope
@Bean
public ItemProcessor<Player, PlayerYears> playerItemProcessor() {
return new ItemProcessor<Player, PlayerYears>() {
@Override
public PlayerYears process(Player item) throws Exception {
return new PlayerYears(item);
}
};
}
@StepScope
@Bean
public FlatFileItemReader<Player> playerItemReader() {
return new FlatFileItemReaderBuilder<Player>()
.name("playerItemReader")
.resource(new FileSystemResource("Players.csv"))
.lineTokenizer(new DelimitedLineTokenizer())
.fieldSetMapper(new PlayerFieldSetMapper())
.linesToSkip(1)
.build();
}
@StepScope
@Bean
public FlatFileItemWriter<PlayerYears> playerItemWriter() {
BeanWrapperFieldExtractor<PlayerYears> fieldExtractor = new BeanWrapperFieldExtractor<>();
fieldExtractor.setNames(new String[]{"ID", "lastName", "position", "yearsExperience"});
fieldExtractor.afterPropertiesSet();
DelimitedLineAggregator<PlayerYears> lineAggregator = new DelimitedLineAggregator<>();
lineAggregator.setDelimiter("=");
lineAggregator.setFieldExtractor(fieldExtractor);
FileSystemResource outputResource = new FileSystemResource("players_output.txt");
return new FlatFileItemWriterBuilder<PlayerYears>()
.name("playerItemWriter")
.resource(outputResource)
.lineAggregator(lineAggregator)
.build();
}
}
소스 코드의 핵심 내용을 살펴보자!
이전 포스팅에서 공부했던것 처럼 Player를 PlayerYears 객체로 트랜잭션을 5개의 단위로 커밋합니다.
ItemProcessor는 Player를 PlayerYears로 변환하는 후처리 역할을 수행합니다.
FlatFileItemReader는 ItemReader의 일종으로서 파일에서 읽어온 데이터를 Player 객체에 담아주는 역할을 수행합니다.
return new FlatFileItemReaderBuilder<Player>()
.name("playerItemReader")
.resource(new FileSystemResource("Players.csv"))
.lineTokenizer(new DelimitedLineTokenizer())
.fieldSetMapper(new PlayerFieldSetMapper())
.linesToSkip(1)
.build();
public class PlayerFieldSetMapper implements FieldSetMapper<Player> {
public Player mapFieldSet(FieldSet fieldSet) {
Player player = new Player();
player.setID(fieldSet.readString(0));
player.setLastName(fieldSet.readString(1));
player.setFirstName(fieldSet.readString(2));
player.setPosition(fieldSet.readString(3));
player.setBirthYear(fieldSet.readInt(4));
player.setDebutYear(fieldSet.readInt(5));
return player;
}
}
FlatFileItemReader와 유사하게 PlayerYears 객체를 파일에 쓰는 역할을 구현합니다.
@StepScope
@Bean
public FlatFileItemWriter<PlayerYears> playerItemWriter() {
BeanWrapperFieldExtractor<PlayerYears> fieldExtractor = new BeanWrapperFieldExtractor<>();
fieldExtractor.setNames(new String[]{"ID", "lastName", "position", "yearsExperience"});
fieldExtractor.afterPropertiesSet();
DelimitedLineAggregator<PlayerYears> lineAggregator = new DelimitedLineAggregator<>();
lineAggregator.setDelimiter("=");
lineAggregator.setFieldExtractor(fieldExtractor);
FileSystemResource outputResource = new FileSystemResource("players_output.txt");
return new FlatFileItemWriterBuilder<PlayerYears>()
.name("playerItemWriter")
.resource(outputResource)
.lineAggregator(lineAggregator)
.build();
}