스프링 배치 로 기상정보 가져오기 환경설정 (맛보기 시리즈 2-5)

MJ·2025년 8월 29일
post-thumbnail

05. 배치 학습 1단계: 환경설정 및 첫 프로젝트

🎯 학습 목표

  • Spring Batch 개발 환경 완전 구축
  • 가장 간단한 Hello World 배치 작성
  • 배치 실행 및 결과 확인
  • 메타데이터 테이블 이해

🛠️ 개발 환경 설정

1. 필수 소프트웨어 설치

Java Development Kit (JDK 17+)

# Windows (Chocolatey 사용)
choco install openjdk17

# macOS (Homebrew 사용)
brew install openjdk@17

# Linux (Ubuntu)
sudo apt-get install openjdk-17-jdk

# 설치 확인
java -version
javac -version

IntelliJ IDEA 또는 Eclipse

# IntelliJ IDEA Community Edition (무료)
# https://www.jetbrains.com/idea/download/

# Eclipse IDE for Enterprise Java Developers
# https://www.eclipse.org/downloads/

Gradle 또는 Maven

# Gradle 설치 (권장)
# Windows
choco install gradle

# macOS
brew install gradle

# Linux
sudo apt-get install gradle

# 설치 확인
gradle -version

2. Spring Boot 프로젝트 생성

Spring Initializr 사용

  1. 웹 브라우저에서 https://start.spring.io/ 접속

  2. 프로젝트 설정:

    Project: Gradle Project
    Language: Java
    Spring Boot: 3.2.x (안정 버전)
    Group: com.example
    Artifact: batch-tutorial
    Name: batch-tutorial
    Description: Spring Batch Tutorial Project
    Package name: com.example.batchtutorial
    Packaging: Jar
    Java: 17
  3. Dependencies 추가:

    • Spring Batch
    • Spring Boot DevTools
    • H2 Database
    • Spring Data JPA
    • Spring Web (웹 UI용)
  4. GENERATE 클릭 후 다운로드

프로젝트 구조 확인

batch-tutorial/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/example/batchtutorial/
│   │   │       └── BatchTutorialApplication.java
│   │   └── resources/
│   │       └── application.properties
│   └── test/
│       └── java/
│           └── com/example/batchtutorial/
│               └── BatchTutorialApplicationTests.java
├── build.gradle
└── gradlew (Unix용 실행 스크립트)

3. 의존성 설정 확인 및 수정

build.gradle 파일 내용:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.0'
    id 'io.spring.dependency-management' version '1.1.4'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '17'
}

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

repositories {
    mavenCentral()
}

