본문으로 바로가기

스프링 배치 작업을 하다보면 반복적인 작업이 나올 수 있다.

 

뭔가 반복적인 템플릿을 만드는 방법은 없을까??

 

인텔이제이에서 제공해주는 Tools -> Save File as Template를 이용하면 보다 편하게 이용할 수 있다.

 

 

- 템플릿이 만들어지면 클래스 생성시 템플릿을 바로 가져와 사용할 수 있다.

- 만들어진 템플릿 클래스 화면

- ItemReaderJob 실행을 위한 매개변수 환경설정

 

※ CSV 데이터와 JDBC 데이터를 읽기 위해 아래와 같이 파일을 셋팅한다.

 

- 적용소스 화면

@Configuration
@Slf4j
public class ItemReaderConfiguration {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;
    private final DataSource dataSource;

    public ItemReaderConfiguration(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, DataSource dataSource) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
        this.dataSource = dataSource;
    }

    @Bean
    public Job itemReaderJob() throws Exception {
        return this.jobBuilderFactory.get("itemReaderJob")
                .incrementer(new RunIdIncrementer())
                .start(this.customItemReaderStep())
                .next(this.csvFileStep())
                .next(this.jdbcStep())
                .build();
    }

    @Bean
    public Step customItemReaderStep() {
        return this.stepBuilderFactory.get("customItemReaderStep")
                .<Person, Person>chunk(10)
                .reader(new CustomItemReader<>(getItems()))
                .writer(itemWriter())
                .build();
    }
    
    @Bean
    public Step csvFileStep() throws Exception {
        return stepBuilderFactory.get("csbFileStep")
                .<Person, Person>chunk(10)
                .reader(this.csvFileItemReader())
                .writer(itemWriter())
                .build();
    }

    @Bean
    public Step jdbcStep() throws Exception {
        return stepBuilderFactory.get("jdbcStep")
                .<Person, Person>chunk(10)
                .reader(this.jdbcCursorItemReader())
                .writer(itemWriter())
                .build();
    }

    private JdbcCursorItemReader<Person> jdbcCursorItemReader() throws Exception {
        JdbcCursorItemReader<Person> itemReader = new JdbcCursorItemReaderBuilder<Person>()
                .name("jdbcCursorItemReader")
                .dataSource(dataSource)
                .sql("select id, name, age, address from person")
                .rowMapper((rs, rowNum) -> new Person(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getString(4)))
                .build();

        itemReader.afterPropertiesSet();
        return itemReader;
    }

    /* csv 파일 생성과, Person 매핑 */
    private FlatFileItemReader<Person> csvFileItemReader() throws Exception {
        DefaultLineMapper<Person> lineMapper = new DefaultLineMapper<>();
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
        tokenizer.setNames("id", "name", "age", "address");
        lineMapper.setLineTokenizer(tokenizer);

        lineMapper.setFieldSetMapper(fieldSet -> {
            int id = fieldSet.readInt("id");
            String name = fieldSet.readString("name");
            String age = fieldSet.readString("age");
            String address = fieldSet.readString("address");

            return new Person(id, name, age, address);
        });

        FlatFileItemReader<Person> itemReader = new FlatFileItemReaderBuilder<Person>()
                .name("csvFileItemReader")
                .encoding("UTF-8")
                .resource(new ClassPathResource("test.csv"))
                .linesToSkip(1) // 데이터가아닌 필드명부터 (1번행 패스)
                .lineMapper(lineMapper)
                .build();

        itemReader.afterPropertiesSet(); // itemReader 필수값들이 정상적으로 됐는지 검증

        return itemReader;
    }

    private ItemWriter<? super Person> itemWriter() {
        return items -> log.info(items.stream()
                .map(Person::getName)
                .collect(Collectors.joining(", ")));
    }

    private List<Person> getItems() {
        List<Person> items = new ArrayList<>();

        for (int i = 0; i < 10; i++) {
            items.add(new Person(i+1, "test name" + i, "test age", "test address"));
        }

        return items;
    }
}

- 아웃풋 결과

스프링배치에서 제공해주는 ListItemReader와 실습용 수동으로 만든 CutomItemReader 앞으로는 ListItemReader를

적극 사용하도록 하자.