이전에, 메일 발송을 위해, Spring에서 제공하는
JavaMailSender
개체와 Thymeleaf 에서 제공하는TemplateEngine
을 활용해서 HTML의 내부 값을 가변적으로 만들어내도록 코드를 작성하였습니다.
초기의 비지니스 로직과 다르게, 메일의 종류가 다양해짐에 따라서, Template이 많아졌고, 그에 따라서 가변적으로 들어가야 할 데이터도 다양해졌습니다. 이를 다형성과 상속을 이용해 풀어낸 방법에 대해 작성해보도록 하겠습니다.
MailBodyInfo
메일 마다 공통적으로 들어가야 내용을 담을 추상클래스템플릿 HTML 파일명
, 메일 제목
MailMetaInfo
메일을 설명하기 위한 공통적인 메타정보를 포함하는 추상클래스메일의 종류
, 메일 받을 사람들
정보를 기본적으로 갖고 있음EmailService
각 구현체들과 TemplateEngine
을 활용해서 Mail 내용을 만들고 발송하는 클래스다음으로 추상클래스 , 구현체 클래스 예시를 보면서 조금 더 자세히 알아보겠습니다.
@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
클래스로 다음과 같은 구성입니다. (자세한 내용 주석 확인해 주세요)
멤버변수
메소드
makeBodyFromMeta()
함수MailBodyInfo
추상 클래스로 다음과 같은 구성입니다. ( 자세한 내용 주석 확인해 주세요)
@Getter
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder
public abstract class MailBodyInfo {
// 메일 바디 종류
protected MailBodyInfoType mailBodyInfoType;
// 메일 제목
protected String subject;
// 메일 내부 헤더
protected String 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()
메소드만 호출해주면 내부 구현은 변화없이 사용 가능하도록 하였습니다.