Skip to content

Commit

Permalink
Refactor | CAKK-58 | 템플릿 콜백 패턴 적
Browse files Browse the repository at this point in the history
  • Loading branch information
lcomment committed Aug 29, 2024
1 parent c736734 commit f361cbe
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.cakk.api.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.cakk.external.extractor.VerificationCodeMessageExtractor;
import com.cakk.external.sender.MessageSender;
import com.cakk.external.template.VerificationCodeSendTemplate;

@Configuration
public class VerificationCodeSendTemplateConfig {

private final MessageSender messageSender;
private final VerificationCodeMessageExtractor verificationCodeMessageExtractor;

public VerificationCodeSendTemplateConfig(
@Qualifier("emailSender")
MessageSender messageSender,
VerificationCodeMessageExtractor verificationCodeMessageExtractor
) {
this.messageSender = messageSender;
this.verificationCodeMessageExtractor = verificationCodeMessageExtractor;
}

@Bean
public VerificationCodeSendTemplate verificationCodeSendTemplate() {
return new VerificationCodeSendTemplate(messageSender, verificationCodeMessageExtractor);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,26 @@

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

@ApplicationEventListener
public class EmailSendEventListener {


private final MessageSender messageSender;
private final VerificationCodeSendTemplate verificationCodeSendTemplate;

public EmailSendEventListener(
@Qualifier("emailSender")
MessageSender messageSender
VerificationCodeSendTemplate verificationCodeSendTemplate
) {
this.messageSender = messageSender;
this.verificationCodeSendTemplate = verificationCodeSendTemplate;
}

@Async
@EventListener
public void sendEmailIncludeVerificationCode(EmailWithVerificationCodeSendEvent event) {
messageSender.send(Objects.requireNonNull(event.email()), Objects.requireNonNull(event.code()));
final VerificationMessage verificationMessage = EventMapper.supplyVerificationMessageBy(event);
verificationCodeSendTemplate.sendMessageForVerificationCode(verificationMessage);
}
}
5 changes: 5 additions & 0 deletions cakk-api/src/main/java/com/cakk/api/mapper/EventMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
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.VerificationMessage;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class EventMapper {
Expand Down Expand Up @@ -42,4 +43,8 @@ public static CertificationMessage supplyCertificationMessageBy(final Certificat
longitude
);
}

public static VerificationMessage supplyVerificationMessageBy(final EmailWithVerificationCodeSendEvent event) {
return new VerificationMessage(event.email(), event.code());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
import com.cakk.api.common.base.MockitoTest;
import com.cakk.api.dto.event.EmailWithVerificationCodeSendEvent;
import com.cakk.external.sender.MessageSender;
import com.cakk.external.template.VerificationCodeSendTemplate;

class EmailSendEventListenerTest extends MockitoTest {

@InjectMocks
private EmailSendEventListener emailSendEventListener;

@Mock
private MessageSender messageSender;
private VerificationCodeSendTemplate verificationCodeSendTemplate;

private EmailWithVerificationCodeSendEvent eventFixture() {
return getConstructorMonkey().giveMeBuilder(EmailWithVerificationCodeSendEvent.class)
Expand All @@ -33,13 +34,13 @@ void sendEmailIncludeVerificationCode() {
// given
EmailWithVerificationCodeSendEvent event = eventFixture();

doNothing().when(messageSender).send(event.email(), event.code());
doNothing().when(verificationCodeSendTemplate).sendMessageForVerificationCode(any());

// when
assertDoesNotThrow(() -> emailSendEventListener.sendEmailIncludeVerificationCode(event));

// then
verify(messageSender, times(1)).send(event.email(), event.code());
verify(verificationCodeSendTemplate, times(1)).sendMessageForVerificationCode(any());
}

@TestWithDisplayName("이벤트에 null 데이터가 포함돼 있으면, 메일 전송 메서드가 호출 시, 에러를 반환한다.")
Expand All @@ -54,6 +55,6 @@ void sendEmailIncludeVerificationCode2() {
);

// then
verify(messageSender, times(0)).send(event.email(), event.code());
verify(verificationCodeSendTemplate, times(0)).sendMessageForVerificationCode(any());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.cakk.external.extractor

import com.cakk.external.vo.VerificationMessage

fun interface VerificationCodeMessageExtractor<T> {

fun extract(verificationMessage: VerificationMessage): T
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.cakk.external.extractor

import jakarta.mail.MessagingException
import jakarta.mail.internet.MimeMessage

import org.springframework.beans.factory.annotation.Value
import org.springframework.mail.javamail.JavaMailSender
import org.springframework.mail.javamail.MimeMessageHelper
import org.springframework.stereotype.Component

import com.cakk.common.enums.ReturnCode
import com.cakk.common.exception.CakkException
import com.cakk.external.vo.VerificationMessage

@Component
class VerificationCodeMimeMessageExtractor(
private val mailSender: JavaMailSender,
@Value("\${spring.mail.username}")
private val senderEmail: String
) : VerificationCodeMessageExtractor<MimeMessage> {

override fun extract(verificationMessage: VerificationMessage): MimeMessage {
val message = mailSender.createMimeMessage()

try {
val helper = MimeMessageHelper(message, true, "UTF-8")

helper.setTo(verificationMessage.receiver)
helper.setFrom(senderEmail)
helper.setSubject("[케이크크] 이메일 인증")

val body = """
<h3>인증코드를 확인해 주세요.</h3>
<h1>${verificationMessage.verificationCode}</h1>
이메일 인증 절차에 따라 이메일 인증코드를 발급해드립니다.<br>
인증코드는 이메일 발송시점으로부터 3분 동안 유효합니다.<br>
만약 본인 요청에 의한 이메일 인증이 아니라면, cakk.contact@gmail.com 으로 관련 내용을 전달해 주세요.
더욱 편리한 서비스를 제공하기 위해 항상 최선을 다하는 케이크크가 되겠습니다.
<br><br>
감사합니다.
""".trimIndent()
helper.setText(body, true)
} catch (e: MessagingException) {
throw CakkException(ReturnCode.SEND_EMAIL_ERROR)
}

return message
}
}
Original file line number Diff line number Diff line change
@@ -1,59 +1,23 @@
package com.cakk.external.sender

import jakarta.mail.MessagingException
import jakarta.mail.internet.MimeMessage

import org.springframework.beans.factory.annotation.Value
import org.springframework.mail.javamail.JavaMailSender
import org.springframework.mail.javamail.MimeMessageHelper
import org.springframework.stereotype.Component

import com.cakk.common.enums.ReturnCode
import com.cakk.common.exception.CakkException

@Component
class EmailSender(
private val mailSender: JavaMailSender,
@Value("\${spring.mail.username}")
private val senderEmail: String
): MessageSender<String> {
private val mailSender: JavaMailSender
) : MessageSender<MimeMessage> {

override fun send(receiver: String, message: String) {
override fun send(message: MimeMessage) {
try {
val emailForm = createMailFrom(receiver, message)

mailSender.send(emailForm)
mailSender.send(message)
} catch (e: RuntimeException) {
throw CakkException(ReturnCode.SEND_EMAIL_ERROR)
}
}

private fun createMailFrom(receiverMail: String, code: String): MimeMessage {
val message = mailSender.createMimeMessage()

try {
val helper = MimeMessageHelper(message, true, "UTF-8")

helper.setTo(receiverMail)
helper.setFrom(senderEmail)
helper.setSubject("[케이크크] 이메일 인증")

val body = """
<h3>인증코드를 확인해 주세요.</h3>
<h1>$code</h1>
이메일 인증 절차에 따라 이메일 인증코드를 발급해드립니다.<br>
인증코드는 이메일 발송시점으로부터 3분 동안 유효합니다.<br>
만약 본인 요청에 의한 이메일 인증이 아니라면, cakk.contact@gmail.com 으로 관련 내용을 전달해 주세요.
더욱 편리한 서비스를 제공하기 위해 항상 최선을 다하는 케이크크가 되겠습니다.
<br><br>
감사합니다.
""".trimIndent()
helper.setText(body, true)
} catch (e: MessagingException) {
throw CakkException(ReturnCode.SEND_EMAIL_ERROR)
}

return message
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.cakk.external.template

import com.cakk.external.extractor.VerificationCodeMessageExtractor
import com.cakk.external.sender.MessageSender
import com.cakk.external.vo.VerificationMessage

class VerificationCodeSendTemplate<T>(
private val messageSender: MessageSender<T>,
private val verificationCodeMessageExtractor: VerificationCodeMessageExtractor<T>
) {

fun sendMessageForVerificationCode(verificationMessage: VerificationMessage) {
this.sendMessageForVerificationCode(
verificationMessage = verificationMessage,
verificationCodeMessageExtractor = verificationCodeMessageExtractor,
messageSender = messageSender
)
}

private fun <T> sendMessageForVerificationCode(
verificationMessage: VerificationMessage,
verificationCodeMessageExtractor: VerificationCodeMessageExtractor<T>,
messageSender: MessageSender<T>
) {
val extractMessage: T = verificationCodeMessageExtractor.extract(verificationMessage)
messageSender.send(extractMessage)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.cakk.external.vo

data class VerificationMessage(
val receiver: String,
val verificationCode: String
)

0 comments on commit f361cbe

Please sign in to comment.