728x90
환경
IDE: intellij
SpringBootVersion: 3.0.11
Gradle: 8.8
Java: 17
해당 포스트는
한 번에 끝내는 Spring 완.전.판 초격차 패키지 Online. 의 강의를 코틀린으로 재구성한것입니다
다루는 내용
- FlatFileItemReader
- FieldSetMapper
- JobParametersValidator
build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
id("org.springframework.boot") version "3.0.11"
id("io.spring.dependency-management") version "1.1.0"
kotlin("jvm") version "1.7.22"
kotlin("plugin.spring") version "1.7.22"
kotlin("plugin.jpa") version "1.7.22"
}
group = "com.example"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_17
repositories {
mavenCentral()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-data-jpa")
implementation("org.springframework.boot:spring-boot-starter-web")
implementation("org.springframework.boot:spring-boot-starter-batch")
implementation("org.jetbrains.kotlin:kotlin-reflect")
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
implementation("org.springframework.kafka:spring-kafka:3.2.0")
implementation("mysql:mysql-connector-java:8.0.33")
implementation("com.querydsl:querydsl-jpa:5.0.0:jakarta")
implementation("com.querydsl:querydsl-kotlin:5.0.0")
annotationProcessor("com.querydsl:querydsl-apt:5.0.0:jakarta")
testImplementation("org.springframework.boot:spring-boot-starter-test")
testImplementation("org.springframework.batch:spring-batch-test")
testImplementation("org.junit.jupiter:junit-jupiter-api")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
}
tasks.withType<KotlinCompile> {
kotlinOptions {
freeCompilerArgs = listOf("-Xjsr305=strict")
jvmTarget = "17"
}
}
tasks.withType<Test> {
useJUnitPlatform()
}
Program arguments
--job.name=lawdInsertJob filePath=LAWD_CODE_SAMPLE.txt
lawdFileItemReader 설명
@Value("#{jobParameters['filePath']}"): Job 파라미터에서 'filePath' 값을 가져와 이 함수의 매개변수로 주입합니다. .delimited(): 파일의 각 라인이 구분자로 나누어진 필드들로 구성되어 있음을 나타냅니다.
.delimiter("\t"): 필드 구분자로 탭(\t)을 사용한다고 지정합니다.
.names(LAWD_CD, LAWD_DONG, EXIST_YN): 각 필드의 이름을 지정합니다. 이 이름들은 Lawd 객체의 프로퍼티 이름과 일치해야 합니다.
.linesToSkip(1): 파일의 첫 번째 줄(보통 헤더)을 건너뛰도록 설정합니다.
.encoding("EUC-KR"): 파일의 인코딩을 EUC-KR로 지정합니다.
.fieldSetMapper(LawdFieldSetMapper()): LawdFieldSetMapper라는 커스텀 FieldSetMapper를 사용하여 읽은 데이터를 Lawd 객체로 매핑합니다.
.resource(ClassPathResource(filePath)): 읽을 파일의 위치를 지정합니다. ClassPathResource는 클래스패스 내의 리소스를 나타냅니다.
Job
import com.example.kotlinsimplespringbatch.domain.Lawd
import com.example.kotlinsimplespringbatch.job.lawd.LawdFieldSetMapper.companion.EXIST_YN
import com.example.kotlinsimplespringbatch.job.lawd.LawdFieldSetMapper.companion.LAWD_CD
import com.example.kotlinsimplespringbatch.job.lawd.LawdFieldSetMapper.companion.LAWD_DONG
import com.example.kotlinsimplespringbatch.job.validator.FilePathParameterValidator
import org.springframework.batch.core.Job
import org.springframework.batch.core.Step
import org.springframework.batch.core.configuration.annotation.JobScope
import org.springframework.batch.core.configuration.annotation.StepScope
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.ItemWriter
import org.springframework.batch.item.file.FlatFileItemReader
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.io.ClassPathResource
import org.springframework.transaction.PlatformTransactionManager
@Configuration
class LawdInsertJobConfig(
val jobRepository: JobRepository,
val transactionManager: PlatformTransactionManager,
) {
val chunkSize: Int = 1_000
@Bean
fun lawdInsertJob(lawdInsertStep: Step): Job {
return JobBuilder("lawdInsertJob", jobRepository)
.start(lawdInsertStep)
.incrementer(RunIdIncrementer())
.validator(FilePathParameterValidator())
.build()
}
@JobScope
@Bean
fun lawdInsertStep(
lawdFieldItemReader: FlatFileItemReader<Lawd>,
lawdItemWriter: ItemWriter<Lawd>,
): Step {
return StepBuilder("lawdInsertStep", jobRepository)
.chunk<Lawd, Lawd>(chunkSize, transactionManager)
.reader(lawdFieldItemReader)
.writer(lawdItemWriter)
.build()
}
@Bean
@StepScope
fun lawdFileItemReader(@Value("#{jobParameters['filePath']}") filePath: String): FlatFileItemReader<Lawd> {
return FlatFileItemReaderBuilder<Lawd>()
.name("lawdFileItemReader")
.delimited()
.delimiter("\t")
.names(LAWD_CD, LAWD_DONG, EXIST_YN)
.linesToSkip(1)
.encoding("EUC-KR")
.fieldSetMapper(LawdFieldSetMapper())
.resource(ClassPathResource(filePath))
.build()
}
@Bean
@StepScope
fun lawdItemWriter(): ItemWriter<Lawd> {
return ItemWriter<Lawd> { items ->
items.forEach(::println)
}
}
}
FieldSetMapper 구현
import com.example.kotlinsimplespringbatch.domain.Lawd
import com.example.kotlinsimplespringbatch.job.lawd.LawdFieldSetMapper.companion.EXIST_TRUE
import com.example.kotlinsimplespringbatch.job.lawd.LawdFieldSetMapper.companion.EXIST_YN
import com.example.kotlinsimplespringbatch.job.lawd.LawdFieldSetMapper.companion.LAWD_CD
import com.example.kotlinsimplespringbatch.job.lawd.LawdFieldSetMapper.companion.LAWD_DONG
import org.springframework.batch.item.file.mapping.FieldSetMapper
import org.springframework.batch.item.file.transform.FieldSet
class LawdFieldSetMapper: FieldSetMapper<Lawd> {
object companion {
const val LAWD_CD = "lawdCd"
const val LAWD_DONG = "lawdDong"
const val EXIST_YN = "existYn"
const val EXIST_TRUE = "존재"
}
override fun mapFieldSet(fieldSet: FieldSet): Lawd {
return Lawd(
code = fieldSet.readString(LAWD_CD),
dong = fieldSet.readString(LAWD_DONG),
existYn = fieldSet.readBoolean(EXIST_YN, EXIST_TRUE)
)
}
}
JobParametersValidator
import org.springframework.batch.core.JobParameters
import org.springframework.batch.core.JobParametersInvalidException
import org.springframework.batch.core.JobParametersValidator
import org.springframework.core.io.ClassPathResource
class FilePathParameterValidator: JobParametersValidator {
companion object {
const val FILEPATH = "filePath"
}
override fun validate(parameters: JobParameters?) {
val filePath = parameters?.getString(FILEPATH)
if (filePath.isNullOrBlank()) {
throw JobParametersInvalidException("$FILEPATH parameter is required")
}
val resource = ClassPathResource(filePath)
if (!resource.exists()) {
throw JobParametersInvalidException("$FILEPATH not found")
}
}
}
Resource file
법정동코드 법정동명 폐지여부
1100000000 서울특별시 존재
1111000000 서울특별시 종로구 존재
1111010100 서울특별시 종로구 청운동 존재
1111010200 서울특별시 종로구 신교동 존재
1111010300 서울특별시 종로구 궁정동 존재
1111010400 서울특별시 종로구 효자동 존재
1111010500 서울특별시 종로구 창성동 존재
1111010600 서울특별시 종로구 통의동 존재
1111010700 서울특별시 종로구 적선동 존재
1111010800 서울특별시 종로구 통인동 존재
1111010900 서울특별시 종로구 누상동 존재
1111011000 서울특별시 종로구 누하동 존재
1111011100 서울특별시 종로구 옥인동 존재
1111011200 서울특별시 종로구 체부동 존재
1111090100 서울특별시 종로구 창신1동 폐지
1111090200 서울특별시 종로구 창신2동 폐지
1111090300 서울특별시 종로구 창신3동 폐지
1111090400 서울특별시 종로구 숭인1동 폐지
1111090500 서울특별시 종로구 숭인2동 폐지
'스프링 프레임워크 > springbatch' 카테고리의 다른 글
스프링배치 tasklet기반 step 시작하기 (0) | 2024.08.06 |
---|---|
spring batch chunk기반 step 시작하기 (0) | 2024.07.31 |
spring batch 시작하기 (0) | 2024.07.31 |
springbatch5 h2 database 특정 job 테스트하기 (0) | 2024.07.09 |