dependencies {
    // Spring Batch 핵심
    implementation 'org.springframework.boot:spring-boot-starter-batch'
    
    // 데이터베이스
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'com.h2database:h2'
    
    // 웹 (모니터링용)
    implementation 'org.springframework.boot:spring-boot-starter-web'
    
    // 개발 편의
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    
    // 로깅 및 유틸리티
    compileOnly 'org.projectlombok:lombok'
    annotationProcessor 'org.projectlombok:lombok'
    
    // 테스트
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.springframework.batch:spring-batch-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

4. 기본 설정 파일 구성

application.properties 설정:

# 애플리케이션 기본 설정
server.port=8080
spring.application.name=batch-tutorial

# H2 데이터베이스 설정
spring.datasource.url=jdbc:h2:mem:batchdb
spring.datasource.username=sa
spring.datasource.password=
spring.datasource.driver-class-name=org.h2.Driver

# H2 콘솔 활성화 (개발용)
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

# JPA/Hibernate 설정
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

# Spring Batch 설정
spring.batch.job.enabled=false
spring.batch.jdbc.initialize-schema=always

# 로깅 설정
logging.level.org.springframework.batch=DEBUG
logging.level.com.example.batchtutorial=DEBUG

🏃‍♂️ 첫 번째 배치 작성

1. Hello World 배치 구현

메인 애플리케이션 클래스:

package com.example.batchtutorial;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BatchTutorialApplication {
    
    public static void main(String[] args) {
        SpringApplication.run(BatchTutorialApplication.class, args);
    }
}

첫 번째 배치 설정 클래스:

package com.example.batchtutorial.config;

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.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

@Slf4j
@Configuration
public class HelloWorldBatchConfig {
    
    @Autowired
    private JobRepository jobRepository;
    
    @Autowired
    private PlatformTransactionManager transactionManager;
    
    /**
     * Hello World Job 정의
     */
    @Bean
    public Job helloWorldJob(Step helloWorldStep) {
        return new JobBuilder("helloWorldJob", jobRepository)
                .start(helloWorldStep)
                .build();
    }
    
    /**
     * Hello World Step 정의 - Tasklet 방식
     */
    @Bean
    public Step helloWorldStep() {
        return new StepBuilder("helloWorldStep", jobRepository)
                .tasklet(helloWorldTasklet(), transactionManager)
                .build();
    }
    
    /**
     * 실제 작업을 수행하는 Tasklet
     */
    @Bean
    public Tasklet helloWorldTasklet() {
        return (contribution, chunkContext) -> {
            log.info("===========================================");
            log.info("🎉 Hello, Spring Batch World!");
            log.info("🚀 첫 번째 배치가 성공적으로 실행되었습니다!");
            log.info("⏰ 실행 시간: {}", java.time.LocalDateTime.now());
            log.info("===========================================");
            
            return RepeatStatus.FINISHED;
        };
    }
}

2. 배치 실행을 위한 컨트롤러 추가

웹 컨트롤러 클래스:

package com.example.batchtutorial.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/batch")
public class BatchController {
    
    @Autowired
    private JobLauncher jobLauncher;
    
    @Autowired
    private Job helloWorldJob;
    
    /**
     * 배치 수동 실행 엔드포인트
     */
    @PostMapping("/hello")
    public String runHelloWorldBatch() {
        try {
            // 매번 다른 파라미터로 실행 (중복 실행 방지)
            JobParameters jobParameters = new JobParametersBuilder()
                    .addLong("timestamp", System.currentTimeMillis())
                    .toJobParameters();
            
            var jobExecution = jobLauncher.run(helloWorldJob, jobParameters);
            
            return String.format(
                "배치가 실행되었습니다! " +
                "Job ID: %d, 상태: %s", 
                jobExecution.getId(), 
                jobExecution.getStatus()
            );
            
        } catch (Exception e) {
            log.error("배치 실행 중 오류 발생", e);
            return "배치 실행 실패: " + e.getMessage();
        }
    }
    
    /**
     * 간단한 상태 확인 페이지
     */
    @GetMapping("/status")
    public String getStatus() {
        return "Spring Batch Tutorial 애플리케이션이 실행 중입니다! " +
               "POST /batch/hello 로 배치를 실행하세요.";
    }
}

3. 간단한 웹 페이지 추가 (선택사항)

HTML 템플릿 (src/main/resources/static/index.html):

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Spring Batch Tutorial</title>
    <style>
        body { 
            font-family: Arial, sans-serif; 
            max-width: 800px; 
            margin: 50px auto; 
            padding: 20px; 
        }
        .container { 
            text-align: center; 
            background: #f5f5f5; 
            padding: 30px; 
            border-radius: 10px; 
        }
        button { 
            background: #007bff; 
            color: white; 
            border: none; 
            padding: 15px 30px; 
            font-size: 16px; 
            border-radius: 5px; 
            cursor: pointer; 
            margin: 10px;
        }
        button:hover { background: #0056b3; }
        .result { 
            margin-top: 20px; 
            padding: 15px; 
            background: white; 
            border-radius: 5px; 
            border-left: 4px solid #007bff;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>🚀 Spring Batch Tutorial</h1>
        <p>첫 번째 Spring Batch 프로젝트에 오신 것을 환영합니다!</p>
        
        <button onclick="runBatch()">📤 Hello World 배치 실행</button>
        <button onclick="openH2Console()">🗄️ H2 데이터베이스 콘솔</button>
        
        <div id="result" class="result" style="display: none;">
            <h3>실행 결과:</h3>
            <p id="resultText"></p>
        </div>
    </div>
    
    <script>
        function runBatch() {
            const button = event.target;
            button.disabled = true;
            button.innerHTML = '⏳ 실행 중...';
            
            fetch('/batch/hello', { method: 'POST' })
                .then(response => response.text())
                .then(data => {
                    document.getElementById('result').style.display = 'block';
                    document.getElementById('resultText').textContent = data;
                    button.disabled = false;
                    button.innerHTML = '📤 Hello World 배치 실행';
                })
                .catch(error => {
                    alert('오류 발생: ' + error);
                    button.disabled = false;
                    button.innerHTML = '📤 Hello World 배치 실행';
                });
        }
        
        function openH2Console() {
            window.open('/h2-console', '_blank');
        }
    </script>
</body>
</html>

🏃‍♂️ 프로젝트 실행 및 테스트

1. 애플리케이션 빌드 및 실행

터미널에서 실행:

# 프로젝트 디렉토리로 이동
cd batch-tutorial

# Gradle로 빌드 및 실행
./gradlew bootRun

# Windows에서는
gradlew.bat bootRun

실행 로그 확인:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.2.0)

2024-08-27 10:30:15.123  INFO --- [main] c.e.b.BatchTutorialApplication : Starting BatchTutorialApplication
2024-08-27 10:30:16.456  INFO --- [main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http)
2024-08-27 10:30:16.789  INFO --- [main] c.e.b.BatchTutorialApplication : Started BatchTutorialApplication in 2.345 seconds

2. 배치 실행 테스트

방법 1: 웹 브라우저 사용

  1. http://localhost:8080 접속
  2. "Hello World 배치 실행" 버튼 클릭
  3. 실행 결과 확인

방법 2: cURL 명령어 사용

# 배치 실행
curl -X POST http://localhost:8080/batch/hello

# 응답 예시:
# 배치가 실행되었습니다! Job ID: 1, 상태: COMPLETED

방법 3: IDE에서 직접 실행

// 테스트 클래스 작성
@SpringBootTest
class HelloWorldBatchTest {
    
    @Autowired
    private JobLauncher jobLauncher;
    
    @Autowired
    private Job helloWorldJob;
    
    @Test
    void testHelloWorldBatch() throws Exception {
        JobParameters jobParameters = new JobParametersBuilder()
                .addLong("timestamp", System.currentTimeMillis())
                .toJobParameters();
        
        JobExecution jobExecution = jobLauncher.run(helloWorldJob, jobParameters);
        
        assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
    }
}

3. 실행 결과 확인

콘솔 로그:

2024-08-27 10:35:22.123  INFO --- [http-nio-8080-exec-1] c.e.b.config.HelloWorldBatchConfig : ===========================================
2024-08-27 10:35:22.124  INFO --- [http-nio-8080-exec-1] c.e.b.config.HelloWorldBatchConfig : 🎉 Hello, Spring Batch World!
2024-08-27 10:35:22.124  INFO --- [http-nio-8080-exec-1] c.e.b.config.HelloWorldBatchConfig : 🚀 첫 번째 배치가 성공적으로 실행되었습니다!
2024-08-27 10:35:22.125  INFO --- [http-nio-8080-exec-1] c.e.b.config.HelloWorldBatchConfig : ⏰ 실행 시간: 2024-08-27T10:35:22.124
2024-08-27 10:35:22.125  INFO --- [http-nio-8080-exec-1] c.e.b.config.HelloWorldBatchConfig : ===========================================

📊 메타데이터 테이블 확인

1. H2 콘솔 접속

  1. http://localhost:8080/h2-console 접속
  2. JDBC URL: jdbc:h2:mem:batchdb
  3. 사용자명: sa
  4. 비밀번호: (비워두기)
  5. Connect 클릭

2. Spring Batch 메타데이터 테이블들

주요 테이블 구조:

-- Job 인스턴스 정보
SELECT * FROM BATCH_JOB_INSTANCE;

-- Job 실행 정보
SELECT 
    JOB_EXECUTION_ID,
    JOB_INSTANCE_ID,
    CREATE_TIME,
    START_TIME,
    END_TIME,
    STATUS,
    EXIT_CODE
FROM BATCH_JOB_EXECUTION;

-- Step 실행 정보
SELECT 
    STEP_EXECUTION_ID,
    JOB_EXECUTION_ID,
    STEP_NAME,
    STATUS,
    READ_COUNT,
    WRITE_COUNT,
    COMMIT_COUNT,
    START_TIME,
    END_TIME
FROM BATCH_STEP_EXECUTION;

-- Job 파라미터
SELECT * FROM BATCH_JOB_EXECUTION_PARAMS;

실행 결과 예시:

BATCH_JOB_EXECUTION 테이블:
JOB_EXECUTION_ID | JOB_INSTANCE_ID | STATUS    | START_TIME          | END_TIME
1                | 1               | COMPLETED | 2024-08-27 10:35:22 | 2024-08-27 10:35:22

BATCH_STEP_EXECUTION 테이블:
STEP_EXECUTION_ID | JOB_EXECUTION_ID | STEP_NAME        | STATUS    | COMMIT_COUNT
1                 | 1                | helloWorldStep   | COMPLETED | 1

✅ 학습 체크포인트

완료해야 할 작업들:

  • Java 17+ 설치 및 확인
  • IDE (IntelliJ 또는 Eclipse) 설치
  • Spring Boot 프로젝트 생성
  • 의존성 설정 확인
  • Hello World 배치 구현
  • 웹 컨트롤러 작성
  • 애플리케이션 실행 성공
  • 배치 실행 및 로그 확인
  • H2 콘솔에서 메타데이터 테이블 확인

확인 질문:

  1. JobRepository의 역할은 무엇인가요?
  2. Tasklet과 Chunk 방식의 차이점은?
  3. JobParameters가 왜 필요한가요?
  4. 배치 실행 상태는 어디에 저장되나요?

다음 단계 준비:

  • ItemReader, ItemProcessor, ItemWriter 개념 학습
  • 실제 데이터(CSV 파일) 처리 배치 구현
  • 에러 처리 및 재시작 기능

🎉 축하합니다! 첫 번째 Spring Batch 프로젝트를 성공적으로 완성했습니다. 이제 다음 단계로 넘어가서 더 실용적인 배치를 만들어보겠습니다.

profile
..

0개의 댓글