From a77f1a467fa4a8b4f4d60b8c44c4da8342118301 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Sun, 3 Nov 2024 21:27:19 +0900 Subject: [PATCH 1/7] =?UTF-8?q?#564=20[feat]=20sql=20=EB=A1=9C=EA=B9=85=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mile/common/log/P6spySqlFormat.java | 33 +++++++++++++++++ .../mile/common/log/P6spySqlFormatConfig.java | 14 ++++++++ .../common/log/SqlFunctionLoggingModule.java | 35 +++++++++++++++++++ .../mile/moim/repository/MoimRepository.java | 1 - 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 module-domain/src/main/java/com/mile/common/log/P6spySqlFormat.java create mode 100644 module-domain/src/main/java/com/mile/common/log/P6spySqlFormatConfig.java create mode 100644 module-domain/src/main/java/com/mile/common/log/SqlFunctionLoggingModule.java diff --git a/module-domain/src/main/java/com/mile/common/log/P6spySqlFormat.java b/module-domain/src/main/java/com/mile/common/log/P6spySqlFormat.java new file mode 100644 index 00000000..d46f4b47 --- /dev/null +++ b/module-domain/src/main/java/com/mile/common/log/P6spySqlFormat.java @@ -0,0 +1,33 @@ +package com.mile.common.log; + +import com.p6spy.engine.logging.Category; +import com.p6spy.engine.spy.appender.MessageFormattingStrategy; +import org.hibernate.engine.jdbc.internal.FormatStyle; +import org.slf4j.MDC; + +import java.util.Locale; + +public class P6spySqlFormat implements MessageFormattingStrategy { + private final String MDC_KEY = "SQL_START"; + + @Override + public String formatMessage(int connectionId, String now, long elapsed, String category, String prepared, String sql, String url) { + sql = formatSql(category, sql); + return MDC.get(MDC_KEY) + "|" + sql; + } + + private String formatSql(String category, String sql) { + if (sql == null || sql.trim().equals("")) return sql; + + if (Category.STATEMENT.getName().equals(category)) { + String tmpsql = sql.trim().toLowerCase(Locale.ROOT); + if (tmpsql.startsWith("create") || tmpsql.startsWith("alter") || tmpsql.startsWith("comment")) { + sql = FormatStyle.DDL.getFormatter().format(sql); + } else { + sql = FormatStyle.BASIC.getFormatter().format(sql); + } + } + + return sql; + } +} \ No newline at end of file diff --git a/module-domain/src/main/java/com/mile/common/log/P6spySqlFormatConfig.java b/module-domain/src/main/java/com/mile/common/log/P6spySqlFormatConfig.java new file mode 100644 index 00000000..c3aeb1b6 --- /dev/null +++ b/module-domain/src/main/java/com/mile/common/log/P6spySqlFormatConfig.java @@ -0,0 +1,14 @@ +package com.mile.common.log; + +import com.p6spy.engine.spy.P6SpyOptions; +import jakarta.annotation.PostConstruct; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class P6spySqlFormatConfig { + + @PostConstruct + public void setLogMessageFormat() { + P6SpyOptions.getActiveInstance().setLogMessageFormat(P6spySqlFormat.class.getName()); + } +} diff --git a/module-domain/src/main/java/com/mile/common/log/SqlFunctionLoggingModule.java b/module-domain/src/main/java/com/mile/common/log/SqlFunctionLoggingModule.java new file mode 100644 index 00000000..be5cb4ef --- /dev/null +++ b/module-domain/src/main/java/com/mile/common/log/SqlFunctionLoggingModule.java @@ -0,0 +1,35 @@ +package com.mile.common.log; + +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; + +/** + * from @sohyundoh + *

