23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
FlatFileItemReader는 Spring Batch에서 제공하는 기본적인 ItemReader로, 텍스트 파일로부터 데이터를 읽습니다.
고정 길이, 구분자 기반, 멀티라인 등 다양한 형식의 텍스트 파일을 지원하며, 다음과 같은 장점을 가집니다.
간단하고 효율적인 구현: 설정 및 사용이 간편하며, 대규모 데이터 처리에도 효율적입니다.
다양한 텍스트 파일 형식 지원: 고정 길이, 구분자 기반, 멀티라인 등 다양한 형식의 텍스트 파일을 읽을 수 있습니다.
확장 가능성: 토크나이저, 필터 등을 통해 기능을 확장할 수 있습니다.
사용처: 고정 길이, 구분자 기반, 멀티라인 등 다양한 형식의 텍스트 파일 데이터 처리
장점: 간단하고 효율적인 구현, 다양한 텍스트 파일 형식 지원
단점: 복잡한 데이터 구조 처리에는 적합하지 않음
Resource: 읽을 텍스트 파일을 지정합니다.
LineMapper: 텍스트 파일의 각 라인을 Item으로 변환하는 역할을 합니다.
LineTokenizer: 텍스트 파일의 각 라인을 토큰으로 분리하는 역할을 합니다.
FieldSetMapper: 토큰을 Item의 속성에 매핑하는 역할을 합니다.
SkippableLineMapper: 오류 발생 시 해당 라인을 건너뛸 수 있도록 합니다.
LineCallbackHandler: 라인별로 처리를 수행할 수 있도록 합니다.
ReadListener: 읽기 시작, 종료, 오류 발생 등의 이벤트를 처리할 수 있도록 합니다.
public class Customer {
private String name;
private int age;
private String gender;
// getter/setter methods...
}읽어들인 정보를 Customer 객체에 매핑할 수 있도록 객체를 정의한다.
다음과 같이 FlatFileItemReader를 생성하고, Customer 객체에 등록하여 반환한다.
@Bean
public FlatFileItemReader<Customer> flatFileItemReader() {
return new FlatFileItemReaderBuilder<Customer>()
.name("FlatFileItemReader")
.resource(new ClassPathResource("./customer.csv"))
.encoding(ENCODING)
.delimited().delimiter(",")
.names("name", "age", "gender")
.targetType(Customer.class)
.build();
}rexource
ClassPathResource("./customers.csv")
클래스 패스 내부에 존재하는 csv 파일을 읽어들인다.
encoding
파일 데이터의 인코딩을 추가한다.
delimited
구분자로 설정되어 있음을 의미한다.
delimiter
구분자를 무엇으로할지 지정한다.
names
구분자로 구분된 데이터의 이름을 지정한다.
targetType
구분된 데이터를 어느 모델에 넣을지 클래스 타입을 지정한다.
이제 CSV 플랫파일을 이용하여 단순히 다시 새로운 플랫파일로 저장하고 탭으로 구분된 배치를 작성해보자.
package com.schooldevops.springbatch.batchsample.jobs.flatfilereader;
import com.schooldevops.springbatch.batchsample.jobs.models.Customer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.transaction.PlatformTransactionManager;
@Slf4j
@Configuration
public class FlatFileItemJobConfig {
/**
* CHUNK 크기를 지정한다.
*/
public static final int CHUNK_SIZE = 100;
public static final String ENCODING = "UTF-8";
public static final String FLAT_FILE_CHUNK_JOB = "FLAT_FILE_CHUNK_JOB";
@Bean
public FlatFileItemReader<Customer> flatFileItemReader() {
return new FlatFileItemReaderBuilder<Customer>()
.name("FlatFileItemReader")
.resource(new ClassPathResource("./customer.csv"))
.encoding(ENCODING)
.delimited().delimiter(",")
.names("name", "age", "gender")
.targetType(Customer.class)
.build();
}
@Bean
public FlatFileItemWriter<Customer> flatFileItemWriter() {
return new FlatFileItemWriterBuilder<Customer>()
.name("flatFileItemWriter")
.resource(new FileSystemResource("./output/customer_new.csv"))
.encoding(ENCODING)
.delimited().delimiter("\t")
.names("Name", "Age", "Gender")
.build();
}
@Bean
public Step flatFileStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
log.info("------------------ Init flatFileStep -----------------");
return new StepBuilder("flatFileStep", jobRepository)
.<Customer, Customer>chunk(CHUNK_SIZE, transactionManager)
.reader(flatFileItemReader())
.writer(flatFileItemWriter())
.build();
}
@Bean
public Job flatFileJob(Step flatFileStep, JobRepository jobRepository) {
log.info("------------------ Init flatFileJob -----------------");
return new JobBuilder(FLAT_FILE_CHUNK_JOB, jobRepository)
.incrementer(new RunIdIncrementer())
.start(flatFileStep)
.build();
}
}지금까지 단순한 FlatFile을 읽는다 이는 csv 형식의 파일이며, 이 파일을 읽어 탭으로 구분된 파일을 새로 작성하는 배치를 작성했다.
FlatFileItemReader로 파일을 읽었다. 이때 파일의 특성에 따라 FlatFileItemReaderBuilder를 이용하여 쉽게 구성했다.
FlatFileItemWriter는 Spring Batch에서 제공하는 ItemWriter 인터페이스를 구현하는 클래스이다.
데이터를 텍스트 파일로 출력하는 데 사용된다.
Resource: 출력 파일 경로를 지정한다.
LineAggregator: Item을 문자열로 변환하는 역할을 한다.
HeaderCallback: 출력 파일 헤더를 작성하는 역할을 한다.
FooterCallback: 출력 파일 푸터를 작성하는 역할을 한다.
Delimiter: 항목 사이 구분자를 지정한다.
AppendMode: 기존 파일에 추가할지 여부를 지정한다.
간편성: 텍스트 파일로 데이터를 출력하는 간편한 방법을 제공한다.
유연성: 다양한 설정을 통해 원하는 형식으로 출력 파일을 만들 수 있다.
성능: 대량의 데이터를 빠르게 출력할 수 있다.
형식 제약: 텍스트 파일 형식만 지원한다.
복잡한 구조: 복잡한 구조의 데이터를 출력할 경우 설정이 복잡해질 수 있다.
오류 가능성: 설정 오류 시 출력 파일이 손상될 수 있다.
@Bean
public FlatFileItemWriter<Customer> flatFileItemWriter() {
return new FlatFileItemWriterBuilder<Customer>()
.name("flatFileItemWriter")
.resource(new FileSystemResource("./output/customer_new.csv"))
.encoding(ENCODING)
.delimited().delimiter("\t")
.names("Name", "Age", "Gender")
.append(false)
.lineAggregator(new CustomerLineAggregator())
.headerCallback(new CustomerHeader())
.footerCallback(new CustomerFooter(aggregateInfos))
.build();
}
FlatFileItemWriterBuilder: 파일로 결과를 쓰기하기 위한 빌더 객체
name: FlatFileItemWriter의 이름을 지정한다.
resource: 저장할 최종 파일 이름이다.
encoding: 저장할 파일의 인코딩 타입
delimited().delimiter: 각 필드를 구분할 딜리미터를 지정한다.
append: true인경우 기존 파일에 첨부한다. false인경우 새로운 파일을 만든다.
lineAggregator: 라인 구분자를 지정한다.
headerCallback: 출력 파일의 헤더를 지정할 수 있도록 한다.
footerCallback: 출력 파일의 푸터를 지정할 수 있도록 한다.
package com.schooldevops.springbatch.batchsample.jobs.flatfilereader;
import com.schooldevops.springbatch.batchsample.jobs.models.Customer;
import org.springframework.batch.item.file.transform.LineAggregator;
public class CustomerLineAggregator implements LineAggregator<Customer> {
@Override
public String aggregate(Customer item) {
return item.getName() + "," + item.getAge();
}
}LineAggregator은 FlatFile에 저장할 아이템들을 스트링으로 변환하는 방법을 지정하는 것이다.
위와 같이 aggregate를 구현하여 아이템을 스트링 문자로 변경하는 것을 확인할 수 있다.
package com.schooldevops.springbatch.batchsample.jobs.flatfilereader;
import org.springframework.batch.item.file.FlatFileHeaderCallback;
import java.io.IOException;
import java.io.Writer;
public class CustomerHeader implements FlatFileHeaderCallback {
@Override
public void writeHeader(Writer writer) throws IOException {
writer.write("ID,AGE");
}
}FlatFileHeaderCallback은 writeHeader를 구현하고, 출력될 파일의 헤더를 달아주는 역할을 한다.
package com.schooldevops.springbatch.batchsample.jobs.flatfilereader;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.item.file.FlatFileFooterCallback;
import java.io.IOException;
import java.io.Writer;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class CustomerFooter implements FlatFileFooterCallback {
ConcurrentHashMap<String, Integer> aggregateCustomers;
public CustomerFooter(ConcurrentHashMap<String, Integer> aggregateCustomers) {
this.aggregateCustomers = aggregateCustomers;
}
@Override
public void writeFooter(Writer writer) throws IOException {
writer.write("총 고객 수: " + aggregateCustomers.get("TOTAL_CUSTOMERS"));
writer.write(System.lineSeparator());
writer.write("총 나이: " + aggregateCustomers.get("TOTAL_AGES"));
}
}FlatFileFooterCallback 은 푸터를 작성할때 사용한다.
결과를 집계하여 총 고객수와 총 나이를 출력하고 있다.
이때 전달된 HashMap을 전달하여, 결과를 출력하고 있음을 확인하자.
package com.schooldevops.springbatch.batchsample.jobs.flatfilereader;
import com.schooldevops.springbatch.batchsample.jobs.models.Customer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.item.ItemProcessor;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
public class AggregateCustomerProcessor implements ItemProcessor<Customer, Customer> {
ConcurrentHashMap<String, Integer> aggregateCustomers;
public AggregateCustomerProcessor(ConcurrentHashMap<String, Integer> aggregateCustomers) {
this.aggregateCustomers = aggregateCustomers;
}
@Override
public Customer process(Customer item) throws Exception {
aggregateCustomers.putIfAbsent("TOTAL_CUSTOMERS", 0);
aggregateCustomers.putIfAbsent("TOTAL_AGES", 0);
aggregateCustomers.put("TOTAL_CUSTOMERS", aggregateCustomers.get("TOTAL_CUSTOMERS") + 1);
aggregateCustomers.put("TOTAL_AGES", aggregateCustomers.get("TOTAL_AGES") + item.getAge());
return item;
}
}ItemProcessor은 process 메소드를 구현하였으며, 각 아이템을 하나씩 읽고 아이템의 내용을 집계하고 있다.
package com.schooldevops.springbatch.batchsample.jobs.flatfilereader;
import com.schooldevops.springbatch.batchsample.jobs.models.Customer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.batch.item.file.transform.LineTokenizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.transaction.PlatformTransactionManager;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Configuration
public class FlatFileItemJobConfig {
/**
* CHUNK 크기를 지정한다.
*/
public static final int CHUNK_SIZE = 100;
public static final String ENCODING = "UTF-8";
public static final String FLAT_FILE_WRITER_CHUNK_JOB = "FLAT_FILE_WRITER_CHUNK_JOB";
private ConcurrentHashMap<String, Integer> aggregateInfos = new ConcurrentHashMap<>();
private final ItemProcessor<Customer, Customer> itemProcessor = new AggregateCustomerProcessor(aggregateInfos);
@Bean
public FlatFileItemReader<Customer> flatFileItemReader() {
return new FlatFileItemReaderBuilder<Customer>()
.name("FlatFileItemReader")
.resource(new ClassPathResource("./customer.csv"))
.encoding(ENCODING)
.delimited().delimiter(",")
.names("name", "age", "gender")
.targetType(Customer.class)
.build();
}
@Bean
public FlatFileItemWriter<Customer> flatFileItemWriter() {
return new FlatFileItemWriterBuilder<Customer>()
.name("flatFileItemWriter")
.resource(new FileSystemResource("./output/customer_new.csv"))
.encoding(ENCODING)
.delimited().delimiter("\t")
.names("Name", "Age", "Gender")
.append(false)
.lineAggregator(new CustomerLineAggregator())
.headerCallback(new CustomerHeader())
.footerCallback(new CustomerFooter(aggregateInfos))
.build();
}
@Bean
public Step flatFileStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
log.info("------------------ Init flatFileStep -----------------");
return new StepBuilder("flatFileStep", jobRepository)
.<Customer, Customer>chunk(CHUNK_SIZE, transactionManager)
.reader(flatFileItemReader())
.processor(itemProcessor)
.writer(flatFileItemWriter())
.build();
}
@Bean
public Job flatFileJob(Step flatFileStep, JobRepository jobRepository) {
log.info("------------------ Init flatFileJob -----------------");
return new JobBuilder(FLAT_FILE_WRITER_CHUNK_JOB, jobRepository)
.incrementer(new RunIdIncrementer())
.start(flatFileStep)
.build();
}
}지금까지 FlatFileItemWriter 를 작성하였다.
FlatFileItemWriter은 파일을 이용하여 결과를 작성하고, 이 결과를 csv, tsv등과 같은 형식화된 파일등으로 보낼때 매우 유용하다.
헤더, 푸터등을 적용하여 파일형식으로 포매팅 할 수 있음을 확인하였다.
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.