Skip to content

Commit

Permalink
Refactor | CAKK-59 | Message Extractor, Sender 관련 리팩토링
Browse files Browse the repository at this point in the history
* Refactor | CAKK-59 | MessageExtractor 인터페이스 추상화

* Refactor | CAKK-59 | as-is 클래스 및 인터페이스 제거

* Refactor | CAKK-59 | as-is 클래스 및 인터페이스 제거

* Refactor | CAKK-59 | 메시지 extractor, template 추상화

* Refactor | CAKK-59 | 에러 메시지 리스너 구현

* Refactor | CAKK-59 | api 모듈 slack 의존성 제거

* Refactor | CAKK-59 | 메시지 관련 비즈니스 리팩토링

* Test | CAKK-59 | 메시지 전송 관련 테스트 수정

* Chore | CAKK-59 | jacoco exclude에 리스너 등록

* Refactor | CAKK-59 | email 관련 sender 네이밍 수정

* Refactor | CAKK-59 | 제네릭 범위 수정

* Test | CAKK-59 | Error 관련 리스너 테스트 작성
  • Loading branch information
lcomment authored Aug 30, 2024
1 parent e90c9dc commit 0346e96
Show file tree
Hide file tree
Showing 33 changed files with 382 additions and 342 deletions.
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ subprojects {
"com.cakk.api.provider.oauth.PublicKeyProvider",
"com.cakk.api.dto.**",
"com.cakk.api.mapper.**",
"com.cakk.api.listener.**",
"com.cakk.api.vo.**",
"com.cakk.domain.**"
)
Expand Down
3 changes: 0 additions & 3 deletions cakk-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ dependencies {
testImplementation("org.testcontainers:junit-jupiter:1.19.7")
testImplementation("org.testcontainers:mysql:1.19.7")

// slack 설정
implementation("net.gpedro.integrations.slack:slack-webhook:1.4.0")

// Point
implementation("org.locationtech.jts:jts-core:1.18.2")
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.cakk.api.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.cakk.external.extractor.CertificationSlackMessageExtractor;
import com.cakk.external.extractor.ErrorAlertSlackMessageExtractor;
import com.cakk.external.extractor.MessageExtractor;
import com.cakk.external.template.MessageTemplate;

@Configuration
public class MessageTemplateConfig {

@Bean
public MessageTemplate certificationTemplate() {
return new MessageTemplate();
}

@Bean
public MessageExtractor certificationMessageExtractor() {
return new CertificationSlackMessageExtractor();
}

@Bean
public MessageExtractor errorAlertMessageExtractor() {
return new ErrorAlertSlackMessageExtractor();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import jakarta.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
Expand All @@ -20,27 +22,37 @@
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

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

import com.cakk.api.service.slack.SlackService;
import com.cakk.api.mapper.EventMapper;
import com.cakk.common.enums.ReturnCode;
import com.cakk.common.exception.CakkException;
import com.cakk.common.response.ApiResponse;

@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalControllerAdvice {

private final SlackService slackService;
private final ApplicationEventPublisher applicationEventPublisher;

private final String profile;

public GlobalControllerAdvice(
ApplicationEventPublisher applicationEventPublisher,
@Value("${spring.profiles.active}") String profile
) {
this.applicationEventPublisher = applicationEventPublisher;
this.profile = profile;
}

@ExceptionHandler(CakkException.class)
public ResponseEntity<ApiResponse<Void>> handleCakkException(CakkException exception, HttpServletRequest request) {
final ReturnCode returnCode = exception.getReturnCode();

if (returnCode.equals(ReturnCode.INTERNAL_SERVER_ERROR) || returnCode.equals(ReturnCode.EXTERNAL_SERVER_ERROR)) {
slackService.sendSlackForError(exception, request);
applicationEventPublisher.publishEvent(EventMapper.supplyErrorAlertEventBy(exception, request, profile));
}

log.error(exception.getMessage());
return getResponseEntity(BAD_REQUEST, ApiResponse.fail(exception.getReturnCode()));
}
Expand Down Expand Up @@ -79,8 +91,9 @@ public ResponseEntity<ApiResponse<Map<String, String>>> handleMethodArgNotValidE
RuntimeException.class
})
public ResponseEntity<ApiResponse<String>> handleServerException(Exception exception, HttpServletRequest request) {
slackService.sendSlackForError(exception, request);
applicationEventPublisher.publishEvent(EventMapper.supplyErrorAlertEventBy(exception, request, profile));
log.error(exception.getMessage());

return getResponseEntity(INTERNAL_SERVER_ERROR, ApiResponse.error(ReturnCode.INTERNAL_SERVER_ERROR, exception.getMessage()));
}

Expand Down
10 changes: 10 additions & 0 deletions cakk-api/src/main/java/com/cakk/api/dto/event/ErrorAlertEvent.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.cakk.api.dto.event;

import jakarta.servlet.http.HttpServletRequest;

public record ErrorAlertEvent(
Exception exception,
HttpServletRequest request,
String profile
) {
}
Original file line number Diff line number Diff line change
@@ -1,27 +1,39 @@
package com.cakk.api.listener;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import lombok.RequiredArgsConstructor;

import com.cakk.api.annotation.ApplicationEventListener;
import com.cakk.api.mapper.EventMapper;
import com.cakk.domain.mysql.event.shop.CertificationEvent;
import com.cakk.external.template.CertificationTemplate;
import com.cakk.external.extractor.MessageExtractor;
import com.cakk.external.sender.MessageSender;
import com.cakk.external.template.MessageTemplate;
import com.cakk.external.vo.CertificationMessage;

@RequiredArgsConstructor
@ApplicationEventListener
public class CertificationEventListener {

private final CertificationTemplate certificationTemplate;
private final MessageTemplate messageTemplate;
private final MessageExtractor messageExtractor;
private final MessageSender messageSender;

public CertificationEventListener(
MessageTemplate messageTemplate,
@Qualifier("certificationMessageExtractor") MessageExtractor messageExtractor,
@Qualifier("slackMessageSender") MessageSender messageSender
) {
this.messageTemplate = messageTemplate;
this.messageExtractor = messageExtractor;
this.messageSender = messageSender;
}

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendMessageToSlack(CertificationEvent certificationEvent) {
CertificationMessage certificationMessage = EventMapper.supplyCertificationMessageBy(certificationEvent);
certificationTemplate.sendMessageForCertification(certificationMessage);
messageTemplate.sendMessage(certificationMessage, messageExtractor, messageSender);
}
}
Original file line number Diff line number Diff line change
@@ -1,33 +1,39 @@
package com.cakk.api.listener;

import java.util.Objects;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;

import com.cakk.api.annotation.ApplicationEventListener;
import com.cakk.api.dto.event.EmailWithVerificationCodeSendEvent;
import com.cakk.api.mapper.EventMapper;
import com.cakk.external.template.VerificationCodeSendTemplate;
import com.cakk.external.extractor.MessageExtractor;
import com.cakk.external.sender.MessageSender;
import com.cakk.external.template.MessageTemplate;
import com.cakk.external.vo.VerificationMessage;

@ApplicationEventListener
public class EmailSendEventListener {


private final VerificationCodeSendTemplate verificationCodeSendTemplate;
private final MessageTemplate messageTemplate;
private final MessageExtractor messageExtractor;
private final MessageSender messageSender;

public EmailSendEventListener(
VerificationCodeSendTemplate verificationCodeSendTemplate
MessageTemplate messageTemplate,
@Qualifier("verificationCodeMimeMessageExtractor") MessageExtractor messageExtractor,
@Qualifier("emailMessageSender") MessageSender messageSender
) {
this.verificationCodeSendTemplate = verificationCodeSendTemplate;
this.messageTemplate = messageTemplate;
this.messageExtractor = messageExtractor;
this.messageSender = messageSender;
}

@Async
@EventListener
public void sendEmailIncludeVerificationCode(EmailWithVerificationCodeSendEvent event) {
final VerificationMessage verificationMessage = EventMapper.supplyVerificationMessageBy(event);
verificationCodeSendTemplate.sendMessageForVerificationCode(verificationMessage);
messageTemplate.sendMessage(verificationMessage, messageExtractor, messageSender);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.cakk.api.listener;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import com.cakk.api.annotation.ApplicationEventListener;
import com.cakk.api.dto.event.ErrorAlertEvent;
import com.cakk.api.mapper.EventMapper;
import com.cakk.external.extractor.MessageExtractor;
import com.cakk.external.sender.MessageSender;
import com.cakk.external.template.MessageTemplate;
import com.cakk.external.vo.ErrorAlertMessage;

@ApplicationEventListener
public class ErrorAlertEventListener {

private final MessageTemplate messageTemplate;
private final MessageExtractor messageExtractor;
private final MessageSender messageSender;

public ErrorAlertEventListener(
MessageTemplate messageTemplate,
@Qualifier("errorAlertMessageExtractor") MessageExtractor messageExtractor,
@Qualifier("slackMessageSender") MessageSender messageSender
) {
this.messageTemplate = messageTemplate;
this.messageExtractor = messageExtractor;
this.messageSender = messageSender;
}

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendMessageToSlack(ErrorAlertEvent errorAlertEvent) {
ErrorAlertMessage certificationMessage = EventMapper.supplyErrorAlertMessageBy(errorAlertEvent);
messageTemplate.sendMessage(certificationMessage, messageExtractor, messageSender);
}
}
30 changes: 30 additions & 0 deletions cakk-api/src/main/java/com/cakk/api/mapper/EventMapper.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package com.cakk.api.mapper;

import java.util.Arrays;
import java.util.Objects;

import jakarta.servlet.http.HttpServletRequest;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import com.cakk.api.dto.event.EmailWithVerificationCodeSendEvent;
import com.cakk.api.dto.event.ErrorAlertEvent;
import com.cakk.api.dto.event.IncreaseSearchCountEvent;
import com.cakk.domain.mysql.event.shop.CertificationEvent;
import com.cakk.external.vo.CertificationMessage;
import com.cakk.external.vo.ErrorAlertMessage;
import com.cakk.external.vo.VerificationMessage;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
Expand All @@ -22,6 +27,14 @@ public static IncreaseSearchCountEvent supplyIncreaseSearchCountEventBy(final St
return new IncreaseSearchCountEvent(keyword);
}

public static ErrorAlertEvent supplyErrorAlertEventBy(
final Exception exception,
final HttpServletRequest request,
final String profile
) {
return new ErrorAlertEvent(exception, request, profile);
}

public static CertificationMessage supplyCertificationMessageBy(final CertificationEvent certificationEvent) {
Double latitude = null;
Double longitude = null;
Expand All @@ -47,4 +60,21 @@ public static CertificationMessage supplyCertificationMessageBy(final Certificat
public static VerificationMessage supplyVerificationMessageBy(final EmailWithVerificationCodeSendEvent event) {
return new VerificationMessage(event.email(), event.code());
}

public static ErrorAlertMessage supplyErrorAlertMessageBy(final ErrorAlertEvent event) {
final String profile = event.profile();
final String stackTrace = Arrays.toString(event.exception().getStackTrace());
final HttpServletRequest request = event.request();

return new ErrorAlertMessage(
profile,
stackTrace,
request.getContextPath(),
request.getRequestURL().toString(),
request.getMethod(),
request.getParameterMap(),
request.getRemoteAddr(),
request.getHeader("User-Agent")
);
}
}
Loading

0 comments on commit 0346e96

Please sign in to comment.