두리공장
[spring batch] 스프링 부트 프로젝트에 스프링 배치 이식하기 본문
스프링 부트로 개발된 back-end 에 스프링 배치를 이식해야 할 경우가 생겼다.
이렇게 하려면, 아래와 같은 순서로 셋팅해야 한다.
1. pom.xml 에 의존성 추가 (dbcp 포함)
2. application.yml 에 db connection 정보 추가
3. DataSourceConfig, VO 추가
4. 시작 지점에 스케줄러 추가
5. JobConfig 구현 (Job, Step, tasklet, ItemReader, ItemWriter)...
순서대로 셋팅해 보자
pom.xml 에 의존성 추가 (dbcp 포함)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
2. application.yml 에 db connection 정보 추가
postgres:
jdbc-url: jdbc:postgresql://localhost:5432/${db schema}
username: ${id}
password: ${password}
driver-class-name: org.postgresql.Driver
3. DataSourceConfig, VO 추가
package com.sunnier.api.batch;
import com.zaxxer.hikari.HikariDataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean(name="postgres")
@Primary
@ConfigurationProperties("spring.postgres")
public DataSource postgres(){
DataSourceBuilder builder = DataSourceBuilder.create();
builder.type(HikariDataSource.class);
return builder.build();
}
// @Value("${spring.datasource.driver-class-name}")
// private String postgresDriverClassName;
//
// @Value("${spring.datasource.url}")
// private String postgresJJdbcUrl;
//
// @Value("${spring.datasource.username}")
// private String postgresJdbcUsername;
//
// @Value("${spring.datasource.password}")
// private String postgresJdbcPassword;
//
// @Bean(name="postgres")
// @Primary
// public DataSource postgresDataSource() {
// return getDataSource(postgresDriverClassName,postgresJJdbcUrl, postgresJdbcUsername, postgresJdbcPassword);
// }
// public DataSource getDataSource(String externalDriverClassName, String externalJdbcUrl, String externalJdbcUsername, String externalJdbcPassword){
// BasicDataSource dataSource = new BasicDataSource();
// dataSource.setDriverClassName(externalDriverClassName);
// dataSource.setUrl(externalJdbcUrl);
// dataSource.setUsername(externalJdbcUsername);
// dataSource.setPassword(externalJdbcPassword);
// return dataSource;
// }
}
package com.sunnier.api.batch;
import lombok.Data;
@Data
public class CustomerVO {
private String id;
private String name;
private String countryname;
}
4. 시작 지점에 스케줄러 추가
@SpringBootApplication
@EnableScheduling
public class SunnierApiApplication {
public static void main(String[] args) {
SpringApplication.run(SunnierApiApplication.class, args);
}
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job job;
//잡을 실행한다.
@Scheduled(cron = "0 0/1 * * * *")
public void jobExecute() throws Exception {
if(jobLauncher == null){
jobLauncher = new SimpleJobLauncher();
}
JobParameters param = new JobParametersBuilder().addString("JobId", String.valueOf(System.currentTimeMillis())).toJobParameters();
System.out.println("server IP : " + ip);
if(ip.equals("192.168.0.71")) {
System.out.println("=======start job========");
jobLauncher.run(job, param);
System.out.println("=======end job========");
}
}
}
5. JobConfig 구현 (Job, Step, tasklet, ItemReader, ItemWriter)...
package com.sunnier.api.batch;
import com.sunnier.api.portal.freeboard.service.BoardService;
import com.sunnier.api.portal.freeboard.vo.BoardVo;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.adapter.ItemWriterAdapter;
import org.springframework.batch.item.database.JdbcCursorItemReader;
import org.springframework.batch.item.database.builder.JdbcCursorItemReaderBuilder;
import org.springframework.batch.item.support.CompositeItemWriter;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Configuration
@EnableBatchProcessing
public class JobConfig {
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private BoardService boardService;
@Bean
public Job queryExecuteJob() throws Exception{
return this.jobBuilderFactory.get("queryExecuteJob")
.start(queryExecuteStep())
.next(callKakaoStep())
.build();
}
//쿼리를 실행한다.(tasklet)
@Bean
public Step queryExecuteStep(@Qualifier("postgres")DataSource dataSource){
String sql = "insert into COUNTRIES_BATCH " +
"select " +
"* " +
"from COUNTRIES " +
"where NAME like 'H%'";
return this.stepBuilderFactory.get("queryExecuteStep")
.tasklet(((stepContribution, chunkContext) -> {
System.out.println("Hello, world");
List<BoardVo> list = boardService.findAll();
System.out.println("데이터를 조회해 온다." + list.get(0).getTitle());
// select insert 쿼리를 실행한다.
new JdbcTemplate(dataSource).execute(sql);
return RepeatStatus.FINISHED;
}))
.build();
}
//데이터를 읽은다음, 카카오 알림톡으로 메시지를 발송하고, 결과를 업데이트 한다.
public Step callKakaoStep() throws Exception{
return this.stepBuilderFactory.get("callKakaoStep")
.chunk(10)
.reader(tableItemReader(null))
.writer(compositeItemWriter())
.build();
}
//데이터 리더 구현
@Bean
public JdbcCursorItemReader<CustomerVO> tableItemReader(@Qualifier("postgres")DataSource dataSource) throws Exception {
String sql = "select id,name,countryname from customer_large";
return new JdbcCursorItemReaderBuilder<CustomerVO>()
.name("tableItemReader")
.dataSource(dataSource)
.rowMapper(new BeanPropertyRowMapper<>(CustomerVO.class))
.sql(sql)
.build();
}
//데이터 라이터 구현
@Bean
public CompositeItemWriter compositeItemWriter() throws Exception {
final CompositeItemWriter<CustomerVO> compositeItemWriter = new CompositeItemWriter<>();
compositeItemWriter.setDelegates(Arrays.asList(
callKakaoApiWriter(null),
printItemWriter()));
return compositeItemWriter;
}
//카카오 알림톡 발송용 라이터 구현
@Bean
public ItemWriter<CustomerVO> callKakaoApiWriter(KakaoAPIService apiService) throws Exception {
ItemWriterAdapter<CustomerVO> itemWriterAdapter = new ItemWriterAdapter<>();
itemWriterAdapter.setTargetObject(apiService);
itemWriterAdapter.setTargetMethod("SendMessage");
return itemWriterAdapter;
}
//카카오 알림톡 발송을 위한 샘플 클래스
@Service
public class KakaoAPIService{
public Map<String, Object> SendMessage(){
Map<String, Object> result = new HashMap<>();
result.put("message", "OK");
return result;
}
}
//화면 출력을 위한 라이터
public ItemWriter<CustomerVO> printItemWriter() throws Exception {
return new ItemWriter<CustomerVO>() {
@Override
public void write(List<? extends CustomerVO> list) throws Exception {
for(CustomerVO item : list){
System.out.println("item result =======> " + item.getCountryname());
}
}
};
}
//카카오 알림톡 발송후 결과 업데이터 라이터 구현
}
끝.
'java' 카테고리의 다른 글
Mybatis 에서 model 에서 innerClass 를 사용하려면?? (0) | 2022.07.28 |
---|---|
스프링 부트 프로젝트에서 OZ리포트 jar 라이브러리 사용시.. (0) | 2022.06.11 |
[Spring batch] Step 9 - 배치시작을 위한 config 및 h2 메모리DB구성, 그리고 itemprocessor 사용 (0) | 2022.06.11 |
spring job scheduler & shedLock 적용 (0) | 2022.06.09 |
[Spring & jQuery] 파일 및 Json 데이터 업로드 (file & json data) (0) | 2022.05.30 |