
本文详解如何在 thymeleaf 模板中安全、规范地渲染动态 html 片段(如带列表的 `
- `),避免 `th:text` 自动转义导致标签显示为纯文本,并推荐使用 `th:each` + 数据结构替代拼接 html 字符串的反模式。
在使用 Thymeleaf 作为邮件模板引擎时,一个常见误区是:将已含 HTML 标签的字符串(如 "
- ...
✅ 正确做法:用 th:each 替代 HTML 字符串拼接
与其在 Java 层手动拼接 HTML 字符串(如 "
- ..."),不如将数据结构化传递给模板——即传入 List
,再由 Thymeleaf 在模板中生成语义化、可维护的 HTML: ✅ 推荐模板写法(修正版):
Template for reminder to team lead
- 示例步骤
✅ 对应 Java 变量准备(关键:变量名一致 + 类型为 List):
立即学习“前端免费学习笔记(深入)”;
TeamLead teamLead = mission.getTeamLead(); Member member = mission.getUMember(); // ✅ 传入 List
,而非拼接好的 HTML 字符串 List lateSteps = Arrays.asList( "fetch his food today", "talk to the blacksmith" ); Map variables = new HashMap<>(); variables.put("firstNameTeamLead", teamLead.getFirstName()); // 注意:与模板中变量名严格一致 variables.put("lastNameTeamLead", teamLead.getLastName()); variables.put("member", member.getFirstName()); variables.put("lateSteps", lateSteps); // 类型是 List,非 String ⚠️ 为什么不推荐 th:utext?
虽然 th:utext="${lateStepsHtml}" 可强制不转义并渲染 HTML,但存在明显风险:
- XSS 漏洞隐患:若 lateStepsHtml 来自用户输入或未清洗的数据,可能执行恶意脚本;
- 模板逻辑外移:HTML 结构本应由模板控制,而非在 Java 层拼接,违背关注点分离原则;
- 可读性与可维护性差:字符串拼接易出错(如你原模板中的 缺失开标签),且难以调试。
? 其他注意事项
- 变量名一致性:确保 createNotificationTlVariables() 中 put("key", value) 的 key 与模板中 ${key} 完全匹配(如 firstNameTL ≠ firstNameTeamLead);
- HTML 结构合法性:Thymeleaf 不校验 HTML 语法,但邮件客户端(如 Outlook、Gmail)对非法嵌套或缺失闭合标签容忍度低,务必验证输出 HTML 的有效性;
-
邮件客户端兼容性:
- 在主流邮件客户端中支持良好,但避免使用 CSS Flex/Grid 或复杂样式;内联样式(style="...")更稳妥。
✅ 总结
方式 安全性 可维护性 推荐度 th:text + HTML 字符串 ❌(自动转义失效) ❌(逻辑混杂) ⛔ th:utext + HTML 字符串 ⚠️(需严格过滤) ❌(模板失控) ⚠️(仅限可信静态内容) th:each + List ✅(天然防 XSS) ✅(结构清晰) ✅✅✅ 坚持“数据驱动模板”,让 Thymeleaf 做它最擅长的事——安全、声明式地渲染结构化数据,这才是构建健壮邮件通知系统的最佳实践。











