参考文章:技术派Thymeleaf模板引擎

Thymeleaf是什么

Thymeleaf 是一个优秀的、面向 Java 的 HTML 页面模板,具有丰富的标签语言和函数。在 JSP 被淘汰之后,Thymeleaf 取而代之成为了 Spring Boot 推荐的模板引擎。

20250804161423

Thymeleaf 在有网和没网的环境下都可以正常工作,既能让美工在浏览器中查看页面的静态效果,也能让程序员在服务器查看带数据的动态页面效果。

这是因为 Thymeleaf 支持 HTML 原型,在 HTML 标签里增加额外的属性来达到模板+数据的展示方式。

浏览器在解释 HTML 的时候会忽略未定义的标签属性,所以 Thymeleaf 可以静态地运行;当有数据返回页面时,Thymeleaf 标签会动态地替换静态内容

下面列举一些 Thymeleaf 常用的表达式、标签和函数。

常用表达式

1)常用表达式

  • ${...} 变量表达式
  • *{...} 选择表达式
  • #{...} 文字表达式
  • @{...} URL 表达式
  • #maps 对象表达式
    2)常用标签
  • th:action 定义服务器端控制器路径。
  • th:each 循环语句
  • th:field 表单字段
  • th:href URL 链接
  • th:id div 标签中的 ID
  • th:if 条件判断
  • th:include 引入文件
  • th:fragment 定义代码片段
  • th:object 替换对象
  • th:src 图片地址
  • th:text 文本
  • th:value 属性值
    3)常用函数
  • #dates 日期函数
  • #lists 列表函数
  • #arrays 数组函数
  • #strings 字符串函数
  • #numbers 数字函数
  • #calendars 日历函数
  • #objects 对象函数
  • #bools 布尔函数

想要查看更多 Thymeleaf 表达式、标签、函数等内容,可以到 Thymeleaf 官网: https://www.thymeleaf.org/

项目如何整合Thymeleaf

第一步 引入依赖

第一步,在 ui 模块 pom.xml 文件中添加 Thymeleaf 的 stater

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

第二步 配置Thymeleaf

第二步,在 web 模块 dev/application-web.yml 文件中添加 Thymeleaf 的配置

1
2
3
4
5
6
7
spring:
thymeleaf:
mode: HTML
encoding: UTF-8
servlet:
content-type: text/html
cache: false
  • mode: 模板模式,通常情况下设置为 “HTML”。
  • encoding: 模板文件的字符编码,通常设置为 “UTF-8”。
  • servlet.content-type: 在 Servlet 环境中,模板的 content type。一般设置为 “text/html”,代表生成的内容是 HTML。
  • cache: 是否缓存模板。在开发环境中,通常设置为 false,这样每次修改模板文件后,不需要重启应用就可以看到效果。在生产环境中,通常设置为 true,以提高性能。可参照 prod/application-web.yml

第三步 编写控制器

第三步,我们直接来看首页吧,在 IndexController 中添加 index 方法,内容如下。

1
2
3
4
5
6
7
@GetMapping(path = {"/", "", "/index"})
public String index(Model model, HttpServletRequest request) {
String activeTab = request.getParameter("category");//获取当前激活的内容分类
IndexVo vo = indexRecommendHelper.buildIndexVo(activeTab);//根据当前激活的分类获取首页数据
model.addAttribute("vo", vo);
return "views/home/index";
}

我尝试大白话讲一下上面代码渲染模板的逻辑:

  • 客户端发送请求到服务器会被controller接收到,然后在上面获取到了数据.
  • 然后将这个数据添加到了Model中,最后返回”views/home/index”视图.
  • 这个视图会被Thymeleaf引擎解析,然后将Model中的数据填充到视图中.
  • 最后返回给客户端.

很好理解,当访问首页的时候,返回 “views/home/index” 视图,该视图是一个 Thymeleaf 页面。

不同的Controller

SpringMVC里面返回类型的区分主要基于下面:

  1. 控制器类型
    1
    2
    @Controller  // 默认返回视图名称
    @RestController // = @Controller + @ResponseBody,直接返回JSON
  2. 方法级注解
    1
    2
    3
    4
    5
    6
    @GetMapping("/page")
    public String page(Model model) { /* 返回视图 */ }

    @ResponseBody
    @GetMapping("/api/data")
    public DataVo api() { /* 返回JSON */ }
  3. 内容协商机制
    1
    2
    GET /api/data.json  // 返回JSON
    GET /api/data.xml // 返回XML
  4. 常见应用场景
    1
    2
    3
    4
    graph LR
    A[请求类型] --> B{含.html/.ftl等后缀}
    B -->|是| C[返回视图模板]
    B -->|否| D[返回JSON]

实际开发中建议:
前后端分离项目统一使用@RestController
服务端渲染页面使用@Controller
混合模式可以通过produces属性明确指定:

