Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): 메일전송을 비동기로 처리한다. #513

Merged
merged 6 commits into from
Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,21 @@
package com.example.tyfserver.common.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;

@Configuration
@EnableAsync
public class AsyncConfig {

@Bean(name = "mailExecutor")
public ThreadPoolTaskExecutor mailExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

우리가 지난번에 했던 http 미션에서 ExecutorService가 있고 그것을 통해서 스레드 관리를 해줄 수가 있었는데링크,
이것과 무슨 차이가 있는지 좀 찾아봤더니

Spring을 사용한다면 ThreadPoolTaskExecutor를 살펴보는 것도 좋다. 내부 구현은 ThreadPoolExecutor로 구현되어 있다. ThreadPoolExecutor 보다 조금 더 간편하며, 추가적인 return 타입도 있다.

출처 http://wonwoo.ml/index.php/post/2254

spring에서 조금 더 편하게 만든 스레드 관리 클래스였어!
image
내부적으로는 ThreadPoolExecutor를 사용하고 있었고,
image
image
workingQueue의 size도 new LinkedBlockingQueue<>(queueCapacity);를 이용하고 있는 것을 볼 수가 있는데, 저 큐는 ThreadPoolExecutor 에서도 사용하는 큐야! 스프링 별거를 다 도와주네 허허

executor.setThreadNamePrefix("mail-executor");
return executor;
}
}
Expand Up @@ -8,6 +8,7 @@
import org.springframework.core.io.ClassPathResource;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.thymeleaf.TemplateEngine;
import org.thymeleaf.context.Context;
Expand All @@ -20,16 +21,15 @@
import java.time.format.DateTimeFormatter;

@Component
@Async("mailExecutor")
@RequiredArgsConstructor
public class SmtpMailConnector {
// todo 메일 전송 시간이 김. 비동기로 해볼까?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오... 언행일치 👍👍 멋진데?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 근데 주석 작성 조이 아님 ? ㅋㅋㅋ

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아... 왜 수리가 적은줄 알았지...? 👀

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅇㅇ나임ㅋㅋ

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋ 조이임


private static final String PREFIX_SUBJECT = "[Thank You For]";

private final JavaMailSender javaMailSender;
private final TemplateEngine templateEngine;


public void sendVerificationCode(String mailAddress, String verificationCode) {
Context context = new Context();
context.setVariable("code", verificationCode);
Expand Down
@@ -1,9 +1,11 @@
package com.example.tyfserver.payment.domain;

import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.UUID;

@NoArgsConstructor
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

없어도 되지 않아? 왜 붙였어?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image
라고 하넹

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아고 저건 못봤넹

@Getter
public class PaymentInfo {
private UUID merchantUid;
Expand Down
52 changes: 26 additions & 26 deletions server/src/main/resources/static/index.html
Expand Up @@ -16,19 +16,19 @@

<script>
async function cancelPay() {
await jQuery.ajax({
url: "http://localhost:8080/payments/cancel",
method: "POST",
headers: {"Content-Type": "application/json"},
data: JSON.stringify({
merchantUid: "935cfb0e-86e5-4458-8994-993cd7dc4e19"
})
}).done(await function (data) {
console.log("환불 성공");
console.log(data);
}).fail(function (e) {
alert("실패!")
});
await jQuery.ajax({
Copy link
Collaborator

@Joyykim Joyykim Oct 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

index.html 삭제할까 생각중인데 혹시 고친 이유가 있어? 이거 쓰나?
비동기 테스트해보려고 한거야?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

응..비동기테스트는 직접 밖에 아직 방법을 못찾아서
나도 이 index.html 삭제하고픔.

삭제하기 전에 파노, 인치에게 프론트 개발 서버 또한 배포를 하면 어떨지에 대해서 말해볼까?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그건 따로 말하고 이건 그냥 삭제해도 될거같은데? 어차피 이거 쓰느 사람없고, 지금 api 서버에도 배포되어 있어서 아주 불편해

url: "http://localhost:8080/payments/cancel",
method: "POST",
headers: {"Content-Type": "application/json"},
data: JSON.stringify({
merchantUid: "935cfb0e-86e5-4458-8994-993cd7dc4e19"
})
}).done(await function (data) {
console.log("환불 성공");
console.log(data);
}).fail(function (e) {
alert("실패!")
});
}
</script>

Expand All @@ -39,26 +39,27 @@

async function requestPay() {
// 가맹점 서버에 Payment 생성 요청
const amount = 1000;
const amount = 1100;
const email = "ssop6403@gmail.com";
const pageName = "hwanorama";
const merchantUid = await createMerchantUid(amount, email, pageName);
const itemId = "ITEM_1";
const merchantUid = await createMerchantUid(amount,itemId);
// IMP.request_pay(param, callback) 호출
let result;
await IMP.request_pay({ // param
pay_method: "card",
merchant_uid: merchantUid,
name: pageName,
name: itemId,
amount: amount,
buyer_email: email
}, async function (rsp) { // callback
if (rsp.success) { // 결제 성공 시: 결제 승인 또는 가상계좌 발급에 성공한 경우
console.log("아임포트 요청 성공");
console.log(rsp);
await jQuery.ajax({
url: "http://localhost:8080/donations", // 가맹점 서버
url: "http://localhost:8080/payments/charge", // 가맹점 서버
method: "POST",
headers: {"Content-Type": "application/json"},
headers: {"Content-Type": "application/json",
"Authorization" : ""},
data: JSON.stringify({
impUid: rsp.imp_uid,
merchantUid: rsp.merchant_uid
Expand All @@ -68,7 +69,7 @@
console.log("결제 끝!");
console.log(data);
result = {
"impUid": data.impUid,
"itemId": data.impUid,
"merchantUid": data.merchantUid
};
if(data.status === "success") {
Expand All @@ -85,16 +86,15 @@
});
}

async function createMerchantUid(amount, email, pageName) {
async function createMerchantUid(amount, itemId) {
let merchantUid;
await jQuery.ajax({
url: "http://localhost:8080/payments", // 가맹점 서버
url: "http://localhost:8080/payments/charge/ready", // 가맹점 서버
method: "POST",
headers: {"Content-Type": "application/json"},
headers: {"Content-Type": "application/json",
"Authorization" : ""},
data: JSON.stringify({
amount: amount,
email: email,
pageName: pageName,
itemId: itemId
}),
contentType: "application/json",
dataType: "json"
Expand Down