精通Spring Boot教程(19):使用thymeleaf或freemarker作为邮件模板
1. 概述
本篇文章中,将介绍如何使用Spring 模板引擎 Thymeleaf
和 FreeMarker
,来发送精美的HTML动态内容邮件。
2. Spring HTML 邮件
首先,我们向 EmailServiceImpl 类添加一个方法,以发送带有HTML正文的电子邮件:
private void sendHtmlMessage(String to, String subject, String htmlBody) throws MessagingException {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
helper.setTo(to);
helper.setSubject(subject);
helper.setText(htmlBody, true);
emailSender.send(message);
}
我们使用 MimeMessageHelper
填充消息。注意传递给 setText 方法的第二个参数为 true :它指定该邮件为HTML内容类型。
接下来看看如何使用 Thymeleaf
和 FreeMarker
模板来构建这个 htmlBody。
3. Thymeleaf 配置
先从配置开始,我们可以新建一个配置类,取名为 EmailConfiguration 。然后,提供一个模板解析器来定位模板文件目录。
3.1. Classpath Resources 中获取模板
模板文件可以在JAR文件中提供, 这是保持模板与其输入数据之间内聚性的最简单方法。
为了从JAR中定位模板,我们使用 ClassLoaderTemplateResolver。模板位于main/resources/mail templates目录中,因此我们设置了相对于resource目录的 Prefix 属性:
@Bean
public ITemplateResolver thymeleafTemplateResolver() {
ClassLoaderTemplateResolver templateResolver = new ClassLoaderTemplateResolver();
templateResolver.setPrefix("mail-templates/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML");
templateResolver.setCharacterEncoding("UTF-8");
return templateResolver;
}
3.2. 外部目录获取模板
在某些情况下,我们希望修改模板但却不需要重新构建和部署。为了实现这一点,我们可以将模板放在文件系统上。
在 application.properties 中配置此路径非常明智,这样我们就可以方便地修改模板路径。可以使用 @Value 注解来访问此属性:
@Value("${spring.mail.templates.path}")
private String mailTemplatesPath;
然后,我们将此模板路径传递给 FileTemplateResolver ,以代替 ThymeleaftTemplateResolver 方法中的ClassLoaderTemplateResolver:
FileTemplateResolver templateResolver = new FileTemplateResolver();
templateResolver.setPrefix(mailTemplatesPath);
3.3.配置 Thymeleaf 引擎
最后一步是为 Thymeleaf 引擎创建工厂方法。我们需要告诉引擎选择了哪个TemplateResolver,可以通过参数将其注入bean factory方法:
@Bean
public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
return templateEngine;
}
我们前面创建的解析器会通过 Spring 自动注入模板引擎工厂方法。
4. FreeMarker 配置
与 Thymeleaf 相同,在 EmailConfiguration 类中,我们将为 FreeMarker 模板 配置模板解析器:
而这次,模板的位置将配置在 FreeMarkerConfigurer
bean 中。
4.1. Classpath中获取模板
在这里,我们与 Thymeleaf
相同,把模板配置为 classpath resources:
@Bean
public FreeMarkerConfigurer freemarkerClassLoaderConfig() {
Configuration configuration = new Configuration(Configuration.VERSION_2_3_27);
TemplateLoader templateLoader = new ClassTemplateLoader(this.getClass(), "/mail-templates");
configuration.setTemplateLoader(templateLoader);
FreeMarkerConfigurer freeMarkerConfigurer = new FreeMarkerConfigurer();
freeMarkerConfigurer.setConfiguration(configuration);
return freeMarkerConfigurer;
}
4.2. 文件系统中获取模板
要从文件系统中的路径配置模板,我们需要替换 TemplateLoader 实例:
TemplateLoader templateLoader = new FileTemplateLoader(new File(mailTemplatesPath));
5. Thymeleaf 和 FreeMarker本地化
为了使用 Thymeleaf 引擎负责翻译模板,我们可以为其指定一个 MessageSource 实例:
@Bean
public ResourceBundleMessageSource emailMessageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("mailMessages");
return messageSource;
}
@Bean
public SpringTemplateEngine thymeleafTemplateEngine() {
...
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
...
}
然后,为支持的每个语言环境创建资源包:
src/main/resources/mailMessages_xx_YY.properties
FreeMarker 建议通过 复制模板
进行本地化,因此我们不必在那里配置消息源。
6. Thymeleaf 模板内容
接下来,我们看看 template-thymeleaf.html 文件:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p th:text="#{greetings(${recipientName})}"></p>
<p th:text="${text}"></p>
<p th:text="#{regards}"></p>
<p>
<em th:text="#{signature(${senderName})}"></em> <br />
</p>
</body>
</html>
可以看出,我们使用了 Thymeleaf 表达式,也就是说,对于变量,${...}
表示变量,#{...}
表示本地化字符串。
模板引擎配置如果正确,使用它非常简单:我们只需创建一个Context 对象,其中包含模板变量(在这里作为Map传递)。
然后,我们将它与模板名一起传递给process方法:
@Autowired
private SpringTemplateEngine thymeleafTemplateEngine;
@Override
public void sendMessageUsingThymeleafTemplate(
String to, String subject, Map<String, Object> templateModel)
throws MessagingException {
Context thymeleafContext = new Context();
thymeleafContext.setVariables(templateModel);
String htmlBody = thymeleafTemplateEngine.process("template-thymeleaf.html", thymeleafContext);
sendHtmlMessage(to, subject, htmlBody);
}
接下来,看看如何用 FreeMarker 做同样的事情。
7. FreeMarker 模板内容
通过下面的代码可以看出,FreeMarker 的语法更简单,但它同样不管理本地化的字符串。下面是英文版:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<p>Hi ${recipientName}</p>
<p>${text}</p>
<p>Regards,</p>
<p>
<em>${senderName} at 锅外的大佬</em> <br />
</p>
</body>
</html>
然后,我们应该使用 FreeMarkerConfigurer 类来获取模板文件,最后使用 FreeMarkerTemplateUtils 从 Map 中注入数据:
@Autowired
private FreeMarkerConfigurer freemarkerConfigurer;
@Override
public void sendMessageUsingFreemarkerTemplate(
String to, String subject, Map<String, Object> templateModel)
throws IOException, TemplateException, MessagingException {
Template freemarkerTemplate = freemarkerConfigurer.getConfiguration()
.getTemplate("template-freemarker.ftl");
String htmlBody = FreeMarkerTemplateUtils.processTemplateIntoString(freemarkerTemplate, templateModel);
sendHtmlMessage(to, subject, htmlBody);
}
为了能把邮件做的更加丰富,我们接下来了解一下如何在电子邮件签名中添加徽章或图片。
8. 嵌入图像的电子邮件
在HTML电子邮件中包含图像是非常常见的,我们将了解如何使用[CID附件]来实现这一点 。通过将true传递给构造函数的第二个参数,将MimeMessageHelper设置为 multi-part :
MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8");
然后将图像文件作为资源,可以使用 @Value 来实现:
@Value("classpath:/mail-logo.png")
Resource resourceFile;
mail-logo.png 文件位于 src/main/resources 目录中,回到 sendHtmlMessage 方法,我们将添加 resourceFile作为内联附件,以便能够用 CID 引用它:
helper.addInline("attachment.png", resourceFile);
最后使用 CID 符号在 Thymeleaf 和 FreeMarker 电子邮件模板中引用:
<img src="cid:attachment.png" />
9. 总结
在本文中,我们掌握了如何使用 Thymeleaf 和 FreeMarker 作为模板发送包含丰富的HTML内容邮件。大部分工作都与 Spring 有关;因此,对于发送电子邮件之类的简单需求,二者非常类似,使用其中一种方法就行。
- 本文标签: Spring Boot
- 版权声明: 本站原创文章,于2020年11月22日由刘一手发布,转载请注明出处