스프링 배치 강좌 목록: https://www.fwantastic.com/p/spring-batch.html
이전 글 다시 보기: [Spring Batch] 스프링 배치 강좌 4. CSV 파일 읽어서 JDBC로 디비에 저장하기
Exam 테이블을 생성 하고 테스트 데이터를 넣는다. Exam 테이블에는 시험 점수가 0-100점 스케일로 저장되어있다.
create-table.sql
Exam.java
시험 점수 grade 스케일은 다음과 같다.
Getter/Setter는 lombok을 사용하여 처리했는데 셋업이 안되있다면 아래 포스트를 참고하자.
자바 lombok 설치와 Getter/Setter 간편하게 만들기
ExamProcessor.java
자세한 설명은 주석을 참고하자.
job4.xml
MyJobTest.java
이전 글 다시 보기: [Spring Batch] 스프링 배치 강좌 4. CSV 파일 읽어서 JDBC로 디비에 저장하기
목적
성적 데이터를 저장하는 Exam 테이블 데이터를 읽어서 시험 점수 0-100점 스케일을 A-F 스케일로 변환하여 CSV 파일에 저장한다.Input
src/test/resources에 com/fwantastic/example4 폴더를 생성 후 create-table.sql를 만든다.Exam 테이블을 생성 하고 테스트 데이터를 넣는다. Exam 테이블에는 시험 점수가 0-100점 스케일로 저장되어있다.
create-table.sql
CREATE TABLE EXAM (
CLASS_NAME VARCHAR2(255)
, STUDENT_NAME VARCHAR2(255)
, SCORE INT
, GRADE VARCHAR2(1)
)
;
INSERT INTO EXAM
(CLASS_NAME, STUDENT_NAME, SCORE) VALUES
('MATH' , 'Fwantastic', 64 )
;
INSERT INTO EXAM
(CLASS_NAME, STUDENT_NAME, SCORE) VALUES
('MATH' , 'IU' , 95 )
;
INSERT INTO EXAM
(CLASS_NAME , STUDENT_NAME, SCORE) VALUES
('COMPUTER SCIENCE', 'Fwantastic', 100 )
;
INSERT INTO EXAM
(CLASS_NAME , STUDENT_NAME, SCORE) VALUES
('COMPUTER SCIENCE', 'IU' , 86 )
;
INSERT INTO EXAM
(CLASS_NAME , STUDENT_NAME, SCORE) VALUES
('COMPUTER SCIENCE', '수지' , 77 )
;
Exam.java
Exam 테이블 데이터를 매핑 할 자바 클래스를 만든다. com.fwantastic.example4 패키지에 아래 클래스를 추가하자.Exam.java
package com.fwantastic.example4;
import java.util.Arrays;
import java.util.Comparator;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Exam {
private String className;
private String studentName;
// 시험 점수. 0-100점
private double score;
// 시험 점수 스케일. A-F
private String grade;
@Getter
public static enum Grade {
A("A", 90), B("B", 80), C("C", 70), D("D", 60), F("F", 0);
private final String grade;
private final double score;
private Grade(String grade, double score) {
this.grade = grade;
this.score = score;
}
public static String convertScore(double score) {
return Arrays.stream(values()).filter(grade -> grade.score < score)
.max(Comparator.comparing(grade -> grade.score)).get().getGrade();
}
}
}
시험 점수 grade 스케일은 다음과 같다.
- A = 90점 이상
- B = 80점 이상
- C = 70점 이상
- D = 60점 이상
- F = 60점 이하
Getter/Setter는 lombok을 사용하여 처리했는데 셋업이 안되있다면 아래 포스트를 참고하자.
자바 lombok 설치와 Getter/Setter 간편하게 만들기
ExamProcessor.java
시험 점수를 grade 스케일로 변환 한 값을 Exam 객체에 매핑 후 반환한다. com.fwantastic.example4 패키지에 아래 클래스를 추가하자.ExamProcessor.java
package com.fwantastic.example4;
import org.springframework.batch.item.ItemProcessor;
/**
* 시험 점수 0-100점 스케일을 A-F 스케일로 변환한다.
*/
public class ExamProcessor implements ItemProcessor<Exam, Exam> {
public Exam process(Exam exam) throws Exception {
exam.setGrade(Exam.Grade.convertScore(exam.getScore()));
return exam;
}
}
job4.xml
src/main/resources/com/fwantastic/example4에 아래의 job4.xml을 만든다.자세한 설명은 주석을 참고하자.
job4.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.3.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
<import resource="classpath:/common-context.xml" />
<!-- job을 시작하기 전에 Exam 테이블과 테스트 데이터 생성. -->
<jdbc:initialize-database
data-source="dataSource">
<jdbc:script
location="classpath:com/fwantastic/example4/create-table.sql" />
</jdbc:initialize-database>
<job id="myJob4"
xmlns="http://www.springframework.org/schema/batch">
<description>
JDBC로 디비를 읽어서 CSV 파일로 저장하는 예제.
</description>
<step id="myStep1">
<tasklet>
<chunk reader="examReader"
processor="examProcessor" writer="examWriter"
commit-interval="10" />
</tasklet>
</step>
</job>
<bean id="examReader"
class="org.springframework.batch.item.database.JdbcCursorItemReader">
<property name="dataSource" ref="dataSource" />
<property name="sql">
<value>
<![CDATA[
SELECT CLASS_NAME, STUDENT_NAME, SCORE
FROM EXAM
ORDER BY CLASS_NAME, STUDENT_NAME, SCORE
]]>
</value>
</property>
<property name="rowMapper" ref="examRowMapper" />
</bean>
<!-- JDBC reader로 읽은 데이터를 자바 객체로 매핑 해준다. -->
<bean id="examRowMapper"
class="org.springframework.jdbc.core.BeanPropertyRowMapper"
scope="step">
<property name="mappedClass"
value="com.fwantastic.example4.Exam" />
</bean>
<!-- Exam 데이터 가공 -->
<bean id="examProcessor"
class="com.fwantastic.example4.ExamProcessor" scope="step" />
<bean id="examWriter"
class="org.springframework.batch.item.file.FlatFileItemWriter"
scope="step">
<!-- Aggregate이 모으다 라는 뜻인데, 한 라인을 어떻게 쓸지 설정한다. -->
<!-- 여기선 콤마로 필드를 구분하고 className, studentName, grade 순서대로 값을 쓰라고 설정했다. -->
<property name="lineAggregator">
<bean
class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<property name="delimiter" value="," />
<property name="fieldExtractor">
<bean
class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<property name="names"
value="className, studentName, grade"></property>
</bean>
</property>
</bean>
</property>
<!-- 쓸 파일 위치를 지정해준다. 배치가 종료되면 프로젝트 root 레벨 (pom.xml과 같은 위치) 에 output
폴더가 생성된다. -->
<property name="resource">
<bean
class="org.springframework.core.io.FileSystemResource">
<constructor-arg name="path"
value="output/com/fwantastic/example4/output.csv" />
</bean>
</property>
<!-- 파일이 존재하면 삭제하고 새로 만든다. -->
<property name="shouldDeleteIfExists" value="true" />
</bean>
</beans>
테스트
src/test/java에 com.fwantastic.example4 패키지 만들고 아래 junit 클래스를 추가하자.MyJobTest.java
package com.fwantastic.example4;
import java.io.File;
import java.util.concurrent.atomic.AtomicBoolean;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/com/fwantastic/example4/job4.xml" })
public class MyJobTest {
@Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
@Autowired
private JdbcTemplate jdbcTemplate;
private static AtomicBoolean isLaunched = new AtomicBoolean(false);
private JobExecution jobExecution;
@Before
public void setUp() throws Exception {
if (!isLaunched.getAndSet(true)) {
jobExecution = jobLauncherTestUtils.launchJob();
}
}
@Test
public void testExitCode() {
Assert.assertEquals(ExitStatus.COMPLETED.getExitCode(), jobExecution.getExitStatus().getExitCode());
}
// output 파일이 생성되었는지 확인한다. 테스트는 더 디테일하면 할수록 더 좋다.
@Test
public void testOutputFileCreated() {
File file = new File("output/com/fwantastic/example4/output.csv");
Assert.assertTrue(file.exists());
}
}
실행 결과
프로젝트 root 레벨에 output/com/fwantastic/example4/output.csv 파일이 생성된 것을 확인 할 수 있다.
COMPUTER SCIENCE,Fwantastic,A
COMPUTER SCIENCE,IU,B
COMPUTER SCIENCE,수지,C
MATH,Fwantastic,D
MATH,IU,A
다음 글
작업중