feat: Add batch & sampleJob & dependency

This commit is contained in:
yoosangwook 2024-11-06 10:25:51 +09:00
parent 2789a26956
commit 4fd3342cb9
12 changed files with 364 additions and 127 deletions

10
pom.xml
View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@ -26,6 +26,14 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>

View File

@ -3,8 +3,10 @@ package com.interplug.qcast;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableScheduling
public class QCastApplication {
public static void main(String[] args) {

View File

@ -0,0 +1,91 @@
package com.interplug.qcast.batch;
import java.util.Date;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class JobLauncherController {
private final Map<String, Job> jobs; // 여러 Job을 주입받도록 변경
private final JobLauncher jobLauncher;
/**
* 특정 Job을 매핑으로 실행하는 메소드
*
* @param jobName
* @return
* @throws JobInstanceAlreadyCompleteException
* @throws JobExecutionAlreadyRunningException
* @throws JobParametersInvalidException
* @throws JobRestartException
*/
@GetMapping("/batch/job/{jobName}") // Path Variable로 jobName을 받음
public String launchJob(@PathVariable String jobName)
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
Job job = jobs.get(jobName);
if (job == null) {
return "Job " + jobName + " not found";
}
JobParameters jobParameters =
new JobParametersBuilder()
.addString("jobName", jobName)
.addDate("time", new Date())
.toJobParameters();
jobLauncher.run(job, jobParameters);
return "Job " + jobName + " started";
}
/**
* 스케줄러로 Job을 실행하는 메소드
*
* @return
* @throws JobInstanceAlreadyCompleteException
* @throws JobExecutionAlreadyRunningException
* @throws JobParametersInvalidException
* @throws JobRestartException
*/
@Scheduled(cron = "0 55 23 * * *")
public String scheduleJobLauncher()
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
String jobName = "sampleOtherJob";
Job job = jobs.get(jobName);
if (job == null) {
return "Job " + jobName + " not found";
}
JobParameters jobParameters =
new JobParametersBuilder()
.addString("jobName", jobName)
.addDate("time", new Date())
.toJobParameters();
jobLauncher.run(job, jobParameters);
return "Job " + jobName + " started";
}
}

View File

@ -0,0 +1,55 @@
package com.interplug.qcast.batch;
import java.util.Arrays;
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.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/** chunk 방식의 Job을 생성하는 Configuration */
@Configuration
public class SampleJobConfiguration {
@Bean
public Job sampleJob(JobRepository jobRepository, Step sampleStep) {
return new JobBuilder("sampleJob", jobRepository).start(sampleStep).build();
}
@Bean
public Step sampleStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("sampleStep", jobRepository)
.<String, String>chunk(10, transactionManager)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
@Bean
public ItemReader<String> reader() {
return new ListItemReader<>(Arrays.asList("Spring", "Batch", "Example"));
}
@Bean
public ItemProcessor<String, String> processor() {
return item -> item.toUpperCase();
}
@Bean
public ItemWriter<String> writer() {
return items -> {
for (String item : items) {
System.out.println("Processing item: " + item);
}
};
}
}

View File

@ -0,0 +1,50 @@
package com.interplug.qcast.batch;
import java.util.Date;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.JobParametersInvalidException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
import org.springframework.batch.core.repository.JobRestartException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SampleJobLauncherController {
@Qualifier("sampleJob")
@Autowired
private Job job;
@Autowired private JobLauncher jobLauncher;
/**
* 특정 Job을 매핑과 스케쥴러로 실행하는 메소드
*
* @return
* @throws JobInstanceAlreadyCompleteException
* @throws JobExecutionAlreadyRunningException
* @throws JobParametersInvalidException
* @throws JobRestartException
*/
@Scheduled(cron = "0 45 23 * * *")
@GetMapping("/batch/sampleJob")
public String launchSampleJob()
throws JobInstanceAlreadyCompleteException,
JobExecutionAlreadyRunningException,
JobParametersInvalidException,
JobRestartException {
JobParameters jobParameters =
new JobParametersBuilder().addDate("time", new Date()).toJobParameters();
jobLauncher.run(job, jobParameters);
return "OK";
}
}

View File

@ -0,0 +1,42 @@
package com.interplug.qcast.batch;
import java.util.Arrays;
import java.util.List;
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.repeat.RepeatStatus;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
/** tasklet 방식의 Job을 생성하는 Configuration */
@Configuration
public class SampleOtherJobConfiguration {
@Bean
public Job sampleOtherJob(JobRepository jobRepository, Step sampleStep) {
return new JobBuilder("sampleOtherJob", jobRepository).start(sampleStep).build();
}
@Bean
public Step sampleOtherStep(
JobRepository jobRepository, PlatformTransactionManager transactionManager) {
return new StepBuilder("sampleOtherStep", jobRepository)
.tasklet(
(contribution, chunkContext) -> {
List<String> items = Arrays.asList("Spring", "Batch", "Example");
for (String item : items) {
String processedItem = item.toUpperCase();
System.out.println("Processing item: " + processedItem);
}
return RepeatStatus.FINISHED;
},
transactionManager)
.build();
}
}

