Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions src/main/java/woojooin/planitbatch/batch/job/BatchConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import lombok.RequiredArgsConstructor;

@Configuration
@EnableBatchProcessing
@RequiredArgsConstructor
public class BatchConfig {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;

private final JobBuilderFactory jobs;

private final StepBuilderFactory steps;

@Bean
public Step sampleStep() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package woojooin.planitbatch.batch.job;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.item.ItemReader;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import lombok.RequiredArgsConstructor;
import woojooin.planitbatch.batch.processor.IsaTaxSavingProcessor;
import woojooin.planitbatch.batch.reader.IsaTaxSavingReader;
import woojooin.planitbatch.batch.writer.IsaTaxSavingWriter;
import woojooin.planitbatch.domain.dto.UserProductQuarterData;
import woojooin.planitbatch.domain.vo.IsaTaxSavingHistoryVo;

@Configuration
@RequiredArgsConstructor
public class IsaTaxSavingJobConfig {

private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;
private final IsaTaxSavingReader reader;
private final IsaTaxSavingProcessor processor;
private final IsaTaxSavingWriter writer;

@Bean
public Job isaTaxSavingJob(@Qualifier("isaTaxReader") ItemReader<UserProductQuarterData> reader) {
Step isaTaxSavingStep = stepBuilderFactory.get("isaTaxSavingStep")
.<UserProductQuarterData, IsaTaxSavingHistoryVo>chunk(100)
.reader(reader)
.processor(processor)
.writer(writer)
.build();

return jobBuilderFactory.get("isaTaxSavingJob")
.start(isaTaxSavingStep)
.build();
}



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package woojooin.planitbatch.batch.processor;

import java.math.BigDecimal;

import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import woojooin.planitbatch.domain.dto.UserProductQuarterData;
import woojooin.planitbatch.domain.vo.IsaTaxSavingHistoryVo;
import woojooin.planitbatch.global.util.IsaTaxCalculator;

@Component
@RequiredArgsConstructor
@Slf4j
public class IsaTaxSavingProcessor implements ItemProcessor<UserProductQuarterData, IsaTaxSavingHistoryVo> {
@Override
public IsaTaxSavingHistoryVo process(UserProductQuarterData item) throws Exception {
Long memberId = item.getMemberId();
String quarter = item.getQuarter();
// "general" 타입 고정, 필요시 변경 가능
String userType = "general";

if (item.getTotalProfit() == null) {
item.setTotalProfit(BigDecimal.ZERO);
}

return IsaTaxCalculator.calculateIsaTaxSavingHistoryVo(memberId, quarter, item.getTotalProfit(), userType);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package woojooin.planitbatch.batch.reader;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.batch.MyBatisPagingItemReader;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import woojooin.planitbatch.domain.dto.UserProductQuarterData;

@Configuration
@RequiredArgsConstructor
@Slf4j
public class IsaTaxSavingReader {

private final SqlSessionFactory sqlSessionFactory;

@Bean(name = "isaTaxReader")
@StepScope
public MyBatisPagingItemReader<UserProductQuarterData> isaTaxReader() {

MyBatisPagingItemReader<UserProductQuarterData> reader = new MyBatisPagingItemReader<>();
reader.setSqlSessionFactory(sqlSessionFactory);
reader.setQueryId("woojooin.planitbatch.domain.mapper.IsaTaxSavingMapper.selectIsaProductProfitByMember");
reader.setPageSize(100);
return reader;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package woojooin.planitbatch.batch.scheduler;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@RequiredArgsConstructor
public class IsaTaxSavingJobBatchScheduler {

private final JobLauncher jobLauncher;
private final JobExplorer jobExplorer;
private final Job isaTaxSavingJob;

@Scheduled(cron = "0 13 11 * * *") // 매일 2시 20분에 실행
public void runIsaTaxSavingJob() {
String jobName = isaTaxSavingJob.getName();

JobParameters jobParameters = new JobParametersBuilder()
.addLong("timestamp", System.currentTimeMillis()) // 매 실행마다 달라지는 값
.toJobParameters();

try {
// 현재 실행 중인 동일 Job이 있는지 확인 (jobName 기준)
if (!jobExplorer.findRunningJobExecutions(jobName).isEmpty()) {
log.warn("[스케줄러] Job '{}'이(가) 이미 실행 중입니다. 실행을 건너뜁니다.", jobName);
return;
}

log.info("[스케줄러] Job '{}' 실행을 시작합니다.", jobName);
JobExecution jobExecution = jobLauncher.run(isaTaxSavingJob, jobParameters);
log.info("[스케줄러] Job '{}' 실행 상태: {}", jobName, jobExecution.getStatus());

} catch (Exception e) {
log.error("[스케줄러] Job '{}' 실행 중 예외가 발생했습니다.", jobName, e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package woojooin.planitbatch.batch.writer;

import java.util.List;

import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.springframework.batch.item.ItemWriter;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import woojooin.planitbatch.domain.mapper.IsaTaxSavingMapper;
import woojooin.planitbatch.domain.vo.IsaTaxSavingHistoryVo;

@Component
@RequiredArgsConstructor
@Slf4j
public class IsaTaxSavingWriter implements ItemWriter<IsaTaxSavingHistoryVo> {

private final SqlSessionFactory sqlSessionFactory;

@Override
public void write(List<? extends IsaTaxSavingHistoryVo> items) throws Exception {

try (SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false)) {
IsaTaxSavingMapper mapper = sqlSession.getMapper(IsaTaxSavingMapper.class);
for (IsaTaxSavingHistoryVo item : items) {
mapper.upsertIsaTaxSavingHistory(item);
}
sqlSession.commit();
} catch (Exception e) {
e.printStackTrace();
}
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package woojooin.planitbatch.domain.dto;


import java.math.BigDecimal;
import lombok.Data;

@Data
public class UserProductQuarterData {
private Long memberId;
private String quarter;
private BigDecimal totalProfit;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package woojooin.planitbatch.domain.mapper;

import java.util.List;


import woojooin.planitbatch.domain.dto.UserProductQuarterData;
import woojooin.planitbatch.domain.vo.IsaTaxSavingHistoryVo;

public interface IsaTaxSavingMapper {
List<UserProductQuarterData> selectIsaProductProfitByMember();

int upsertIsaTaxSavingHistory(IsaTaxSavingHistoryVo vo);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package woojooin.planitbatch.domain.vo;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;

import lombok.Builder;
import lombok.Data;

@Data
public class IsaTaxSavingHistoryVo {

private Long memberId;
private String quarter; // 예: "2024-Q1"
private Long isaProfit; // ISA 수익
private Long generalTax; // 일반계좌였다면 냈을 세금 = isaProfit * 0.154
private Long taxSaved; // 절세 금액 = generalTax - 0 = generalTax

}

Loading