1. 概述
Thymeleaf 是一款用于处理和生成 HTML、XML、JavaScript、CSS 以及纯文本的 Java 模板引擎。
在本篇文章中,我们将重点介绍 如何将 Thymeleaf 集成到 Spring 应用中,并探讨它在 Spring MVC 视图层的一些典型使用场景。
Thymeleaf 具有极强的可扩展性,同时天然支持模板原型化开发,这意味着即使没有后端服务也可以直接预览模板内容。相比 JSP 等传统模板技术,这种特性大大加快了前端开发效率。
2. 在 Spring 中集成 Thymeleaf
首先来看一下与 Spring 集成所需的配置项。要实现集成,需要引入 thymeleaf-spring
相关依赖。
我们先在 Maven 的 POM 文件中添加如下依赖:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
⚠️ 注意:如果是 Spring 4 项目,请使用 thymeleaf-spring4
依赖而不是 thymeleaf-spring5
。
核心类是 SpringTemplateEngine
,它负责完成所有的模板引擎初始化工作。
我们可以在 Java 配置文件中将其注册为一个 Bean:
@Bean
@Description("Thymeleaf Template Resolver")
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
@Bean
@Description("Thymeleaf Template Engine")
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setTemplateEngineMessageSource(messageSource());
return templateEngine;
}
其中,templateResolver
的 prefix
和 suffix
属性分别定义了视图页面的路径前缀和文件扩展名。
接下来是视图解析器(ViewResolver)部分。Spring MVC 中的 ViewResolver
负责把控制器返回的逻辑视图名映射为实际的视图对象。Thymeleaf 提供了 ThymeleafViewResolver
来实现这一功能。
最后一步是将 ThymeleafViewResolver
注册为 Bean:
@Bean
@Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
✅ 至此,Thymeleaf 已成功集成进 Spring 项目中。
3. 在 Spring Boot 中使用 Thymeleaf
Spring Boot 对 Thymeleaf 提供了自动配置支持。只需添加以下 starter 依赖即可:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
无需额外配置,默认情况下 HTML 模板应放在 resources/templates
目录下即可被识别。
4. 显示来自消息源(属性文件)的内容
可以使用 th:text="#{key}"
标签属性来展示来自 .properties
文件中的内容。
为此,我们需要先将属性文件注册为 messageSource
Bean:
@Bean
@Description("Spring Message Resolver")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
然后在 HTML 模板中引用该 key:
<span th:text="#{welcome.message}" />
5. 显示模型属性
5.1. 简单属性
使用 th:text="${attributename}"
可以直接显示模型中的简单属性值。
比如在 Controller 中设置一个属性:
model.addAttribute("serverTime", dateFormat.format(new Date()));
在模板中就可以这样展示:
Current time is <span th:text="${serverTime}" />
5.2. 集合属性
如果模型属性是一个集合对象,可以用 th:each
进行遍历。
定义一个 Student 实体类:
public class Student implements Serializable {
private Integer id;
private String name;
// standard getters and setters
}
Controller 中添加集合数据:
List<Student> students = new ArrayList<Student>();
// logic to build student data
model.addAttribute("students", students);
模板中遍历并显示:
<tbody>
<tr th:each="student: ${students}">
<td th:text="${student.id}" />
<td th:text="${student.name}" />
</tr>
</tbody>
6. 条件判断语句
6.1. if 与 unless
使用 th:if="${condition}"
来控制元素是否渲染,而 th:unless="${condition}"
则相反。
例如,在 Student 类中新增 gender 字段:
public class Student implements Serializable {
private Integer id;
private String name;
private Character gender;
// standard getters and setters
}
假设该字段只允许 M/F 值,我们可以用如下方式显示性别:
<td>
<span th:if="${student.gender} == 'M'" th:text="Male" />
<span th:unless="${student.gender} == 'M'" th:text="Female" />
</td>
6.2. switch 与 case
更优雅的方式是使用 th:switch
和 th:case
实现条件分支:
<td th:switch="${student.gender}">
<span th:case="'M'" th:text="Male" />
<span th:case="'F'" th:text="Female" />
</td>
7. 处理用户输入
处理表单提交时,可使用 th:action="@{url}"
和 th:object="${object}"
。
th:action
:指定表单提交的目标 URL;th:object
:绑定表单数据的对象;th:field="*{name}"
:绑定具体字段。
以 Student 类为例创建一个表单:
<form action="#" th:action="@{/saveStudent}" th:object="${student}" method="post">
<table border="1">
<tr>
<td><label th:text="#{msg.id}" /></td>
<td><input type="number" th:field="*{id}" /></td>
</tr>
<tr>
<td><label th:text="#{msg.name}" /></td>
<td><input type="text" th:field="*{name}" /></td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
</tr>
</table>
</form>
对应的 Controller 方法:
@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
public String saveStudent(Model model, @ModelAttribute("student") Student student) {
// logic to process input data
}
@RequestMapping
将 URL 映射到方法;@ModelAttribute
绑定表单字段到对象;- 方法内部执行业务逻辑处理。
8. 显示校验错误信息
可以通过 #fields.hasErrors()
判断是否有错误,使用 #fields.errors()
获取错误信息。
显示特定字段的错误:
<ul>
<li th:each="err : ${#fields.errors('id')}" th:text="${err}" />
<li th:each="err : ${#fields.errors('name')}" th:text="${err}" />
</ul>
也可使用通配符 *
或常量 all
表示所有字段:
<ul>
<li th:each="err : ${#fields.errors('*')}" th:text="${err}" />
</ul>
或使用 th:errors
属性简化写法:
<ul>
<li th:errors="*{id}" />
<li th:errors="*{name}" />
</ul>
全局错误可通过 global
常量获取:
<ul>
<li th:each="err : ${#fields.errors('global')}" th:text="${err}" />
</ul>
9. 数据格式化显示
使用双大括号语法 {{}}
可对字段进行格式化显示。这依赖于上下文中配置的 conversionService
中的格式化器。
示例格式化 Student 的 name 字段:
<tr th:each="student: ${students}">
<td th:text="${{student.name}}" />
</tr>
格式化器需继承 Spring 的 Formatter
接口,并通过 WebMvcConfigurer
注册:
@Configuration
public class WebMVCConfig extends WebMvcConfigurerAdapter {
// ...
@Override
@Description("Custom Conversion Service")
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new NameFormatter());
}
}
还可以使用 #conversions.convert()
工具函数转换类型:
<tr th:each="student: ${students}">
<td th:text="${#conversions.convert(student.percentage, 'Integer')}" />
</tr>
10. 总结
本文详细介绍了如何在 Spring MVC 中集成和使用 Thymeleaf 模板引擎,包括:
✅ 展示模型属性
✅ 渲染条件语句
✅ 表单处理与输入绑定
✅ 错误信息展示
✅ 字段格式化输出
完整代码示例可在 GitHub 仓库 中找到。