From c97da37db002ab6df8392ca35b09b96383bb58d7 Mon Sep 17 00:00:00 2001 From: jinho jeong Date: Tue, 31 May 2022 22:52:51 +0900 Subject: [PATCH] batch delete --- build.gradle | 2 + .../com/example/oneul/OneulApplication.java | 4 ++ .../post/dao/PostCommandRepository.java | 4 ++ .../oneul/domain/post/domain/Post.java | 32 +++++++++- .../oneul/global/config/BatchConfig.java | 60 +++++++++++++++++++ .../oneul/global/util/BatchScheduler.java | 45 ++++++++++++++ src/main/resources/application.yml | 5 +- 7 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/oneul/global/config/BatchConfig.java create mode 100644 src/main/java/com/example/oneul/global/util/BatchScheduler.java diff --git a/build.gradle b/build.gradle index aaa64cb..04c9cdf 100644 --- a/build.gradle +++ b/build.gradle @@ -26,6 +26,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-batch' + implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-data-redis' diff --git a/src/main/java/com/example/oneul/OneulApplication.java b/src/main/java/com/example/oneul/OneulApplication.java index ac1c8f7..75551d1 100644 --- a/src/main/java/com/example/oneul/OneulApplication.java +++ b/src/main/java/com/example/oneul/OneulApplication.java @@ -1,13 +1,17 @@ package com.example.oneul; +import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; +import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @SpringBootApplication @EnableJpaAuditing +@EnableScheduling +@EnableBatchProcessing @EnableRedisHttpSession public class OneulApplication { public static void main(String[] args) { diff --git a/src/main/java/com/example/oneul/domain/post/dao/PostCommandRepository.java b/src/main/java/com/example/oneul/domain/post/dao/PostCommandRepository.java index 53e8c9a..2b9188a 100644 --- a/src/main/java/com/example/oneul/domain/post/dao/PostCommandRepository.java +++ b/src/main/java/com/example/oneul/domain/post/dao/PostCommandRepository.java @@ -1,5 +1,7 @@ package com.example.oneul.domain.post.dao; +import java.time.LocalDateTime; +import java.util.List; import java.util.Optional; import com.example.oneul.domain.post.domain.Post; @@ -13,4 +15,6 @@ public interface PostCommandRepository extends CrudRepository { void deleteByIdAndWriter(Long id, UserEntity writer); void deleteById(Long id); void delete(Post post); + + List findAllByExpiredAt(LocalDateTime expiredAt); } \ No newline at end of file diff --git a/src/main/java/com/example/oneul/domain/post/domain/Post.java b/src/main/java/com/example/oneul/domain/post/domain/Post.java index 84b0605..d2767b4 100644 --- a/src/main/java/com/example/oneul/domain/post/domain/Post.java +++ b/src/main/java/com/example/oneul/domain/post/domain/Post.java @@ -31,6 +31,9 @@ public class Post implements Serializable { @CreatedDate private LocalDateTime createdAt; @Column(nullable = false) + private LocalDateTime expiredAt; + private LocalDateTime deletedAt; + @Column(nullable = false) private String content; @Access(AccessType.PROPERTY) @ManyToOne(fetch = FetchType.EAGER, optional = false) @@ -38,9 +41,11 @@ public class Post implements Serializable { public Post() {} - public Post(Long id, LocalDateTime createdAt, String content, UserEntity writer){ + public Post(Long id, LocalDateTime createdAt, LocalDateTime expiredAt, String content, UserEntity writer){ this.id = id; this.createdAt = createdAt; + this.expiredAt = expiredAt.plusHours(24); + this.deletedAt = null; this.content = content; this.writer = writer; } @@ -61,6 +66,22 @@ public class Post implements Serializable { this.createdAt = createdAt; } + public LocalDateTime getExpiredAt() { + return this.expiredAt; + } + + public void setExpiredAt(LocalDateTime expiredAt){ + this.expiredAt = expiredAt; + } + + public LocalDateTime getDeletedAt(){ + return this.deletedAt; + } + + public void setDeletedAt(LocalDateTime deletedAt){ + this.deletedAt = deletedAt; + } + public String getContent(){ return this.content; } @@ -99,6 +120,8 @@ public class Post implements Serializable { return "Post[" + "id: " + this.id + ", createdAt: " + this.createdAt + + ", expiredAt: " + this.expiredAt + + ", deletedAt; " + this.deletedAt + ", content: " + this.content + "writer: " + this.writer.getId() + "]"; @@ -112,12 +135,14 @@ public class Post implements Serializable { private Long id; private String content; private LocalDateTime createdAt; + private LocalDateTime expiredAt; private UserEntity writer; public Post build(){ return new Post( id, createdAt, + expiredAt, content, writer); } @@ -131,6 +156,11 @@ public class Post implements Serializable { return this; } + public Builder expiredAt(LocalDateTime expiredAt){ + this.expiredAt = expiredAt; + return this; + } + public Builder content(String content){ this.content = content; return this; diff --git a/src/main/java/com/example/oneul/global/config/BatchConfig.java b/src/main/java/com/example/oneul/global/config/BatchConfig.java new file mode 100644 index 0000000..ca8be0d --- /dev/null +++ b/src/main/java/com/example/oneul/global/config/BatchConfig.java @@ -0,0 +1,60 @@ +package com.example.oneul.global.config; + +import java.time.LocalDateTime; +import java.util.List; + +import com.example.oneul.domain.post.dao.PostCommandRepository; +import com.example.oneul.domain.post.domain.Post; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +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.repeat.RepeatStatus; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@EnableBatchProcessing +public class BatchConfig { + public JobBuilderFactory jobBuilderFactory; + public StepBuilderFactory stepBuilderFactory; + + private final Logger log = LoggerFactory.getLogger(BatchConfig.class); + + private PostCommandRepository postCommandRepository; + + public BatchConfig(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, PostCommandRepository postCommandRepository){ + this.jobBuilderFactory = jobBuilderFactory; + this.stepBuilderFactory = stepBuilderFactory; + this.postCommandRepository = postCommandRepository; + } + + @Bean + public Job job() { + Job job = jobBuilderFactory.get("job") + .start(step()) + .build(); + + return job; + } + + @Bean + public Step step() { + return stepBuilderFactory.get("step") + .tasklet((contribution, chunkContext) -> { + LocalDateTime expiredAt = LocalDateTime.now(); + List posts = postCommandRepository.findAllByExpiredAt(expiredAt); + // posts.stream().forEach(post -> { + // post.setDeletedAt(expiredAt); + // }); + // // TODO: Query DB 한테 알려줘야함 + // postCommandRepository.saveAll(posts); + log.info(expiredAt + " posts(" + posts.size() + ") are deleted."); + return RepeatStatus.FINISHED; + }).build(); + } +} diff --git a/src/main/java/com/example/oneul/global/util/BatchScheduler.java b/src/main/java/com/example/oneul/global/util/BatchScheduler.java new file mode 100644 index 0000000..e88dd17 --- /dev/null +++ b/src/main/java/com/example/oneul/global/util/BatchScheduler.java @@ -0,0 +1,45 @@ +package com.example.oneul.global.util; + +import java.util.HashMap; +import java.util.Map; + +import com.example.oneul.global.config.BatchConfig; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.batch.core.JobParameter; +import org.springframework.batch.core.JobParameters; +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.stereotype.Component; + +@Component +public class BatchScheduler { + private final Logger log = LoggerFactory.getLogger(BatchScheduler.class); + + private JobLauncher jobLauncher; + private BatchConfig batchConfig; + + public BatchScheduler(JobLauncher jobLauncher, BatchConfig batchConfig){ + this.jobLauncher = jobLauncher; + this.batchConfig = batchConfig; + } + + // 1 분마다 실행 + @Scheduled(cron = "0 * * * * *") + public void runjob(){ + Map configMap = new HashMap<>(); + configMap.put("time", new JobParameter(System.currentTimeMillis())); + JobParameters jobParameters = new JobParameters(configMap); + + try { + jobLauncher.run(batchConfig.job(), jobParameters); + } catch (JobExecutionAlreadyRunningException | JobInstanceAlreadyCompleteException | JobParametersInvalidException | JobRestartException e) { + log.error(e.getMessage()); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index ef46c2a..0ed668c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,3 +1,6 @@ spring: profiles: - active: local \ No newline at end of file + active: local + batch: + job: + enabled: false \ No newline at end of file