Skip to content

Commit

Permalink
Merge pull request #262 from WE-ARE-RACCOONS/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ywj9811 authored May 14, 2024
2 parents 561979d + 49d673a commit 91df0b8
Show file tree
Hide file tree
Showing 77 changed files with 1,142 additions and 517 deletions.
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ repositories {

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-amqp'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.boot:spring-boot-starter-security'
Expand Down Expand Up @@ -77,6 +76,10 @@ dependencies {
// https://mvnrepository.com/artifact/org.mockito/mockito-core
testImplementation 'org.mockito:mockito-core:5.6.0'

// spring-batch
implementation 'org.springframework.boot:spring-boot-starter-batch'
testImplementation 'org.springframework.batch:spring-batch-test'

}

tasks.named('test') {
Expand Down
86 changes: 86 additions & 0 deletions src/main/java/com/postgraduate/batch/cancel/CancelJobConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package com.postgraduate.batch.cancel;

import lombok.RequiredArgsConstructor;
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.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.PagingQueryProvider;
import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder;
import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;

import static java.time.LocalDateTime.now;

@Configuration
@RequiredArgsConstructor
@Slf4j
public class CancelJobConfig {
private final JobRepository jobRepository;
private final PlatformTransactionManager transactionManager;
private final CancelMentoringWriter cancelMentoringWriter;
private final DataSource dataSource;

private static final int CHUNK_SIZE = 50;

@Bean(name = "cancelJob")
public Job cancelJob() throws Exception {
return new JobBuilder("cancelJob", jobRepository)
.start(cancelStep())
.build();
}

@Bean(name = "cancelStep")
public Step cancelStep() throws Exception {
return new StepBuilder("cancelStep", jobRepository)
.<CancelMentoring, CancelMentoring>chunk(CHUNK_SIZE, transactionManager)
.reader(itemReader())
.writer(cancelMentoringWriter)
.faultTolerant()
.skip(Exception.class)
.skipLimit(Integer.MAX_VALUE)
.build();
}

@Bean(name = "cancelReader")
public JdbcPagingItemReader<CancelMentoring> itemReader() throws Exception {
Map<String, Object> parameter = new HashMap<>();
LocalDateTime now = now()
.toLocalDate()
.atStartOfDay();
parameter.put("date", Timestamp.valueOf(now));

return new JdbcPagingItemReaderBuilder<CancelMentoring>()
.pageSize(CHUNK_SIZE)
.fetchSize(CHUNK_SIZE)
.dataSource(dataSource)
.rowMapper(new CancelMentoringRowMapper())
.queryProvider(cancelQueryProvider())
.parameterValues(parameter)
.name("cancelReader")
.build();
}

@Bean(name = "cancelQuery")
public PagingQueryProvider cancelQueryProvider() throws Exception {
SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean();
queryProvider.setDataSource(dataSource);
queryProvider.setSelectClause("select mentoring_id, user_user_id, senior_senior_id, payment_payment_id");
queryProvider.setFromClause("from mentoring");
queryProvider.setWhereClause("where status = 'WAITING' and created_at < :date");
queryProvider.setSortKey("mentoring_id");
return queryProvider.getObject();
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.postgraduate.batch.cancel;

public record CancelMentoring(
Long mentoringId,
Long userId,
Long seniorId,
Long paymentId
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.postgraduate.batch.cancel;

import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@RequiredArgsConstructor
public class CancelMentoringRepository{
private final NamedParameterJdbcTemplate jdbcTemplate;
private static final String AUTO_CANCEL = "자동취소";
private static final String UPDATE_MENTORING = "update mentoring set status = 'CANCEL' where mentoring_id = :mentoringId";
private static final String INSERT_REFUSE = "insert into refuse(" +
"mentoring_mentoring_id, " +
"reason" +
") values(" +
":mentoringId, :reason" +
")";

public void insertAllRefuse(List<CancelMentoring> mentorings) {
jdbcTemplate.batchUpdate(INSERT_REFUSE, generateParameterSource(mentorings));
}

public void updateAllMentoring(List<CancelMentoring> mentorings) {
jdbcTemplate.batchUpdate(UPDATE_MENTORING, generateParameterSource(mentorings));
}

private SqlParameterSource[] generateParameterSource(List<CancelMentoring> mentorings) {
return mentorings.stream()
.map(mentoring -> new MapSqlParameterSource(generateEntityParams(mentoring)))
.toArray(SqlParameterSource[]::new);
}

private Map<String, Object> generateEntityParams(CancelMentoring cancelMentoring) {
HashMap<String, Object> parameter = new HashMap<>();
parameter.put("mentoringId", cancelMentoring.mentoringId());
parameter.put("reason", AUTO_CANCEL);
return parameter;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.postgraduate.batch.cancel;

import org.springframework.jdbc.core.RowMapper;

import java.sql.ResultSet;
import java.sql.SQLException;

public class CancelMentoringRowMapper implements RowMapper<CancelMentoring> {
@Override
public CancelMentoring mapRow(ResultSet rs, int rowNum) throws SQLException {
return new CancelMentoring(
rs.getLong("mentoring_id"),
rs.getLong("user_user_id"),
rs.getLong("senior_senior_id"),
rs.getLong("payment_payment_id")
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.postgraduate.batch.cancel;

import com.postgraduate.domain.payment.application.usecase.PaymentManageUseCase;
import com.postgraduate.domain.user.domain.entity.User;
import com.postgraduate.domain.user.domain.service.UserGetService;
import com.postgraduate.global.bizppurio.application.usecase.BizppurioJuniorMessage;
import com.postgraduate.global.slack.SlackErrorMessage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.item.Chunk;
import org.springframework.batch.item.ItemWriter;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@RequiredArgsConstructor
@Slf4j
public class CancelMentoringWriter implements ItemWriter<CancelMentoring> {
private final UserGetService userGetService;
private final PaymentManageUseCase paymentManageUseCase;
private final SlackErrorMessage slackErrorMessage;
private final CancelMentoringRepository cancelMentoringRepository;
private final BizppurioJuniorMessage bizppurioJuniorMessage;
@Override
public void write(Chunk<? extends CancelMentoring> chunk) {
log.info("ChunkSize : {}", chunk.size());
chunk.forEach(this::updateCancelWithAuto);
}

public void updateCancelWithAuto(CancelMentoring mentoring) {
try {
User user = userGetService.byUserId(mentoring.userId());
cancelMentoringRepository.updateAllMentoring(List.of(mentoring));
cancelMentoringRepository.insertAllRefuse(List.of(mentoring));
paymentManageUseCase.refundPayByUser(mentoring.userId(), mentoring.paymentId());
log.info("mentoringId : {} 자동 취소", mentoring.mentoringId());
bizppurioJuniorMessage.mentoringRefuse(user);
} catch (Exception ex) {
log.error("mentoringId : {} 자동 취소 실패", mentoring.mentoringId());
log.error(ex.getMessage());
slackErrorMessage.sendSlackMentoringError(mentoring.mentoringId(), ex);
throw ex;
}
}
}
74 changes: 74 additions & 0 deletions src/main/java/com/postgraduate/batch/done/DoneJobConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.postgraduate.batch.done;

import lombok.RequiredArgsConstructor;
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.database.JdbcPagingItemReader;
import org.springframework.batch.item.database.PagingQueryProvider;
import org.springframework.batch.item.database.builder.JdbcPagingItemReaderBuilder;
import org.springframework.batch.item.database.support.SqlPagingQueryProviderFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;

@Configuration
@RequiredArgsConstructor
public class DoneJobConfig {
private final JobRepository jobRepository;
private final PlatformTransactionManager transactionManager;
private final DataSource dataSource;
private final DoneMentoringProcessor doneMentoringProcessor;
private final DoneMentoringWriter doneMentoringWriter;
private final DoneMentoringSkipListener doneMentoringSkipListener;

private static final int CHUNK_SIZE = 50;

@Bean(name = "doneJob")
public Job doneJob() throws Exception {
return new JobBuilder("doneJob", jobRepository)
.start(doneStep())
.build();
}

@Bean(name = "doneStep")
public Step doneStep() throws Exception {
return new StepBuilder("doneStep", jobRepository)
.<DoneMentoring, DoneMentoring>chunk(CHUNK_SIZE, transactionManager)
.reader(doneReader())
.processor(doneMentoringProcessor)
.writer(doneMentoringWriter)
.faultTolerant()
.skip(Exception.class)
.skipLimit(Integer.MAX_VALUE)
.listener(doneMentoringSkipListener)
.build();
}

@Bean(name = "doneReader")
public JdbcPagingItemReader<DoneMentoring> doneReader() throws Exception {
return new JdbcPagingItemReaderBuilder<DoneMentoring>()
.pageSize(CHUNK_SIZE)
.fetchSize(CHUNK_SIZE)
.dataSource(dataSource)
.rowMapper(new DoneMentoringRowMapper())
.queryProvider(doneQueryProvider())
.name("doneReader")
.build();
}

@Bean(name = "doneQuery")
public PagingQueryProvider doneQueryProvider() throws Exception {
SqlPagingQueryProviderFactoryBean queryProvider = new SqlPagingQueryProviderFactoryBean();
queryProvider.setDataSource(dataSource);
queryProvider.setSelectClause("select m.mentoring_id, m.senior_senior_id, m.salary_salary_id, m.date, p.pay");
queryProvider.setFromClause("from mentoring m join payment p on m.payment_payment_id = p.payment_id");
queryProvider.setWhereClause("where m.status = 'EXPECTED'");
queryProvider.setSortKey("mentoring_id");
return queryProvider.getObject();
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/postgraduate/batch/done/DoneMentoring.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.postgraduate.batch.done;

public record DoneMentoring(
Long mentoringId,
Long seniorId,
Long salaryId,
String date,
int pay
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.postgraduate.batch.done;

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

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import static java.time.LocalDateTime.now;
import static java.time.LocalDateTime.parse;
import static java.time.format.DateTimeFormatter.ofPattern;

@Component
public class DoneMentoringProcessor implements ItemProcessor<DoneMentoring, DoneMentoring> {
@Override
public DoneMentoring process(DoneMentoring doneMentoring) {
DateTimeFormatter formatter = ofPattern("yyyy-MM-dd-HH-mm");
LocalDateTime doneDate = parse(doneMentoring.date(), formatter);
if (now().minusDays(3)
.isAfter(doneDate))
return doneMentoring;
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.postgraduate.batch.done;

import com.postgraduate.domain.mentoring.domain.entity.constant.TermUnit;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
@RequiredArgsConstructor
public class DoneMentoringRepository {
private final NamedParameterJdbcTemplate jdbcTemplate;
private static final int CHARGE = TermUnit.SHORT.getCharge();
private static final String UPDATE_MENTORING = "update mentoring set status = 'DONE' where mentoring_id = :mentoringId";
private static final String UPDATE_SALARY = "update salary set total_amount = total_amount + :amount where salary_id = :salaryId";

public void updateAllSalary(List<DoneMentoring> mentorings) {
jdbcTemplate.batchUpdate(UPDATE_SALARY, generateParameterSource(mentorings));
}

public void updateAllMentoring(List<DoneMentoring> mentorings) {
jdbcTemplate.batchUpdate(UPDATE_MENTORING, generateParameterSource(mentorings));
}

private SqlParameterSource[] generateParameterSource(List<DoneMentoring> mentorings) {
return mentorings.stream()
.map(mentoring -> new MapSqlParameterSource(generateEntityParams(mentoring)))
.toArray(SqlParameterSource[]::new);
}

private Map<String, Object> generateEntityParams(DoneMentoring doneMentoring) {
HashMap<String, Object> parameter = new HashMap<>();
parameter.put("mentoringId", doneMentoring.mentoringId());
parameter.put("amount", doneMentoring.pay() - CHARGE);
parameter.put("salaryId", doneMentoring.salaryId());
return parameter;
}
}
Loading

0 comments on commit 91df0b8

Please sign in to comment.