+ * SQL 진입점을 로깅하기 위한 AOP 클래스 + */ +@Aspect +@Component +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +@Slf4j +public class SqlFunctionLoggingModule { + private final String MDC_KEY = "SQL_START"; + + @Pointcut("execution(* com.mile.*.repository..*.*(..))") + public void sqlLoggingPoint() { + } + + @Around("sqlLoggingPoint()") + public Object putSqlStartingPoint(final ProceedingJoinPoint joinPoint) throws Throwable { + MDC.put(MDC_KEY, "[ QUERY START -> " + joinPoint.getSignature().toShortString() + "]"); + + return joinPoint.proceed(); + } +} diff --git a/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java b/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java index 43865d32..85b7fa5f 100644 --- a/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java +++ b/module-domain/src/main/java/com/mile/moim/repository/MoimRepository.java @@ -1,7 +1,6 @@ package com.mile.moim.repository; import com.mile.moim.domain.Moim; -import com.mile.post.domain.Post; import com.mile.writername.domain.WriterName; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; From e86e8edd09d744b6734c7711ada44284c6348341 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Mon, 4 Nov 2024 22:22:41 +0900 Subject: [PATCH 2/7] =?UTF-8?q?#569=20[feat]=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mile/moim/domain/popular/MoimPopularInfo.java | 3 ++- .../moim/repository/MoimPopularInfoRepository.java | 5 ++--- .../moim/service/popular/MoimPopularInfoService.java | 12 +++++++++++- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/module-domain/src/main/java/com/mile/moim/domain/popular/MoimPopularInfo.java b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimPopularInfo.java index 2a24a358..082d1dc9 100644 --- a/module-domain/src/main/java/com/mile/moim/domain/popular/MoimPopularInfo.java +++ b/module-domain/src/main/java/com/mile/moim/domain/popular/MoimPopularInfo.java @@ -1,5 +1,6 @@ package com.mile.moim.domain.popular; +import com.mile.common.config.BaseTimeEntity; import jakarta.persistence.Column; import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; @@ -16,7 +17,7 @@ @Entity @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class MoimPopularInfo { +public class MoimPopularInfo extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) diff --git a/module-domain/src/main/java/com/mile/moim/repository/MoimPopularInfoRepository.java b/module-domain/src/main/java/com/mile/moim/repository/MoimPopularInfoRepository.java index 51b71483..8ff11921 100644 --- a/module-domain/src/main/java/com/mile/moim/repository/MoimPopularInfoRepository.java +++ b/module-domain/src/main/java/com/mile/moim/repository/MoimPopularInfoRepository.java @@ -12,7 +12,6 @@ public interface MoimPopularInfoRepository extends JpaRepository findByMoimId(final long moimId); - - @Scheduled(cron = "59 59 23 * * SUN") - void deleteAll(); + @Query("select count(m) from MoimPopularInfo m") + Long countAll(); } diff --git a/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java index f62119fe..0928aae4 100644 --- a/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java +++ b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java @@ -3,10 +3,12 @@ import com.mile.moim.domain.Moim; import com.mile.moim.domain.popular.MoimPopularInfo; import com.mile.moim.repository.MoimPopularInfoRepository; -import com.mile.moim.service.lock.AtomicValidateMoimPopulerInfo; +import com.mile.slack.module.SendMessageModule; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; +import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @Service @@ -14,6 +16,7 @@ public class MoimPopularInfoService { private final MoimPopularInfoRepository moimPopularInfoRepository; private final MoimPopularInfoRegister moimPopularInfoRegister; + private final SendMessageModule sendMessageModule; @Cacheable(value = "moimPopularInfo", key = "#moim.id") @@ -23,4 +26,11 @@ public MoimPopularInfo getMoimPopularInfo(final Moim moim) { ); } + @Async + @Scheduled(cron = "59 59 23 * * SUN") + public void deleteAllForScheduled() { + sendMessageModule.sendMessage("글모임 별 인기 글/ 인기 작가 삭제 완료 : 총 " + moimPopularInfoRepository.countAll() + "개의 모임"); + moimPopularInfoRepository.deleteAllInBatch(); + } + } From 9a179d66956910e2071cd921b745856aad76417c Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Mon, 4 Nov 2024 22:23:41 +0900 Subject: [PATCH 3/7] =?UTF-8?q?#569=20[feat]=20webhook=20uri=EB=A1=9C=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=20=ED=9B=84=20=EB=A9=94=EC=8B=9C=EC=A7=80=20?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EB=8F=84=EB=A1=9D=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module-external/build.gradle | 1 + .../mile/slack/module/SendMessageModule.java | 53 +++++++++++++++++++ .../mile/slack/module/SendWebhookMessage.java | 8 +++ 3 files changed, 62 insertions(+) create mode 100644 module-external/src/main/java/com/mile/slack/module/SendMessageModule.java create mode 100644 module-external/src/main/java/com/mile/slack/module/SendWebhookMessage.java diff --git a/module-external/build.gradle b/module-external/build.gradle index e9d98386..6ac922d7 100644 --- a/module-external/build.gradle +++ b/module-external/build.gradle @@ -5,4 +5,5 @@ dependencies { implementation project(":module-common") implementation("software.amazon.awssdk:bom:2.21.0") implementation("software.amazon.awssdk:s3:2.21.0") + implementation("org.springframework.boot:spring-boot-starter-webflux") } diff --git a/module-external/src/main/java/com/mile/slack/module/SendMessageModule.java b/module-external/src/main/java/com/mile/slack/module/SendMessageModule.java new file mode 100644 index 00000000..6b8b2e4d --- /dev/null +++ b/module-external/src/main/java/com/mile/slack/module/SendMessageModule.java @@ -0,0 +1,53 @@ +package com.mile.slack.module; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.lang.NonNull; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.client.WebClient; + +import java.time.LocalDateTime; +import java.util.ArrayList; + + +@Component +@Slf4j +public class SendMessageModule implements SendWebhookMessage { + private final StringBuilder sb = new StringBuilder(); + + @Value("${webhook.url-for-event}") + private String webHookUri; + + @Override + public void sendMessage(@NonNull final String message) { + WebClient webClient = WebClient.builder() + .baseUrl(webHookUri).build(); + + + webClient.post() + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(generateMessage(message)) + .accept(MediaType.APPLICATION_JSON) + .retrieve() + .bodyToMono(String.class) + .doOnError(e -> log.error("WEB HOOK 전송 중 에러 발생 -> {}", e.getMessage())) + .subscribe(); + } + + private SlackMessage generateMessage(final String message) { + sb.append("*[인기글 삭제 작업 완료]*").append("\n").append(message).append("\n"); + sb.append("*[진행일자]*").append("\n").append(LocalDateTime.now()).append("\n"); + + return new SlackMessage(sb.toString()); + } + + @Getter + @AllArgsConstructor + private class SlackMessage { + private String text; + } +} diff --git a/module-external/src/main/java/com/mile/slack/module/SendWebhookMessage.java b/module-external/src/main/java/com/mile/slack/module/SendWebhookMessage.java new file mode 100644 index 00000000..ae4f1e2e --- /dev/null +++ b/module-external/src/main/java/com/mile/slack/module/SendWebhookMessage.java @@ -0,0 +1,8 @@ +package com.mile.slack.module; + +import org.springframework.lang.NonNull; + +public interface SendWebhookMessage { + void sendMessage(@NonNull final String message); + +} From 785e7426004c383b8fe692fac9a347fa1d7365ee Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Mon, 4 Nov 2024 22:27:20 +0900 Subject: [PATCH 4/7] =?UTF-8?q?#569=20[feat]=20Async=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mile/moim/service/popular/MoimPopularInfoService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java index 0928aae4..842ab3de 100644 --- a/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java +++ b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java @@ -26,7 +26,6 @@ public MoimPopularInfo getMoimPopularInfo(final Moim moim) { ); } - @Async @Scheduled(cron = "59 59 23 * * SUN") public void deleteAllForScheduled() { sendMessageModule.sendMessage("글모임 별 인기 글/ 인기 작가 삭제 완료 : 총 " + moimPopularInfoRepository.countAll() + "개의 모임"); From cfb4a521826e231ccb059055ff986355b9717583 Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Tue, 5 Nov 2024 21:39:58 +0900 Subject: [PATCH 5/7] =?UTF-8?q?#569=20[feat]=20Cache=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=AA=A8=EB=93=88=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../external/InternalController.java | 19 +++++++++++++++++++ .../java/com/mile/common/CacheService.java | 19 +++++++++++++++++++ .../popular/MoimPopularInfoService.java | 1 - 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 module-api/src/main/java/com/mile/controller/external/InternalController.java create mode 100644 module-domain/src/main/java/com/mile/common/CacheService.java diff --git a/module-api/src/main/java/com/mile/controller/external/InternalController.java b/module-api/src/main/java/com/mile/controller/external/InternalController.java new file mode 100644 index 00000000..9e242625 --- /dev/null +++ b/module-api/src/main/java/com/mile/controller/external/InternalController.java @@ -0,0 +1,19 @@ +package com.mile.controller.external; + +import com.mile.common.CacheService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class InternalController { + + private final CacheService cacheService; + + @DeleteMapping("/api/v1/moim/info/cache") + public void deleteMoimInfoCache() { + cacheService.deleteMoimCache(); + } +} diff --git a/module-domain/src/main/java/com/mile/common/CacheService.java b/module-domain/src/main/java/com/mile/common/CacheService.java new file mode 100644 index 00000000..5f6463e6 --- /dev/null +++ b/module-domain/src/main/java/com/mile/common/CacheService.java @@ -0,0 +1,19 @@ +package com.mile.common; + +import lombok.RequiredArgsConstructor; +import org.springframework.cache.CacheManager; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class CacheService { + + private final String MOIM_CACHE_NAME = "moimPopularInfo"; + private final CacheManager cacheManager; + + public void deleteMoimCache() { + if (cacheManager.getCache(MOIM_CACHE_NAME) != null) { + cacheManager.getCache(MOIM_CACHE_NAME).clear(); + } + } +} diff --git a/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java index 842ab3de..53ccf0df 100644 --- a/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java +++ b/module-domain/src/main/java/com/mile/moim/service/popular/MoimPopularInfoService.java @@ -7,7 +7,6 @@ import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.springframework.cache.annotation.Cacheable; -import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; From ce08c1449d4b55265198bcedfb76115cf3f20e4b Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Tue, 5 Nov 2024 21:44:25 +0900 Subject: [PATCH 6/7] =?UTF-8?q?#569=20[feat]=20=EA=B8=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20API=20Request=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/mile/post/service/dto/request/PostPutRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module-domain/src/main/java/com/mile/post/service/dto/request/PostPutRequest.java b/module-domain/src/main/java/com/mile/post/service/dto/request/PostPutRequest.java index be15b495..7bf479cc 100644 --- a/module-domain/src/main/java/com/mile/post/service/dto/request/PostPutRequest.java +++ b/module-domain/src/main/java/com/mile/post/service/dto/request/PostPutRequest.java @@ -12,7 +12,7 @@ public record PostPutRequest( String topicId, @NotBlank(message = "제목을 입력해주세요.") - @Size(max = 29, message = "제목 최대 글자를 초과했습니다.") + @Size(max = 34, message = "제목 최대 글자를 초과했습니다.") @Schema(description = "글 제목", example = "편안한 글쓰기") String title, From 74270a93fcf9472a866fa97acaa3b8938c0644cb Mon Sep 17 00:00:00 2001 From: sohyundoh Date: Tue, 5 Nov 2024 21:46:31 +0900 Subject: [PATCH 7/7] =?UTF-8?q?#569=20[feat]=20InternalController=20HTTP?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/mile/controller/external/InternalController.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/module-api/src/main/java/com/mile/controller/external/InternalController.java b/module-api/src/main/java/com/mile/controller/external/InternalController.java index 9e242625..991d2159 100644 --- a/module-api/src/main/java/com/mile/controller/external/InternalController.java +++ b/module-api/src/main/java/com/mile/controller/external/InternalController.java @@ -2,8 +2,7 @@ import com.mile.common.CacheService; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @RestController @@ -12,7 +11,7 @@ public class InternalController { private final CacheService cacheService; - @DeleteMapping("/api/v1/moim/info/cache") + @PostMapping("/api/v1/moim/info/cache") public void deleteMoimInfoCache() { cacheService.deleteMoimCache(); }