1. 概述
在上一篇文章中,我們學習瞭如何使用 Spring 來編寫和發送文本郵件。
但也有可能使用 Spring 模板引擎來編寫包含動態內容的精美 HTML 郵件。
在本教程中,我們將學習如何使用最流行的引擎:Thymeleaf 和 FreeMarker。
2. Spring HTML 郵件
我們從 Spring 郵件教程開始。
首先,我們將向 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 < /em > 來填充消息。關鍵在於將 true 值傳遞給 setText 方法:它指定了 HTML 內容類型。
讓我們看看如何使用 Thymeleaf 和 FreeMarker 模板構建這個 htmlBody。
3. Thymeleaf 配置
讓我們從配置開始。我們可以將其隔離在一個名為 EmailConfiguration 的類中。
首先,我們應該 提供一個模板解析器來定位模板文件目錄。
3.1. 模板作為類路徑資源
模板文件可以打包在 JAR 文件中,這是保持模板與其輸入數據之間連貫性的最簡單方法。
要從 JAR 文件中定位模板,我們使用 ClassLoaderTemplateResolver。 我們的模板位於 main/resources/mail-templates 目錄下,因此我們設置 Prefix 屬性,使其相對於 resource 目錄:
@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, 替代了我們在 thymeleafTemplateResolver 方法中的 ClassLoaderTemplateResolver:
FileTemplateResolver templateResolver = new FileTemplateResolver();
templateResolver.setPrefix(mailTemplatesPath);3.3. 配置 Thymeleaf 引擎
最後一步是創建 Thymeleaf 引擎的工廠方法。我們需要告訴引擎我們選擇的 TemplateResolver,可以通過參數注入到 Bean 工廠方法中:
@Bean
public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver templateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver);
templateEngine.setTemplateEngineMessageSource(emailMessageSource());
return templateEngine;
}在這裏,我們之前創建的解析器會自動被 Spring 注入到模板引擎工廠方法中。
4. FreeMarker 配置
類似於 Thymeleaf,在 <em >EmailConfiguration</em> 類中,我們將配置 FreeMarker 模板的 <strong >解析器 <em>(.ftl)</strong >。
並且這次,模板的位置將配置在 <em >FreeMarkerConfigurer</em> Bean 中。
4.1. 類路徑中的模板
這裏,我們擁有與 Thymeleaf 相同的選項。 讓我們將模板配置為類路徑資源:
@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 Baeldung</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 附件 來實現。
第一個更改涉及 sendHtmlMessage 方法。我們需要通過將 MimeMessageHelper 設置為多部分,將 true 傳遞給構造函數的第二個參數:
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 相關;因此,無論使用 Thymeleaf 還是 FreeMarker,對於簡單的需求,如發送郵件,其使用方式非常相似。