知識庫 / Spring RSS 訂閱

使用 ThymeLeaf 和 FreeMarker 郵件模板與 Spring 結合

Spring
HongKong
10
01:00 PM · Dec 06 ,2025

1. 概述

在上一篇文章中,我們學習瞭如何使用 Spring 來編寫和發送文本郵件。

但也有可能使用 Spring 模板引擎來編寫包含動態內容的精美 HTML 郵件。

在本教程中,我們將學習如何使用最流行的引擎:ThymeleafFreeMarker

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,對於簡單的需求,如發送郵件,其使用方式非常相似。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.