From bd2827958801d7092e42329a63b516010dfae2fb Mon Sep 17 00:00:00 2001 From: vran Date: Fri, 25 Mar 2022 11:21:37 +0800 Subject: [PATCH] feat: update mail template --- build.gradle | 2 + core/build.gradle | 2 +- .../document/service/DocumentService.java | 3 +- .../subscriber/DocumentEventSubscriber.java | 60 +++++++------- .../event/subscriber/UserEventSubscriber.java | 43 ++++++---- .../core/infrastructure/mail/MailSender.java | 36 ++++++--- .../mail/MailTemplateConfig.java | 22 +++++ .../mail/MailTemplateProcessor.java | 30 +++++++ .../resources/ftl/mail/DiscussCreated.ftl | 0 .../resources/ftl/mail/DocumentUpdated.ftl | 81 +++++++++++++++++++ .../main/resources/ftl/mail/PasswordRenew.ftl | 61 ++++++++++++++ .../main/resources/ftl/mail/UserCreated.ftl | 65 +++++++++++++++ 12 files changed, 345 insertions(+), 60 deletions(-) create mode 100644 core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateConfig.java create mode 100644 core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateProcessor.java create mode 100644 core/src/main/resources/ftl/mail/DiscussCreated.ftl create mode 100644 core/src/main/resources/ftl/mail/DocumentUpdated.ftl create mode 100644 core/src/main/resources/ftl/mail/PasswordRenew.ftl create mode 100644 core/src/main/resources/ftl/mail/UserCreated.ftl diff --git a/build.gradle b/build.gradle index ff76286..ddb8c5d 100644 --- a/build.gradle +++ b/build.gradle @@ -35,6 +35,7 @@ subprojects { hikariVersion = '5.0.0' jacksonVersion = '2.13.1' easyExcelVersion = '3.0.5' + freemarkerVersion = '2.3.31' } dependencies { @@ -49,6 +50,7 @@ subprojects { implementation "org.slf4j:slf4j-api:${slf4jVersion}" implementation "com.alibaba:easyexcel:${easyExcelVersion}" + implementation "org.freemarker:freemarker:${freemarkerVersion}" } diff --git a/core/build.gradle b/core/build.gradle index bb87958..59aba72 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -29,8 +29,8 @@ dependencies { // others implementation 'com.auth0:java-jwt:3.18.3' implementation 'org.commonmark:commonmark:0.18.1' - implementation 'org.freemarker:freemarker:2.3.31' implementation 'com.alibaba:easyexcel' + implementation "org.freemarker:freemarker" implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-jackson:2.9.0' diff --git a/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java b/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java index ed7ad48..2021a36 100644 --- a/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java +++ b/core/src/main/java/com/databasir/core/domain/document/service/DocumentService.java @@ -112,7 +112,8 @@ public class DocumentService { eventPublisher.publish(new DocumentUpdated(diff, version + 1, version, projectId)); } else { saveNewDocument(current, 1L, projectId); - eventPublisher.publish(new DocumentUpdated(null, 1L, null, projectId)); + RootDiff diff = Diffs.diff(null, current); + eventPublisher.publish(new DocumentUpdated(diff, 1L, null, projectId)); } } diff --git a/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/DocumentEventSubscriber.java b/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/DocumentEventSubscriber.java index 98ea95e..ba5f18a 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/DocumentEventSubscriber.java +++ b/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/DocumentEventSubscriber.java @@ -4,6 +4,7 @@ import com.databasir.core.diff.data.DiffType; import com.databasir.core.diff.data.RootDiff; import com.databasir.core.domain.document.event.DocumentUpdated; import com.databasir.core.infrastructure.mail.MailSender; +import com.databasir.core.infrastructure.mail.MailTemplateProcessor; import com.databasir.dao.impl.ProjectDao; import com.databasir.dao.impl.SysMailDao; import com.databasir.dao.impl.UserDao; @@ -14,7 +15,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @Component @@ -30,26 +34,33 @@ public class DocumentEventSubscriber { private final SysMailDao sysMailDao; + private final MailTemplateProcessor mailTemplateProcessor; + @EventListener(classes = DocumentUpdated.class) public void onDocumentUpdated(DocumentUpdated created) { - ProjectPojo project = projectDao.selectById(created.getProjectId()); - List to = userDao.selectEnabledGroupMembers(project.getGroupId()) - .stream() - .map(UserPojo::getEmail) - .filter(mail -> mail.contains("@")) - .collect(Collectors.toList()); sysMailDao.selectOptionTopOne().ifPresent(mail -> { - String subject = project.getName() + " 文档有新的版本"; - String message = created.getDiff() - .map(diff -> build(diff)) - .orElseGet(() -> "首次文档同步常规"); - mailSender.batchSend(mail, to, subject, message); + ProjectPojo project = projectDao.selectById(created.getProjectId()); + List to = userDao.selectEnabledGroupMembers(project.getGroupId()) + .stream() + .filter(UserPojo::getEnabled) + .map(UserPojo::getEmail) + .filter(userEmail -> userEmail.contains("@")) + .collect(Collectors.toList()); + String subject = project.getName() + " 文档有新的内容变更"; + List> diffs = created.getDiff() + .map(this::diffs) + .orElseGet(Collections::emptyList); + Map context = new HashMap<>(); + context.put("diffs", diffs); + context.put("projectName", project.getName()); + String message = mailTemplateProcessor.process("ftl/mail/DocumentUpdated.ftl", context); + mailSender.batchSendHtml(mail, to, subject, message); }); } - private String build(RootDiff diff) { + private List> diffs(RootDiff diff) { if (diff.getDiffType() == DiffType.NONE) { - return ""; + return Collections.emptyList(); } else { return diff.getFields() .stream() @@ -57,25 +68,14 @@ public class DocumentEventSubscriber { .flatMap(f -> f.getFields().stream()) .map(table -> { String tableName = table.getFieldName(); - String change = toDescription(table.getDiffType()); - return tableName + " " + change; + Map map = Map.of( + "tableName", tableName, + "diffType", table.getDiffType().name() + ); + return map; }) - .collect(Collectors.joining("\n")); + .collect(Collectors.toList()); } } - private String toDescription(DiffType diffType) { - switch (diffType) { - case NONE: - return "无变化"; - case ADDED: - return "新增"; - case REMOVED: - return "删除"; - case MODIFIED: - return "修改"; - default: - return diffType.name(); - } - } } diff --git a/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/UserEventSubscriber.java b/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/UserEventSubscriber.java index adc01b9..70e4b79 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/UserEventSubscriber.java +++ b/core/src/main/java/com/databasir/core/infrastructure/event/subscriber/UserEventSubscriber.java @@ -4,6 +4,7 @@ import com.databasir.core.domain.user.data.UserSource; import com.databasir.core.domain.user.event.UserCreated; import com.databasir.core.domain.user.event.UserPasswordRenewed; import com.databasir.core.infrastructure.mail.MailSender; +import com.databasir.core.infrastructure.mail.MailTemplateProcessor; import com.databasir.dao.impl.SysMailDao; import com.databasir.dao.impl.UserDao; import com.databasir.dao.tables.pojos.UserPojo; @@ -12,6 +13,9 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; +import java.util.HashMap; +import java.util.Map; + /** * TODO use html template instead of simple message */ @@ -26,36 +30,41 @@ public class UserEventSubscriber { private final UserDao userDao; + private final MailTemplateProcessor mailTemplateProcessor; + @EventListener(classes = UserPasswordRenewed.class) public void onPasswordRenewed(UserPasswordRenewed event) { UserPojo operator = userDao.selectById(event.getRenewByUserId()); sysMailDao.selectOptionTopOne() .ifPresent(mailPojo -> { String renewBy = operator.getNickname(); - String subject = "Databasir 密码重置提醒"; - String message = String.format("Hi %s,\r\n 您的密码已被 %s 重置,新密码为 %s", - event.getNickname(), - renewBy, - event.getNewPassword()); - mailSender.send(mailPojo, event.getEmail(), subject, message); + Map context = new HashMap<>(); + context.put("renewBy", renewBy); + context.put("nickname", event.getNickname()); + context.put("newPassword", event.getNewPassword()); + String message = template("ftl/mail/PasswordRenew.ftl", context); + String subject = "Databasir 密码重置通知"; + mailSender.sendHtml(mailPojo, event.getEmail(), subject, message); }); } @EventListener(classes = UserCreated.class) public void onUserCreated(UserCreated event) { - String subject = "Databasir 账户创建成功"; - String message; if (UserSource.isManual(event.getSource())) { - message = String.format("Hi %s\r\n您的 Databasir 账户已创建成功,用户名:%s,密码:%s", - event.getNickname(), event.getUsername(), event.getRawPassword()); - } else { - message = String.format("Hi %s\r\n您的 Databasir 账户已创建成功,用户名:%s", - event.getNickname(), event.getUsername()); + sysMailDao.selectOptionTopOne() + .ifPresent(mailPojo -> { + Map context = new HashMap<>(); + context.put("nickname", event.getNickname()); + context.put("username", event.getUsername()); + context.put("password", event.getRawPassword()); + String message = template("ftl/mail/UserCreated.ftl", context); + String subject = "Databasir 账户创建成功"; + mailSender.sendHtml(mailPojo, event.getEmail(), subject, message); + }); } - sysMailDao.selectOptionTopOne() - .ifPresent(mailPojo -> { - mailSender.send(mailPojo, event.getEmail(), subject, message); - }); } + private String template(String templatePath, Map context) { + return mailTemplateProcessor.process(templatePath, context); + } } diff --git a/core/src/main/java/com/databasir/core/infrastructure/mail/MailSender.java b/core/src/main/java/com/databasir/core/infrastructure/mail/MailSender.java index bc53664..8668709 100644 --- a/core/src/main/java/com/databasir/core/infrastructure/mail/MailSender.java +++ b/core/src/main/java/com/databasir/core/infrastructure/mail/MailSender.java @@ -1,11 +1,14 @@ package com.databasir.core.infrastructure.mail; +import com.databasir.common.SystemException; import com.databasir.dao.tables.pojos.SysMailPojo; -import org.springframework.mail.SimpleMailMessage; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; import org.springframework.stereotype.Component; +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; import java.nio.charset.StandardCharsets; import java.util.Collection; import java.util.Collections; @@ -13,18 +16,29 @@ import java.util.Collections; @Component public class MailSender { - public void batchSend(SysMailPojo mail, Collection to, String subject, String content) { - SimpleMailMessage message = new SimpleMailMessage(); - message.setFrom(mail.getUsername()); - message.setTo(to.toArray(new String[0])); - message.setSubject(subject); - message.setText(content); - JavaMailSender sender = initJavaMailSender(mail); - sender.send(message); + public void sendHtml(SysMailPojo mail, + String to, + String subject, + String content) { + this.batchSendHtml(mail, Collections.singleton(to), subject, content); } - public void send(SysMailPojo mail, String to, String subject, String content) { - this.batchSend(mail, Collections.singleton(to), subject, content); + public void batchSendHtml(SysMailPojo mail, + Collection to, + String subject, + String content) { + JavaMailSender sender = initJavaMailSender(mail); + MimeMessage mimeMessage = sender.createMimeMessage(); + try { + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); + helper.setFrom(mail.getUsername()); + helper.setTo(to.toArray(new String[0])); + helper.setSubject(subject); + helper.setText(content, true); + sender.send(mimeMessage); + } catch (MessagingException e) { + throw new SystemException("send mail error", e); + } } private JavaMailSender initJavaMailSender(SysMailPojo properties) { diff --git a/core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateConfig.java b/core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateConfig.java new file mode 100644 index 0000000..0510380 --- /dev/null +++ b/core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateConfig.java @@ -0,0 +1,22 @@ +package com.databasir.core.infrastructure.mail; + +import freemarker.template.Configuration; +import freemarker.template.TemplateExceptionHandler; +import org.springframework.context.annotation.Bean; + +@org.springframework.context.annotation.Configuration +public class MailTemplateConfig { + + @Bean + public Configuration mailTemplateConfiguration() { + Configuration cfg = new Configuration(Configuration.VERSION_2_3_29); + cfg.setClassForTemplateLoading(getClass(), "/"); + cfg.setDefaultEncoding("UTF-8"); + cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER); + cfg.setLogTemplateExceptions(false); + cfg.setWrapUncheckedExceptions(true); + cfg.setFallbackOnNullLoopVariable(false); + return cfg; + } + +} diff --git a/core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateProcessor.java b/core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateProcessor.java new file mode 100644 index 0000000..a431e1b --- /dev/null +++ b/core/src/main/java/com/databasir/core/infrastructure/mail/MailTemplateProcessor.java @@ -0,0 +1,30 @@ +package com.databasir.core.infrastructure.mail; + +import com.databasir.common.SystemException; +import freemarker.template.Configuration; +import freemarker.template.Template; +import freemarker.template.TemplateException; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class MailTemplateProcessor { + + private final Configuration mailTemplateConfiguration; + + public String process(String templatePath, Map context) { + try { + Template template = mailTemplateConfiguration.getTemplate(templatePath); + StringWriter writer = new StringWriter(); + template.process(context, writer); + return writer.toString(); + } catch (IOException | TemplateException e) { + throw new SystemException("build template content error", e); + } + } +} diff --git a/core/src/main/resources/ftl/mail/DiscussCreated.ftl b/core/src/main/resources/ftl/mail/DiscussCreated.ftl new file mode 100644 index 0000000..e69de29 diff --git a/core/src/main/resources/ftl/mail/DocumentUpdated.ftl b/core/src/main/resources/ftl/mail/DocumentUpdated.ftl new file mode 100644 index 0000000..6ba3e89 --- /dev/null +++ b/core/src/main/resources/ftl/mail/DocumentUpdated.ftl @@ -0,0 +1,81 @@ + + +
+ + + + + + + + + + + + + +
+
+ + Databasir + + 专注于数据库文档管理 +
+
+
+
+
+

+ 数据库 ${projectName} 有新的文档变更: +

+
+ + + <#list diffs as diff > + <#if diff.diffType == "MODIFIED"> + + + + + <#elseif diff.diffType == "REMOVED"> + + + + + <#elseif diff.diffType == "ADDED"> + + + + + + +
${diff.tableName}修改
${diff.tableName}删除
${diff.tableName}新增
+
+
+

+ 详细变更内容请登录平台通过版本差异对比查看 +

+
+
+
+
+
+

+ 系统文档 + | + Databasir +

+
+
+
+
+ + + diff --git a/core/src/main/resources/ftl/mail/PasswordRenew.ftl b/core/src/main/resources/ftl/mail/PasswordRenew.ftl new file mode 100644 index 0000000..d771532 --- /dev/null +++ b/core/src/main/resources/ftl/mail/PasswordRenew.ftl @@ -0,0 +1,61 @@ + + +
+ + + + + + + + + + + + + +
+
+ + Databasir + + 专注于数据库文档管理 +
+
+
+
+
+

+ 尊敬的 ${nickname}:

+

+ 您的密码已被 ${renewBy} 重置,为了您的账户安全,请尽快通过以下密码登录系统并修改密码 +

+
+ + + ${newPassword} + + +
+
+
+
+
+
+

+ 系统文档 + | + Databasir +

+
+
+
+
+ + \ No newline at end of file diff --git a/core/src/main/resources/ftl/mail/UserCreated.ftl b/core/src/main/resources/ftl/mail/UserCreated.ftl new file mode 100644 index 0000000..9a73c8e --- /dev/null +++ b/core/src/main/resources/ftl/mail/UserCreated.ftl @@ -0,0 +1,65 @@ + + +
+ + + + + + + + + + + + + +
+
+ + Databasir + + 专注于数据库文档管理 +
+
+
+
+
+

+ 尊敬的 ${nickname}:

+

+ 您已成功注册 Databasir,用户名为 ${username}。 + 为了您的账号安全,请尽快通过以下密码登录系统并及时修改新密码 +

+
+ + + ${newPassword} + + +
+
+
+
+
+
+

+ 系统文档 + | + Databasir +

+
+
+
+
+ + +