Java & Spring/Batch

[Spring] Batch 3

nippycloud 2026. 2. 25. 13:05

Tasklet 방식을 이용한 배치 작업 예시

 

package spring.batch.fileCleanUp;

import java.io.File;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class LogGenerator {
    private static final String ROOT_PATH = "./test-logs";
    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public static void main(String[] args) throws IOException {
        File dir = new File(ROOT_PATH);

        if(!dir.exists()) {
            dir.mkdirs(); // 현재 파일 아래에 test-logs 파일 생성
        }

        // 파일 이름에 날짜를 포함하여 생성 (2026.02.25.log)
        createLogFile(dir, "access", 2); // 2일 전        // access.2026.02.23.log
        createLogFile(dir, "access", 0); // 0일 전 = 금일  // access.2026.02.25.log
        createLogFile(dir, "service", 50); // 50일 전     // access.2025.11.17.log
        createLogFile(dir, "service", 100); // 100일 전   // access.2026.01.06.log

        // 날짜 패턴이 없는 파일 생성, system_config.conf.log 
        createLogFile(dir, "system_config.conf", -1);

        System.out.println("Finish to create test log " + ROOT_PATH);
    }

    private static void createLogFile(File dir, String prefix, int daysAgo) throws IOException {
        String filename;

        if (daysAgo == -1) {
            // 날짜 패턴이 없는 일반 파일
            filename = prefix;
        } else {
            // 날짜 패턴 적용: prefix_yyyy-MM-dd.log
            LocalDate targetDate = LocalDate.now().minusDays(daysAgo);
            String dateStr = targetDate.format(DATE_TIME_FORMATTER);
            filename = prefix + "_" + dateStr + ".log";
        }

        File file = new File(dir, filename);

        if (file.createNewFile()) {
            System.out.println("create new file: " + filename);
        } else {
            System.out.println("already exists: " + filename);
        }
    }
}

 

 

실행 : test-logs 아래에 5개의 파일 생성

 

 

배치 Tasklet 생성

package spring.batch.fileCleanUp;

import lombok.RequiredArgsConstructor;
import org.jspecify.annotations.Nullable;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.StepContribution;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.infrastructure.repeat.RepeatStatus;

import java.io.File;
import java.time.LocalDate;

@RequiredArgsConstructor
public class FileCleanUpTasklet implements Tasklet {

    private final String rootPath;   // 파일을 삭제할 경로
    private final int retentionDays; // 보관할 기간

    @Override
    public @Nullable RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
        LocalDate cutOffDate = LocalDate.now().minusDays(retentionDays); // 현재 날짜 - 보관 기간
        
        File folder = new File(rootPath);
        File[] files = folder.listFiles();

        if (files == null) return RepeatStatus.FINISHED; // 파일이 비어있다면 배치 작업 종료

        for (File file : files) {
            String name = file.getName();

            if (name.endsWith(".log") && name.length() >= 10) { // 날짜가 적힌 파일 판단 : length >= 10
                // "access_2026-01-31.log" => "2026-01-31"
                name = name.substring(name.lastIndexOf("_") + 1, name.lastIndexOf("."));
                LocalDate fileDate = LocalDate.parse(name);

                if (fileDate.isBefore(cutOffDate)) {
                    file.delete();
                    System.out.println("삭제된 로그 파일 : " + name);
                }
            }
        }
        return RepeatStatus.FINISHED;
    }
}

 

 

 

package spring.batch.fileCleanUp;

import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.job.Job;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.Step;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@RequiredArgsConstructor
public class FileCleanUpConfig {
    private final JobRepository jobRepository;
    private final PlatformTransactionManager txManager;

    @Bean
    public Tasklet fileCleanUpTasklet() {
        return new FileCleanUpTasklet("./test-logs", 30); // 30일동안 보관
    }

    @Bean
    public Job fileCleanUpJob() {
        return new JobBuilder("fileCleanUpJob", jobRepository)
                .start(fileCleanUpStep())
                .build();
    }

    @Bean
    public Step fileCleanUpStep() {
        return new StepBuilder("fileCleanUpStep", jobRepository)
                .tasklet(fileCleanUpTasklet(), txManager)
                .build();
    }
}

 

 

 

배치 작업 - fileCleanUpJob 실행

- 금일 날짜 - 30일 (retentionDays)보다 이전인 파일을 삭제

./gradlew bootRun --args='--spring.batch.job.name=fileCleanUpJob'

 

 

 

'Java & Spring > Batch' 카테고리의 다른 글

[Spring] Batch 6  (0) 2026.02.26
[Spring] Batch 5  (0) 2026.02.25
[Spring] Batch 4  (0) 2026.02.25
[Spring] Batch 2  (0) 2026.02.25
[Spring] Batch 1  (0) 2026.02.25