1
2
@GetMapping(value = "/api/data", produces = "application/json")
public DataVo api() { /* 返回JSON */ }

第四步 编写Thymeleaf页面

第四步,在 paicoding-ui 模块下新建 index.html 文件(文件名对应控制器中 index 方法返回的字符串).

20250804162141

这里只截个图,简单解释一下里面用到 Thymeleaf 的几个关键点。

<html lang="zh" xmlns:th="http://www.thymeleaf.org"> 为 Thymeleaf 的命名空间,通过引入命名空间就可以在 HTML 文件中使用 Thymeleaf 标签语言,用关键字 “th”来标注。

th:replace: 用指定的模板片段替换当前的元素。比如 th:replace="components/layout/header :: head(~{::title}, ~{}, ~{})" 就是将当前的 div 元素替换为 components/layout/header 模板中的 head 片段。

th:text: 设置元素的文本内容。比如 th:text="${global.siteInfo.websiteName}" 就是将当前元素的文本内容设置为 global.siteInfo.websiteName 的值。

th:href: 设置元素的 href 属性。类似的还有 th:src,用于设置元素的 src 属性。

th:if: 设置元素的条件显示。如果表达式的值为 true,则显示元素,否则不显示。比如 th:if="${!#lists.isEmpty(vo.sideBarItems)}",如果 vo.sideBarItems 不为空,就显示当前元素。

th:inline="javascript" 表示下面的 script 标签中包含 Thymeleaf 表达式,需要进行处理。

第五步 测试

第五步,启动主类,在浏览器地址栏里输入 http://127.0.0.1:8080/ 访问首页。

Spring Boot 是如何自动装配 Thymeleaf 的?

Spring Boot 的核心功能就是自动配置,这在整合 Thymeleaf 时也不例外。当我们在项目依赖中加入 spring-boot-starter-thymeleaf 后,Spring Boot 就会自动配置 Thymeleaf。这包括创建 Thymeleaf 的模板解析器、模板引擎,以及视图解析器

在 Spring Boot 的自动装配模块(spring-boot-autoconfigure)中,有一个名为 ThymeleafAutoConfiguration 的配置类,这个类负责 Thymeleaf 的自动配置。

20250804185305

大家可以扒开 ThymeleafAutoConfiguration 细致看一下,我这里帮大家梳理几个点:

①、@EnableConfigurationProperties(ThymeleafProperties.class): 启用 Thymeleaf 的配置属性类 ThymeleafProperties,这个类定义了 Thymeleaf 的各种配置项,如模板的位置、缓存策略等。

20250804185348

和我们前面提到的 Thymeleaf 配置项是呼应的。

②、@ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class }): 这个条件注解表示只有当类路径中存在 TemplateMode 类和 SpringTemplateEngine 类时,才会启用这个自动配置。

TemplateMode 是 Thymeleaf 的类。

20250804190558

SpringTemplateEngine 是 Spring 与 Thymeleaf 集成的类。

20250804190853

所以,这个配置类的启动条件是 Thymeleaf 和 Spring 都存在。

模版解析器

ThymeleafAutoConfiguration 中,有一个名为 DefaultTemplateResolverConfiguration 的内部类,这个类负责创建 Thymeleaf 的模板解析器。

20250804192433

Thymeleaf 模板解析器负责解析模板文件,并将模板文件解析为 Thymeleaf 可以处理的内部结构。DefaultTemplateResolverConfiguration 模板解析器可以处理在 classpath:/templates/ 目录下的 .html 文件。

模板引擎

模板引擎是 Thymeleaf 的核心,它负责执行模板的处理和渲染。在处理模板时,模板引擎会使用表达式执行引擎对 Thymeleaf 表达式进行求值,同时还会执行所有定义的处理器。

Thymeleaf 中,模板引擎的核心类是 org.thymeleaf.TemplateEngine。该类负责处理模板,并产生处理结果。SpringTemplateEngineTemplateEngine 的子类,比如在 ThymeleafWebMvcConfigurationThymeleafWebFluxConfiguration 类中,SpringTemplateEngine 对象会被注入到 ThymeleafViewResolverThymeleafReactiveViewResolver 中。

20250804193345

TemplateEngineConfigurations.DefaultTemplateEngineConfigurationTemplateEngineConfigurations.ReactiveTemplateEngineConfiguration 配置类负责具体的引擎配置。

20250804195730

视图解析器

视图解析器的任务是将控制器方法返回的视图名解析为实际的视图对象。在 Spring Boot 自动配置的 Thymeleaf 中,视图名就是模板文件的名字。例如,视图名 “index” 对应的模板文件是 classpath:/templates/index.html

ThymeleafAutoConfiguration 中,有一个名为 ThymeleafWebMvcConfiguration 的内部类,它内部又有一个内部类 ThymeleafViewResolverConfiguration,这个类负责创建 Thymeleaf 的视图解析器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

