From 4eba14a5420aa31eb47df083051d750b9b44a422 Mon Sep 17 00:00:00 2001 From: SeungGyu Date: Thu, 20 Feb 2025 18:55:33 +0900 Subject: [PATCH] =?UTF-8?q?[refactor]=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B8=EC=A6=9D=EC=BD=94=EB=93=9C=20=EC=A0=84=EC=86=A1?= =?UTF-8?q?=EC=9D=84=20@Async=EB=A1=9C=20=EB=B9=84=EB=8F=99=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../pickyfy/common/config/AsyncConfig.java | 40 ++++++++++++++ .../pickyfy/service/EmailServiceImpl.java | 48 ++--------------- .../web/controller/AsyncEmailService.java | 54 +++++++++++++++++++ 3 files changed, 99 insertions(+), 43 deletions(-) create mode 100644 src/main/java/com/pickyfy/pickyfy/common/config/AsyncConfig.java create mode 100644 src/main/java/com/pickyfy/pickyfy/web/controller/AsyncEmailService.java diff --git a/src/main/java/com/pickyfy/pickyfy/common/config/AsyncConfig.java b/src/main/java/com/pickyfy/pickyfy/common/config/AsyncConfig.java new file mode 100644 index 0000000..a37e54f --- /dev/null +++ b/src/main/java/com/pickyfy/pickyfy/common/config/AsyncConfig.java @@ -0,0 +1,40 @@ +package com.pickyfy.pickyfy.common.config; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.lang.reflect.Method; +import java.util.concurrent.Executor; + +@Slf4j +@Configuration +@EnableAsync +public class AsyncConfig implements AsyncConfigurer { + + @Override + public Executor getAsyncExecutor(){ + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(2); + executor.setMaxPoolSize(5); + executor.setQueueCapacity(10); + executor.setThreadNamePrefix("Async MailExecutor-"); + executor.initialize(); + return executor; + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler(){ + return new CustomAsyncExceptionHandler(); + } + + private static class CustomAsyncExceptionHandler implements AsyncUncaughtExceptionHandler { + @Override + public void handleUncaughtException(Throwable throwable, Method method, Object... obj) { + log.error("비동기 메서드 예외 발생: {}", method.getName(), throwable); + } + } +} diff --git a/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java b/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java index aa57758..c8b6d2e 100644 --- a/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java +++ b/src/main/java/com/pickyfy/pickyfy/service/EmailServiceImpl.java @@ -1,87 +1,49 @@ package com.pickyfy.pickyfy.service; import com.pickyfy.pickyfy.web.apiResponse.error.ErrorStatus; -import com.pickyfy.pickyfy.common.Constant; import com.pickyfy.pickyfy.common.util.JwtUtil; import com.pickyfy.pickyfy.common.util.RedisUtil; +import com.pickyfy.pickyfy.web.controller.AsyncEmailService; import com.pickyfy.pickyfy.web.dto.request.EmailVerificationSendRequest; import com.pickyfy.pickyfy.web.dto.request.EmailVerificationVerifyRequest; import com.pickyfy.pickyfy.web.dto.response.EmailVerificationSendResponse; import com.pickyfy.pickyfy.web.dto.response.EmailVerificationVerifyResponse; import com.pickyfy.pickyfy.exception.ExceptionHandler; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.MimeMessage; -import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Service; -import org.thymeleaf.TemplateEngine; -import org.thymeleaf.context.Context; import java.util.concurrent.ThreadLocalRandom; @Service @RequiredArgsConstructor public class EmailServiceImpl implements EmailService { - private static final String ENCODING = "utf-8"; - private static final String EMAIL_TITLE = "[Pickyfy] 인증코드"; - private static final String VARIABLE_NAME = "code"; - private static final String TEMPLATE = "mail"; - - private final JavaMailSender javaMailSender; - private final TemplateEngine templateEngine; + private final AsyncEmailService asyncEmailService; private final RedisUtil redisUtil; private final JwtUtil jwtUtil; - @Transactional @Override public EmailVerificationSendResponse sendAuthCode(EmailVerificationSendRequest request) { String email = request.email(); String code = generateVerificationCode(); - sendVerificationEmail(code, email); + asyncEmailService.sendVerificationEmail(code, email); return new EmailVerificationSendResponse(email, code); } - @Transactional @Override public EmailVerificationVerifyResponse verifyAuthCode(EmailVerificationVerifyRequest request) { String email = request.email(); String inputCode = request.code(); String savedCode = redisUtil.getData("email:" + email); + redisUtil.deleteData("email:" + email); if(!savedCode.equals(inputCode)){ throw new ExceptionHandler(ErrorStatus.AUTH_CODE_INVALID); } + return new EmailVerificationVerifyResponse(email, jwtUtil.createEmailToken(email)); } private String generateVerificationCode() { return Long.toString(ThreadLocalRandom.current().nextLong(100000L, 999999L)); } - - private void sendVerificationEmail(String code, String email) { - try { - MimeMessage mimeMessage = createMimeMessage(code, email); - javaMailSender.send(mimeMessage); - } catch (MessagingException e) { - throw new ExceptionHandler(ErrorStatus._INTERNAL_SERVER_ERROR); - } - - redisUtil.setData("email:" + email, code, Constant.EMAIL_TOKEN_EXPIRATION_TIME); - } - - private MimeMessage createMimeMessage(String code, String email) throws MessagingException { - MimeMessage mimeMessage = javaMailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, ENCODING); - helper.setSubject(EMAIL_TITLE); - helper.setTo(email); - - Context context = new Context(); - context.setVariable(VARIABLE_NAME, code); - String htmlContent = templateEngine.process(TEMPLATE, context); - helper.setText(htmlContent, true); - - return mimeMessage; - } } \ No newline at end of file diff --git a/src/main/java/com/pickyfy/pickyfy/web/controller/AsyncEmailService.java b/src/main/java/com/pickyfy/pickyfy/web/controller/AsyncEmailService.java new file mode 100644 index 0000000..55e150e --- /dev/null +++ b/src/main/java/com/pickyfy/pickyfy/web/controller/AsyncEmailService.java @@ -0,0 +1,54 @@ +package com.pickyfy.pickyfy.web.controller; + +import com.pickyfy.pickyfy.common.Constant; +import com.pickyfy.pickyfy.common.util.RedisUtil; +import com.pickyfy.pickyfy.exception.ExceptionHandler; +import com.pickyfy.pickyfy.web.apiResponse.error.ErrorStatus; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.MimeMessage; +import lombok.RequiredArgsConstructor; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + +@Service +@RequiredArgsConstructor +public class AsyncEmailService { + + private static final String ENCODING = "utf-8"; + private static final String EMAIL_TITLE = "[Pickyfy] 인증코드"; + private static final String VARIABLE_NAME = "code"; + private static final String TEMPLATE = "mail"; + + private final JavaMailSender javaMailSender; + private final TemplateEngine templateEngine; + private final RedisUtil redisUtil; + + @Async + public void sendVerificationEmail(String code, String email) { + try { + MimeMessage mimeMessage = createMimeMessage(code, email); + javaMailSender.send(mimeMessage); + } catch (MessagingException e) { + throw new ExceptionHandler(ErrorStatus._INTERNAL_SERVER_ERROR); + } + redisUtil.setData("email:" + email, code, Constant.EMAIL_TOKEN_EXPIRATION_TIME); + } + + private MimeMessage createMimeMessage(String code, String email) throws MessagingException { + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, ENCODING); + helper.setSubject(EMAIL_TITLE); + helper.setTo(email); + + Context context = new Context(); + context.setVariable(VARIABLE_NAME, code); + String htmlContent = templateEngine.process(TEMPLATE, context); + helper.setText(htmlContent, true); + + return mimeMessage; + } +}