2021. 4. 13. 17:19ㆍspring
가. 목표
SpringBatch에서 제공하는 소스를 가능한 이용해서 기능을 구현했다. ( 2012.03.17 )
Java 1.6이상
Spring 4.2.4
SpringSecurity 3.1
SpringBatch 3.0.7
SpringModules 0.9 ⇒ deprecated
Struts 1.3.10
Easy Mock 3.0
JUnit 4.4
- csv 파일을 읽어서 다른 파일에 쓰기 샘플. 이때 열을 바꿔서 출력.
- SpringBatch로 읽어들인 파일 데이터를 FieldSet이라는 클래스에 보존한다.
- FieldSet 에서 POJO 클래스로 값을 옮겨 적는 것을 매핑한다라고 한다.
나. 스프링배치의 기반에 관한 설정 /back-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator"
p:jobLauncher-ref="jobLauncher" p:jobExplorer-ref="jobExplorer"
p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
<bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"
p:dataSource-ref="dataSource" />
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
<bean class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
<property name="jobRegistry" ref="jobRegistry"/>
</bean>
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager"
p:maxVarCharLength="2000"
p:isolationLevelForCreate="ISOLATION_SERIALIZABLE" />
<!-- DB設定 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="XXX.driver" />
<property name="url" value="jdbc.XXX.url" />
<property name="username" value="XXX" />
<property name="password" value="XXX" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager" lazy-init="true">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
다. 설정파일 샘플 /job-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
">
<!-- SpringBatch의 기반부분에 관한 설정의 임포트 -->
<import resource="classpath:/back-context.xml" />
<!-- ジョブの設定 -->
<job id="job1" xmlns="http://www.springframework.org/schema/batch"
incrementer="jobParametersIncrementer">
<step id="step1" parent="simpleStep">
<tasklet>
<chunk reader="fileItemReader" writer="fileItemWriter" />
</tasklet>
</step>
</job>
<!-- enables the functionality of JobOperator.startNextInstance(jobName) -->
<bean id="jobParametersIncrementer"
class="org.springframework.batch.core.launch.support.RunIdIncrementer" />
<bean id="simpleStep"
class="org.springframework.batch.core.step.item.SimpleStepFactoryBean"
abstract="true">
<property name="jobRepository" ref="jobRepository" />
<property name="commitInterval" value="1" />
</bean>
<bean id="fileItemReader"
class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<property name="resource" value="file:c:/test/data.csv" />
<property name="lineMapper">
<bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
<property name="lineTokenizer">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<property name="names" value="num,name" />
</bean>
</property>
<property name="fieldSetMapper">
<bean class="test.batch.item.MemberFieldSetMapper" />
</property>
</bean>
</property>
</bean>
<!-- 열을 변경해서 다른 파일에 출력하는 Writer -->
<bean id="fileItemWriter" class="org.springframework.batch.item.file.FlatFileItemWriter">
<property name="resource" value="file:c:/test/test.txt" />
<property name="lineAggregator">
<bean class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="fieldExtractor">
<bean class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor" >
<property name="names" value="name,num" />
</bean>
</property>
</bean>
</property>
</bean>
</beans>
- 설정파일 설명
가. fileItemReader (FlatFileItemReader 클래스)
<FlatFileItemReader의 프로퍼티>
프로퍼티 명 | 형 (타입) | 내용 | |
comments | String[] | 설정한 값이 행의 맨앞에 있으면 코맨트행으로 간주 | |
encoding | String | 문자인코딩, 초기값 = "ISO-8859-1" | |
lineMapper | LineMapper | 오브젝트에 매핑하는 방법 지정 | |
linesToSkip | int | 무시 (스킵)하는 행수 지정 | |
recordSeparatorPolicy | RecordSeparatorPolicy | ""으로 묶인 문자열 중에 개행문자가 있어도 하나의 레코드로 간주하여 읽어들일지를 결정. | |
resource | Resource | 읽어들일 파일 패스 지정. | |
skippedLinesCallback | LineCallbackHandler | 스킵한 행을 여기에 지정한 콜백에 전달. 만약, linesToSkip에 2를 설정한 경우, 콜백을 2회 호출. | |
strict | boolean | true로 설정하면 stict mode로 변환. resource에 지정한 리소스가 발견되지 않은 경우, exception 발생. |
lineMapper 프로퍼티를 변경하는 것으로 구분자 문자 변경하수도, 고정문자열에도 대응 가능하다.
여기서 사용되는 DelimitedLineTokenizer, FixedLengthTokenizer, PatternMatchingCompositeLineTokenizer 등의 부품에 대해서는 javadoc를 참조하시오.
또한 복수행으로 하나의 데이터로 된 경우에도 대응 가능하다.
고정문자열을 읽어 들이느 tokenizer의 사례
<bean id="fixedLengthLineTokenizer"
class="org.springframework.batch.io.file.transform.FixedLengthTokenizer">
<property name="names" value="num,name,age" />
<property name="columns" value="1-7, 7-18, 19-21" />
</bean>
나. fileItemWriter (FlatFileItemWriter클래스)
이 클래스는 파일에 데이터를 쓰는 데 이용된다.
lineAggregator 프로퍼티에 설정되어 있는 것은 구분자문자에 의해 데이터를 쓰는 클래스이다.
물론 구분자 문자도 자유롭게 변경 가능하다.
또한 FormatterLineAggregator를 사용하면 위치를 자유롭게 변경하는 것도, 서식변환하는 것도 가능하다.
<FlatFileItemWriter의 프로퍼티>
프로퍼티 명 | 형 (타입) | 내용 | |
appendAllowed | boolean | true일 경우, append mode로 처리한다. 이 프로퍼티가 설정되면 shouldDeleteIfExists 프로퍼티는 자동적으로 false로 변경된다. 그러므로 이경우에는 shouldDeleteIfExists프로퍼티를 설정하면안된다. 초기값은 false |
|
shouldDeleteIfEmpty | boolean | 처리가 종료 될 때 파일에 헤더, 풋터 이외에 1행도 write안된 경우 파일을 삭제할지 여부를 지정한다. true의 경우, 파일 삭제, 초기값은 false |
|
saveState | boolean | ItemStream이 update 메소드를 호출하는 동안 ExecutionContext에 상태를 보존할지 말지를 지정한다. 만약 false를 설정한 경우, restart 했을 때 언제나 가장 최초에서 시작하는 것으로 동작한다. 결국 에러가 난 위치부터 시작하지 않는다. |
|
headerCallback | FlatFileHeaderCallback | 첫번째 item을 처리하기 전에 이 callback이 호출된다. | |
footerCallback | FlatFileFooterCallback | 마지막 item을 처리된 이후에 이 callback이 호출된다. | |
transactional | boolean | 만약 트랜잭션이 active인 경우, 버퍼에 쓰기를 지연하는 것을 지시한다. 초기값은 true. | |
lineSeparator | String | 개행문자를 설정한다. 초기값은 java 시스템 프로퍼티에 설정한 개행문자이다. 시스템프로퍼티에 통상 OS의 초기 개행문자가 설정되어 있을 것. | |
lineAggregator | LineAggregator | 아이템을 파일의 1행에 전개한는 클래스를 지정 | |
Resource | Resource | 출력파일을 지정 | |
encoding |
String | 출력파일의 인코딩을 지정 |
다. POJO 클래스, test.batch.item.Member.java
public class Member {
private int num;
private String name;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
라. POJO 에 값설정 매퍼 클래스 : test.batch.item.MemberFieldSetMapper.java
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
public class MemberFieldSetMapper implements FieldSetMapper<Member> {
@Override
public Member mapFieldSet(FieldSet fs) throws BindException {
Member member = new Member();
member.setNum(fs.readInt("num", 0));
member.setName(fs.readString("name"));
return member;
}
}
POJO 에의 매핑은 FieldSetMapper를 구현한 클래스에서 수행된다.
fs.readInt ("num", 0); // 두번째 인수는 취득값이 널인 경우 초기값으로 지정
fs.readDate("birthdate", null, "yyyy/MM/dd" );
5. 실행
가. 읽을 파일 c:/test/data.csv
1, 철수 2, 영희
나. 실행방법1
코맨드라인에서 다음과 같이 실행
java org.springframework.batch.core.launch.support.CommandLineJobRunner
classpath:/example/launch-context.xml job1
다. 실행방법2
이클립스에서
라. 실행결과
철수, 1
영희, 2
최종적으로 POJO에 값을 매핑하는 용으로 BeanWrapperFieldSetMapper 클래스 라는 걸 쓸수도 있다.
POJO 대신에 LinkedHashMap 를 사용할 수 있다.
'spring' 카테고리의 다른 글
[퍼옴] Spring Batch 주요 개념 (0) | 2021.04.14 |
---|---|
07. spring batch - 배치 처리의 실제 샘플 (chunk: db 읽기) (0) | 2021.04.14 |
05. Spring배치 사용준비 (0) | 2021.04.12 |
04. Spring Batch 기본개념 (ExecutionContext) (0) | 2021.04.12 |
03. Spring Batch 기본개념 (기동, 기동 옵션) (0) | 2021.04.12 |