// 配置类注解,proxyBeanMethods=false表示不代理@Bean方法,优化启动性能
@Configuration(proxyBeanMethods = false)
static class ThymeleafViewResolverConfiguration {

// 定义Thymeleaf视图解析器Bean
@Bean
// 仅当容器中不存在名为"thymeleafViewResolver"的Bean时才创建
@ConditionalOnMissingBean(name = "thymeleafViewResolver")
ThymeleafViewResolver thymeleafViewResolver(ThymeleafProperties properties,
SpringTemplateEngine templateEngine) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
// 设置模板引擎
resolver.setTemplateEngine(templateEngine);
// 从配置获取字符编码
resolver.setCharacterEncoding(properties.getEncoding().name());
// 组合内容类型和字符编码
resolver.setContentType(
appendCharset(properties.getServlet().getContentType(), resolver.getCharacterEncoding()));
// 设置是否在渲染过程中产生部分输出
resolver.setProducePartialOutputWhileProcessing(
properties.getServlet().isProducePartialOutputWhileProcessing());
// 设置排除的视图名称
resolver.setExcludedViewNames(properties.getExcludedViewNames());
// 设置匹配的视图名称
resolver.setViewNames(properties.getViewNames());
// 设置解析器顺序(低优先级),作为后备解析器
resolver.setOrder(Ordered.LOWEST_PRECEDENCE - 5);
// 是否启用缓存
resolver.setCache(properties.isCache());
return resolver;
}
}

简单总结一下,Spring Boot通过ThymeleafAutoConfiguration类来自动装配Thymeleaf。该类定义了许多Bean(如SpringTemplateEngineThymeleafViewResolver等),并使用条件注解(如@ConditionalOnClass@ConditionalOnMissingBean等)来实现条件装配。由于使用了@EnableConfigurationProperties(ThymeleafProperties.class)注解来注入和读取Thymeleaf相关属性,所以我们可以在 application.yml 中自定义 Thymeleaf 的配置项。

如何将后端数据返回给 Thymeleaf 呢?

理解了 Thymeleaf 的自动装配机制后,我们再来思考一个问题:如果我们想把后端的数据传回给 Thymeleaf,该怎么办呢?

其实也简单,我们可以通过 ModeladdAttribute 方法来完成,比如说 model.addAttribute("vo", vo);

20250804201711

这样就能将数据传回给 Thymeleaf 了。

那 Thymeleaf 页面中如何取出这些数据呢?
在 HTML 中,可以通过 ${vo.xxxx} 的方式。

1
2
3
<div
th:replace="views/home/navbar/index :: navbar(${vo.categories})"
></div>

这一行代码表示,用模板文件views/home/navbar/index中定义的navbar元素(可能是一个HTML的片段或整个元素)替换当前div标签。${vo.categories}表示传递给navbar元素的参数。在模板文件views/home/navbar/index中,这个参数可以使用Thymeleaf的表达式访问。

JavaScript 中,可以通过 const archiveId = [[${vo.yyyy}]] 的方式。

1
2
3
4
5
6
7
8
<script th:inline="javascript">
const archiveId = [[${vo.categoryId}]]
const category = [[${ vo.currentCategory }]]
const params = {
"category": category ? category : '全部',
"page": 2
}
</script>

[[${vo.categoryId}]]是Thymeleaf的内联表达式,这表示在服务器端渲染页面时,这个表达式会被${vo.categoryId}的值替代。

那如果是一些公共的属性,针对所有页面的全局信息,该怎么办呢?

我们可以通过全局拦截器的方式,GlobalViewInterceptor 中的 postHandle(这个方法在请求处理完成后,但在视图渲染之前执行)来完成。

20250804201854

通过 modelAndView.getModel().put("global", globalInitService.globalAttr()); 来往视图中增加一些全局信息。

比如说把开发环境、测试环境还是生产环境放进来,然后通过 ${global.env} 的方式访问。

20250804202116

小结

Spring Boot通过自动配置(Auto-configuration)可以轻松整合了Thymeleaf模板引擎。

只需要在项目中添加Spring Boot Thymeleaf Starter依赖,就能启用Thymeleaf的自动配置,该过程在ThymeleafAutoConfiguration类中实现。

自动配置会创建必要的SpringTemplateEngine,ThymeleafViewResolver等Bean。

在application.yml中,可以对Thymeleaf进行个性化配置,如模板的前缀和后缀,缓存策略等。

在Controller层,我们可以使用Model对象将数据传递到Thymeleaf中,并在模板中利用Thymeleaf的各种标签(如th:text,th:if等)进行数据渲染和交互逻辑处理。

如果需要一些全局信息,则可以通过拦截器来完成。

以上,尤其是 Thymeleaf 的自动装配和全局信息这里可以实操一下,会学到很多。