Hello Friends 예제 - 1

2018. 9. 27. 23:16Spring Batch

반응형

HelloJob.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
						http://www.springframework.org/schema/beans/spring-beans.xsd
						http://www.springframework.org/schema/batch
						http://www.springframework.org/schema/batch/spring-batch.xsd">
						
	<job id="HelloJob" xmlns="http://www.springframework.org/schema/batch">
		
		<step id="HelloStep">
			<tasklet>
				<chunk reader="HelloReader"
					processor="HelloProcessor"
					writer="HelloWriter"
					commit-interval="10"/>
			</tasklet>
		</step>
	</job>
	
	<!-- Reader Bean Injection -->
	<bean id="HelloReader" class="com.batchguide.hello.HelloReader" scope="step">
		<property name="bseYm" value="#{jobParameters['BSEYM']}" />
	</bean>
	
	<!-- Processor Bean Injection -->
	<bean id="HelloProcessor" class="com.batchguide.hello.HelloProcessor" />
	
	<!-- Writer Bean Injection -->
	<bean id="HelloWriter" class="com.batchguide.hello.HelloWriter" />
</beans>



CommonUtils.java


package com.batchguide.util;

import java.util.ArrayList;
import java.util.List;

public class CommonUtils {

	/**
	 * 입력 파라미터 정보 추출
	 * 
	 * @param params 입력파라미터
	 * @return 입력파라미터 정보
	 */
	public static ArrayList<String> makeParameters(List<String> params) {
		
		ArrayList<String> retList = new ArrayList<String>();
		
		/*
		 * 입력파라미터는 key=value 형태로 이루어지므로 입력 스트림에 대한 필터 처리 후
		 * 파라미터 정보만 리스트에 담는다.
		 */
		params.stream().filter(p -> p.contains("=")).forEach(param -> {
			retList.add(param.split("=")[0].toUpperCase() + "=" + param.split("=")[1]);
		});
		
		return retList;
	}
	
}

프로그램 실행시 파라미터정보는 key=value 형태로 입력이 되어지는데 입력파라미터만 별도로 추출 하는 함수



RunBatch.java


package com.batchguide.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.concurrent.atomic.AtomicInteger;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import egovframework.rte.bat.core.launch.support.EgovCommandLineRunner;

public class RunBatch {	
	private static final Logger LOGGER = LoggerFactory.getLogger(RunBatch.class);
	
	public static void start(String...args) {
		EgovCommandLineRunner command = new EgovCommandLineRunner();
		
		HashSet<String> opts = new HashSet<String>();
		
		// JOB_PATH 설정
		String jobPath = args[0];
		
		// JOB_ID 설정
		String jobId = args[1];
		
		ArrayList newList = new ArrayList(Arrays.asList(args));
		newList.add("TIMESTAMP=" + (new Date()).getTime());
		
		ArrayList<String> paramList = CommonUtils.makeParameters(newList);
		
		// 입력파라마터출력
		AtomicInteger atomicInteger = new AtomicInteger(0);
		paramList.forEach(p -> System.out.println("Parameter[" + atomicInteger.getAndIncrement() +"] : " + p));
		
		// 리스트 형태의 파라미터를 배열로 변환
		String[] paramArr = paramList.stream().toArray(n -> new String[n]);
		
		// 배치프로그램실행
		int statusCode = command.start(jobPath, jobId, paramArr, opts);
		
		// 배치실행결과출력
		LOGGER.info("Status Code: " + statusCode);
		
		if (statusCode == 0) {
			System.out.println(jobId + " 성공 [SUCCESS]");
		} else {
			LOGGER.error(jobId + " 실패 [FAIL]");
			LOGGER.error("Error Message: " + EgovCommandLineRunner.getErrorMessage());
		}
	}	
}


EgovCommandLineRunner.start 실행 메소드 아래와 같이 4개의 파라미터를 가진다.

