文章背景图

Thymeleaf 模板片段复用实践

问题

一个博客有二十来个页面,每个页面顶部都要放导航、底部都要放页脚。复制粘贴的后果是:

  • 加一个菜单项,要改二十个文件
  • 页脚的备案号换了,漏改一个页面就是违规
  • 某次改完,有三个页面的
少了一层,样式全乱

抽片段

新建 templates/fragments/site-footer.html:

<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.w3.org/1999/xhtml">
<body>
<footer th:fragment="site-footer" class="ui inverted vertical segment">
    <div class="ui container">
        <p>© 2020-2026 一颗星的博客</p>
        <p>
            <a href="https://beian.miit.gov.cn/" target="_blank" rel="noopener nofollow">
                蜀ICP备2021032163号-2
            </a>
        </p>
    </div>
</footer>
</body>
</html>

页面里引用:

<div th:replace="~{fragments/site-footer :: site-footer}"></div>

以后改备案号,只动这一个文件。

带参数的片段

导航需要在不同页面高亮不同的菜单项,片段就要带参数:

<nav th:fragment="site-nav(active, hidden)" class="gird-header"
     th:id="${hidden} ? 'nav' : null"
     th:style="${hidden} ? 'display:none' : null">
    <a th:href="@{/}" th:classappend="${active == 'index'} ? 'active'">首页</a>
    <a th:href="@{/archives}" th:classappend="${active == 'archives'} ? 'active'">时间轴</a>
</nav>

调用:

<nav th:replace="~{fragments/site-nav :: site-nav(active='index', hidden=false)}"></nav>

th:id="${hidden} ? 'nav' : null" 这个写法很实用:表达式返回 null 时,Thymeleaf 会把这个属性整个去掉,而不是渲染成 id="null"。

几个坑

片段文件里也要写 xmlns:th,否则编辑器不认 th:* 属性。

th:replace 会替换掉整个宿主标签,th:insert 才是插到标签内部。前者适合

占位,后者适合往已有的
里塞内容。

片段路径是相对 templates/ 的,写 fragments/site-footer 而不是 templates/fragments/site-footer。

参数名和片段签名必须对上,site-nav(active, hidden) 调用时少传一个,Spring 会报 TemplateProcessingException,而且错误信息不太直观,容易找半天。

顺手解决的事

把页脚抽出来之后,还发现一个隐性收益:所有页面的版权年份、备案号、联系方式天然一致。以前是"记得改",现在是"改一次全都对"。

这类"容易忘、忘了要出事"的内容,都应该收敛到一处。

  • 作者:一颗星
  • 发表时间:2026-06-05
  • 标签:Thymeleaf、模板、Spring Boot
  • 版权声明:署名-非商业性使用-相同方式共享 4.0(CC BY-NC-SA 4.0),转载请注明出处
  • 站点性质:本站为个人非经营性网站,不接受任何形式的打赏与赞助