[Java] 메일 발송 코드 리팩토링

한호성·2024년 1월 30일
0

Introduction

이전에, 메일 발송을 위해, Spring에서 제공하는 JavaMailSender 개체와 Thymeleaf 에서 제공하는 TemplateEngine 을 활용해서 HTML의 내부 값을 가변적으로 만들어내도록 코드를 작성하였습니다.

초기의 비지니스 로직과 다르게, 메일의 종류가 다양해짐에 따라서, Template이 많아졌고, 그에 따라서 가변적으로 들어가야 할 데이터도 다양해졌습니다. 이를 다형성과 상속을 이용해 풀어낸 방법에 대해 작성해보도록 하겠습니다.

Class Diagram

  • MailBodyInfo 메일 마다 공통적으로 들어가야 내용을 담을 추상클래스
    • 템플릿 HTML 파일명 , 메일 제목
  • MailMetaInfo 메일을 설명하기 위한 공통적인 메타정보를 포함하는 추상클래스
    • 메일의 종류, 메일 받을 사람들 정보를 기본적으로 갖고 있음
  • EmailService 각 구현체들과 TemplateEngine 을 활용해서 Mail 내용을 만들고 발송하는 클래스

Flow Chart

다음으로 추상클래스 , 구현체 클래스 예시를 보면서 조금 더 자세히 알아보겠습니다.

@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
@Getter
public abstract class MailMetaInfo {

    // 받는 사람
    protected List<User> targetUserMailList;
    // 메일 종류
    protected MailType mailType;

    /**
     *
     * @param projectName 메일 제목의 [] 괄호 안 앞쪽에 들어갈 내용. ex) [HHS: 리뷰 요청] 의 HHS
     * @param linkPrefix 메일 본문의 링크에 정적으로 사용될 prefix. ex) 127.0.0.1:8084/
     * @return MetaInfo, projectName, linkPrefix를 사용하여 필요한 MailBodyInfo 구현체를 리턴하도록 구현
     */
    public abstract MailBodyInfo makeBodyFromMeta(String projectName, String linkPrefix);

}

MailMetaInfo 추상 클래스로 다음과 같은 구성입니다. ( 자세한 내용 주석 확인해 주세요)

멤버변수

  • 받는 사람들
  • 메일 종류

메소드

  • makeBodyFromMeta()

다음으로 구현체 예시를 보겠습니다.

@Getter
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public class MentionMailMetaInfo extends MailMetaInfo {
    private Long contractId;
    private String contractName;
    private User contractCreateUser;
    private Instant contractCreateDate;
    // 나를 멘션한 사람
    private User mentionUser;
    // 멘션 내용
    private String comment;
    private String workspaceCode;
    private String workspaceName;

    @Override
    public MailBodyInfo makeBodyFromMeta(String projectName, String linkPrefix) {
        return MentionMailBodyInfo.builder()
                .subject(this.getMailType().getMailSubjectWithContractName(projectName, this.getContractName(), this.getWorkspaceName()))
                .type(this.getMailType().getMailTypeToString())
                .mailBodyInfoType(MailBodyInfoType.MENTION)
                .workspaceName(workspaceName)
                .contractName(this.getContractName())
                .mentionUserName(this.getMentionUser().getUserName())
                .comment(Parser.convertCommentToMessage(this.getComment()))
                .createUser(this.getContractCreateUser().getUserName())
                .createDate(DateTimeTransform.changeToAsiaSeoul(this.getContractCreateDate(), DATE_TIME_FORMAT_PATTERN_03))
                .link(linkPrefix + "contracts/" + this.workspaceCode + "/" + this.getContractId())
                .build();
    }

    public void updateWorkspaceName(String wsName) {
        this.workspaceName = wsName;
    }

    public static MentionMailMetaInfo of(ContractComment contractComment, List<User> mentoinUserList) {
        Contract contract = contractComment.getContractHistory().getContract();
        return MentionMailMetaInfo.builder()
                .targetUserMailList(mentoinUserList)
                .mailType(MailType.NOTICE_MENTION)
                .contractId(contract.getId())
                .contractName(contract.getContractName())
                .contractCreateUser(contract.getUser())
                .contractCreateDate(contract.getCreateDate())
                .mentionUser(contractComment.getCreateUser())
                .comment(contractComment.getDetails())
                .workspaceCode(contract.getWorkspaceCode())
                .build();
    }
}

MailMetaInfo 를 구현한 MentionMailMetaInfo 클래스로 다음과 같은 구성입니다. (자세한 내용 주석 확인해 주세요)

멤버변수

  • 각 템플릿 HTML 본문에 필요한 내용들

메소드

  • 추상메소드 구현체 makeBodyFromMeta() 함수

MailBodyInfo 추상 클래스로 다음과 같은 구성입니다. ( 자세한 내용 주석 확인해 주세요)

@Getter
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public abstract class MailBodyInfo {
    // 메일 바디 종류
    protected MailBodyInfoType mailBodyInfoType;
    // 메일 제목
    protected String subject;
    // 메일 내부 헤더
    protected String type;
}

멤버변수

  • 메일 Template의 type 식별
  • 메일 제목 (공통 부분)
  • 메일 내부 헤더 (공통 부분)

MailBodyInfo 구현체 클래스

@Getter
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public class MentionMailBodyInfo extends MailBodyInfo {
    //메일 내부 내용
    private String workspaceName;
    private String contractName;
    private String mentionUserName;
    private String comment;
    private String createUser;
    private String createDate;
    private String link;

    public void updateLink(String link) {
        this.link = link;
    }
}

멤버변수

  • 멘션 메일에 필요한 부수적인 데이터들 포함

다음과 같이 수정함으로써, 새로운 메일 템플릿이 생길 때마다, 각각 추상클래스의 구현체 + Template HTML 추가하게 될 경우, EmailService 의 sendEmails() 메소드만 호출해주면 내부 구현은 변화없이 사용 가능하도록 하였습니다.

profile
개발자 지망생입니다.

0개의 댓글