/**
 * Batch Job을 실행한다.
 * 실행을 위해서 , Job 이름 / JobExecutionID, Job Parameter
 * 그리고 CommandLineRunner Option가 지정되어야 한다.
 * 
 * @param jobPath : Job Context가 저장된 XML 파일 경로 
 * @param jobIdentifier : Job 이름 /JobExecutionID
 * @param parameters : Job Parameter 
 * @param opts : CommandLineRunner 옵션(-restart, -next, -stop, -abandon)
 */
public int start(String jobPath, String jobIdentifier, String[] parameters, Set<String> opts) {
  ...
}

jobPath : /config/batch/context-base.xml 경로

jobIdentifier(jobId) : HelloJob.xml 에 선언된 job id = "HelloJob"

parameters : key=value구조로 이루어진 배열 입력파라미터

opts : CommandLneRunner 옵션



HelloReader.java


package com.batchguide.hello; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.batch.item.ItemReader; import org.springframework.beans.factory.annotation.Value; public class HelloReader implements ItemReader<String> { private static final Logger LOGGER = LoggerFactory.getLogger(HelloReader.class); @Value("#{jobParameters['bseYm']}") public String bseYm; private String[] names = { "이철수", "김길동", "김영희" }; private int count = 0; @Override public String read() throws Exception { LOGGER.info("JOB PARAMETER VALUE : " + bseYm); if (count < names.length) { return names[count++]; } else { count = 0; } return null; } /** * @param bseYm the bseYm to set */ public void setBseYm(String bseYm) { this.bseYm = bseYm; } }


프로그램 실행 시 입력 받은 파라미터 정보를 설정하기 위해서 @Value("#jobParameters['Key name'] 설정 후 setter method 생성을 통해서 파라미터 값 설정


HelloProcessor.java


package com.batchguide.hello;

import org.springframework.batch.item.ItemProcessor;

public class HelloProcessor implements ItemProcessor<String, String> {

	@Override
	public String process(String name) throws Exception {		
		return name + "!!";
	}

}

특별한 로직은 없는 경우는 Processor 구현은 Skip 가능



HelloWriter.java


package com.batchguide.hello;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemWriter;

public class HelloWriter implements ItemWriter<String> {
	
	private static final Logger LOGGER = LoggerFactory.getLogger(HelloWriter.class);

	@Override
	public void write(List<? extends String> names) throws Exception {
		for (String name : names) {
			LOGGER.info("안녕 " + name);
		}
	}

}


프로그램실행


1. 메인프로그램등록



2. Arguments 설정



3. 프로그램실행결과



실행결과에 프로그램 실행 시 설정한 파라미터 정보도 잘 나오는지 확인하기 위해 출력해보았다.

입력한 값이 정상적으로 출력되는걸 확인 할 수 있다.


다시한번 프로그램을 실행해 보자.


오류가 발생하였다. 

오류메세지 "A job instance already exists and is complete for parameters={BSEYM=201810}"


오류 메세지가 발생한 원인은 jobInstance=Job+JobParameter 인데 동일한 파라미터로 두번 이상 실행하는 경우 동일 Job으로 인식하기 때문에 발생하는 오류이다. 오류해결을 위해서 RunBatch.java 25 Line 아래에 파라미터 정보를 설정해 준다.

newList.add("TIMESTAMP=" + (new Date()).getTime());

프로그램 재실행시 아래와 같이 정상적으로 수행되는 것을 확인 할 수 있을 것이다.



프로그램은 간단 하지만 Hello Friends 프로그램 작성 보다는 환경 설정 부분이 시간이 많이 걸리는 것을 알 수 있을 것이다. 하지만 다른 언어도 마찬가지 겠지만 Hello World를 만든다는 것은 단순히 System.out.println("Hello World")를 출력하기 위함이 아니라 프레임웍 및 구조에 대해 자세히 알아 가는 과정이라는 생각이 든다.


[소스레파지토리]

☞ https://github.com/roopy1210/springbatch/blob/master/spring_batch_tutorial

반응형