View File

@ -1,22 +1,17 @@
package com.interplug.qcast.config.datasource;
import com.zaxxer.hikari.HikariDataSource;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
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.DependsOn;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
import org.springframework.transaction.PlatformTransactionManager;
/** data source config */
@ -24,58 +19,23 @@ import org.springframework.transaction.PlatformTransactionManager;
@MapperScan(basePackages = {"com.interplug.qcast"})
public class DataSourceConfig {
protected static final String MASTER = "masterDataSource";
protected static final String READ = "readDataSource";
/** masterDataSource config */
/** dataSource config */
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
/** readDataSource config */
@Bean
@ConfigurationProperties(prefix = "spring.datasource.read")
public DataSource readDataSource() {
return DataSourceBuilder.create().type(HikariDataSource.class).build();
}
/** routingDataSource config */
@Bean
public DataSource routingDataSource(
@Qualifier(MASTER) DataSource master, @Qualifier(READ) DataSource slave) {
Map<Object, Object> dataSources = new HashMap<>();
dataSources.put(MASTER, master);
dataSources.put(READ, slave);
RoutingDataSource routingDataSource = new RoutingDataSource();
routingDataSource.setTargetDataSources(dataSources);
routingDataSource.setDefaultTargetDataSource(master);
return routingDataSource;
}
/** lazyDataSource config */
@Bean
@DependsOn({"routingDataSource"})
public LazyConnectionDataSourceProxy lazyDataSource(
@Qualifier("routingDataSource") DataSource dataSource) {
return new LazyConnectionDataSourceProxy(dataSource);
}
/** transactionManager config */
@Bean
public PlatformTransactionManager transactionManager(
@Qualifier("lazyDataSource") DataSource dataSource) {
public PlatformTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
/** sqlSessionFactory config */
@Bean
@SuppressWarnings("PMD.SignatureDeclareThrowsException")
public SqlSessionFactory sqlSessionFactory(LazyConnectionDataSourceProxy dataSource)
throws Exception {
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
@ -87,8 +47,7 @@ public class DataSourceConfig {
/** sqlSessionTemplate config */
@Bean
public SqlSessionTemplate sqlSessionTemplate(
@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory) {
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}

View File

@ -1,18 +0,0 @@
package com.interplug.qcast.config.datasource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/** RoutingDataSource config */
public class RoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
boolean isReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
if (isReadOnly) {
return DataSourceConfig.READ;
} else {
return DataSourceConfig.MASTER;
}
}
}

View File

@ -5,23 +5,35 @@ server:
#spring
spring:
datasource:
datasource:
master:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Master-HikariPool
read:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Read-HikariPool
# datasource:
# master:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Master-HikariPool
# read:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Read-HikariPool
jackson:
time-zone: Asia/Seoul
batch:
jdbc:
initialize-schema: never
job:
names: ${job.name:NONE}
enabled: false
#QSP
qsp:

View File

@ -5,23 +5,35 @@ server:
#spring
spring:
datasource:
datasource:
master:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Master-HikariPool
read:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Read-HikariPool
# datasource:
# master:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Master-HikariPool
# read:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Read-HikariPool
jackson:
time-zone: Asia/Seoul
batch:
jdbc:
initialize-schema: never
job:
names: ${job.name:NONE}
enabled: false
#QSP
qsp:
@ -33,5 +45,5 @@ qsp:
#File
file:
root.path: C:\\
ini.root.path: C:\\NewEstimate
ini.root.path: /Users/yoosangwook/dev/myworks/NewEstimate
ini.base.filename: 料金シミュレーション.ini

View File

@ -5,23 +5,35 @@ server:
#spring
spring:
datasource:
datasource:
master:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Master-HikariPool
read:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Read-HikariPool
# datasource:
# master:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Master-HikariPool
# read:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Read-HikariPool
jackson:
time-zone: Asia/Seoul
batch:
jdbc:
initialize-schema: never
job:
names: ${job.name:NONE}
enabled: false
#QSP
qsp:

View File

@ -12,24 +12,36 @@ spring:
profiles:
active: local
datasource:
master:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Master-HikariPool
# connection-test-query: SELECT 1
read:
driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
username: pvDBuser
password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
maximum-pool-size: 4
pool-name: Read-HikariPool
# master:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Master-HikariPool
# # connection-test-query: SELECT 1
# read:
# driver-class-name: net.sf.log4jdbc.sql.jdbcapi.DriverSpy
# jdbc-url: jdbc:log4jdbc:sqlserver://1.248.227.176:1433;databaseName=NEWPVCAD;encrypt=true;trustServerCertificate=true
# username: pvDBuser
# password: ENC(W7owprYnvf7vqwO6Piw4dHfVBCSxE4Ck)
# maximum-pool-size: 4
# pool-name: Read-HikariPool
# connection-test-query: SELECT 2
jackson:
time-zone: Asia/Seoul
batch:
jdbc:
initialize-schema: never
job:
names: ${job.name:NONE}
enabled: false
management:
endpoints: