Skip to content

Commit

Permalink
[Feature] 메일 스케쥴링 작업 (#409)
Browse files Browse the repository at this point in the history
* feat: 테스트를 위한 @EnableJpaAuditing 설정 이동

* feat: mail 전송 여부 확인을 위한 isSent 변수 추가

* feat: mail 전송시 체크를 위한 consultingId 추가

* feat: 스케쥴링을 통한 메일 전송 실패 대비

* feat: 메일 구성 추가

로고 및 사용자 이름 추가

* chore: 메일 스케쥴링 cron 변경

1분 -> 5분
  • Loading branch information
jjddhh authored Aug 26, 2023
1 parent b4d102d commit d934539
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableAsync
@EnableScheduling
@SpringBootApplication
public class BeMyCarMasterApplication {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package softeer.be_my_car_master.application.consult.handler;

import java.util.List;
import java.util.stream.Collectors;

import org.springframework.transaction.annotation.Transactional;

import lombok.RequiredArgsConstructor;
import softeer.be_my_car_master.domain.consulting.Consulting;
import softeer.be_my_car_master.global.annotation.Adaptor;
import softeer.be_my_car_master.infrastructure.jpa.car_master.entity.ConsultingEntity;
import softeer.be_my_car_master.infrastructure.jpa.car_master.repository.ConsultingJpaRepository;

@Adaptor
@RequiredArgsConstructor
public class MailSendAdaptor implements MailSendPort {

private final ConsultingJpaRepository consultingJpaRepository;

@Override
@Transactional
public void sendComplete(Long consultingId) {
ConsultingEntity consulting = consultingJpaRepository.findById(consultingId).get();
consulting.sendEmail();
}

@Override
public List<Consulting> findSendFailureConsultings() {
return consultingJpaRepository.findAllByIsSent(false).stream()
.map(ConsultingEntity::toConsulting)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,7 @@
public class MailSendEvent {

private UUID estimateId;
private String clientName;
private String clientEmail;
private Long consultingId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,31 @@ public class MailSendHandler {

private final JavaMailSender mailSender;
private final SpringTemplateEngine templateEngine;
private final MailSendPort mailSendPort;

@Async
@TransactionalEventListener(
phase = TransactionPhase.AFTER_COMMIT,
classes = MailSendEvent.class
)
public void publicApplyConsultingEvent(MailSendEvent mailSendEvent) throws MessagingException {

MimeMessage mimeMessage = mailSender.createMimeMessage();
String text = makeText(mailSendEvent.getEstimateId());
String text = makeText(mailSendEvent.getEstimateId(), mailSendEvent.getClientName());

MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage, false, "UTF-8");
mimeMessageHelper.setTo(mailSendEvent.getClientEmail());
mimeMessageHelper.setSubject("다들 화이팅합시다~");
mimeMessageHelper.setSubject("[Hyundai] " + mailSendEvent.getClientName() + "님의 구매 상담 신청이 접수되었습니다.");
mimeMessageHelper.setText(text, true); // 메일 본문 내용, HTML 여부
mailSender.send(mimeMessage);

mailSendPort.sendComplete(mailSendEvent.getConsultingId());
}

private String makeText(UUID estimateId) {
private String makeText(UUID estimateId, String clientName) {
String clientEstimateLink = estimateLink + estimateId.toString();
Context context = new Context();
context.setVariable("clientEstimateLink", clientEstimateLink);
context.setVariable("clientName", clientName);
return templateEngine.process("mail", context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package softeer.be_my_car_master.application.consult.handler;

import java.util.List;

import softeer.be_my_car_master.domain.consulting.Consulting;
import softeer.be_my_car_master.global.annotation.Port;

@Port
public interface MailSendPort {

void sendComplete(Long consultingId);

List<Consulting> findSendFailureConsultings();
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public Optional<CarMaster> findCarMasterById(Long carMasterId) {
}

@Override
public void createConsulting(Consulting consulting) {
consultingJpaRepository.save(ConsultingEntity.from(consulting));
public Long createConsulting(Consulting consulting) {
ConsultingEntity consultingEntity = consultingJpaRepository.save(ConsultingEntity.from(consulting));
return consultingEntity.getId();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ public interface ApplyConsultingPort {

Optional<CarMaster> findCarMasterById(Long carMasterId);

void createConsulting(Consulting consulting);
Long createConsulting(Consulting consulting);
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public void execute(
.orElseThrow(() -> InvalidCarMasterIdException.EXCEPTION);

Consulting consulting = Consulting.create(clientName, clientEmail, clientPhone, estimate, carMaster);
port.createConsulting(consulting);
Long consultingId = port.createConsulting(consulting);

// 이메일 전송
eventPublisher.publishEvent(new MailSendEvent(estimateId, clientEmail));
eventPublisher.publishEvent(new MailSendEvent(estimateId, clientName, clientEmail, consultingId));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package softeer.be_my_car_master.domain.consulting;

import java.util.UUID;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
Expand All @@ -13,9 +15,11 @@
@AllArgsConstructor
public class Consulting {

private Long id;
private String clientName;
private String clientEmail;
private String clientPhone;
private Boolean isSent;
private Estimate estimate;
private CarMaster carMaster;

Expand All @@ -35,4 +39,8 @@ public static Consulting create(
.carMaster(carMaster)
.build();
}

public UUID getUuid() {
return estimate.getUuid();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package softeer.be_my_car_master.global.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;

@Configuration
@EnableJpaAuditing
public class BaseTimeConfig {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package softeer.be_my_car_master.global.config;

import java.util.List;
import java.util.UUID;

import javax.transaction.Transactional;

import org.springframework.context.ApplicationEventPublisher;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import softeer.be_my_car_master.application.consult.handler.MailSendEvent;
import softeer.be_my_car_master.application.consult.handler.MailSendPort;
import softeer.be_my_car_master.domain.consulting.Consulting;

@Slf4j
@Component
@RequiredArgsConstructor
public class SchedulingConfig {

private final MailSendPort mailSendPort;
private final ApplicationEventPublisher eventPublisher;

@Transactional
@Scheduled(cron = "0 */5 * * * *")
public void setDiaryEditStatus() {
List<Consulting> sendFailureConsultings = mailSendPort.findSendFailureConsultings();
sendEmails(sendFailureConsultings);
}

private void sendEmails(List<Consulting> sendFailureConsultings) {
sendFailureConsultings.stream()
.forEach(consulting -> {
UUID uuid = consulting.getUuid();
String clientName = consulting.getClientName();
String clientEmail = consulting.getClientEmail();
Long id = consulting.getId();
eventPublisher.publishEvent(new MailSendEvent(uuid, clientName, clientEmail, id));
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@
import softeer.be_my_car_master.domain.car_master.CarMaster;
import softeer.be_my_car_master.domain.consulting.Consulting;
import softeer.be_my_car_master.domain.estimate.Estimate;
import softeer.be_my_car_master.global.config.BaseTime;
import softeer.be_my_car_master.infrastructure.jpa.estimate.entity.EstimateEntity;

@Entity
@Table(name = "consulting")
@Builder
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ConsultingEntity {
public class ConsultingEntity extends BaseTime {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -39,6 +40,9 @@ public class ConsultingEntity {
@Column(name = "client_phone", nullable = false)
private String clientPhone;

@Column(name = "is_sent", nullable = false)
private Boolean isSent;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "estimate_id", nullable = false)
private EstimateEntity estimate;
Expand All @@ -47,6 +51,10 @@ public class ConsultingEntity {
@JoinColumn(name = "car_master_id", nullable = false)
private CarMasterEntity carMaster;

public Long getId() {
return id;
}

public static ConsultingEntity from(Consulting consulting) {
Estimate estimate = consulting.getEstimate();
EstimateEntity estimateEntity = EstimateEntity.from(estimate);
Expand All @@ -60,6 +68,26 @@ public static ConsultingEntity from(Consulting consulting) {
.clientPhone(consulting.getClientPhone())
.estimate(estimateEntity)
.carMaster(carMasterEntity)
.isSent(false)
.build();
}

public Consulting toConsulting() {
Estimate estimate = Estimate.builder()
.uuid(this.estimate.getUuid())
.build();

return Consulting.builder()
.id(id)
.clientName(clientName)
.clientEmail(clientEmail)
.clientPhone(clientPhone)
.isSent(isSent)
.estimate(estimate)
.build();
}

public void sendEmail() {
isSent = true;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
package softeer.be_my_car_master.infrastructure.jpa.car_master.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import softeer.be_my_car_master.infrastructure.jpa.car_master.entity.ConsultingEntity;

public interface ConsultingJpaRepository extends JpaRepository<ConsultingEntity, Long> {

@Query(value = "SELECT c "
+ "FROM ConsultingEntity c "
+ "JOIN FETCH c.estimate "
+ "WHERE c.isSent = :isSent")
List<ConsultingEntity> findAllByIsSent(boolean isSent);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion BE-MyCarMaster/src/main/resources/templates/mail.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,11 @@

<body>
<div style="margin:100px;">
<h1> 안녕하세요.</h1>
<div align="top">
<img src="https://www.hyundai.com/content/dam/hyundai/kr/ko/images/mail-template/img_mailing_header.jpg" width="700" height="82" alt loading="lazy"/>
</div>

<h1 th:text="'안녕하세요 ' + ${clientName} + '님.'"> 안녕하세요.</h1>
<h1> 마이카마스터 서비스를 이용해주셔서 감사합니다. </h1>
<br>

Expand Down

0 comments on commit d934539

Please sign in to comment.