1、概览 {#1概览}
Thymeleaf 是一个 Java 模板引擎,用于处理和创建 HTML、XML、JavaScript、CSS 和文本。
本文将带你了解如何在 Spring 和 Spring Boot 应用中整合、使用 Thymeleaf。
该库具有极高的可扩展性,其天然的模板功能可以确保在没有后端的情况下制作模板原型。与其他流行的模板引擎(如 JSP)相比,这使得开发速度非常快。
2、Spring 整合 Thymeleaf {#2spring-整合-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
Bean 的 prefix
和 suffix
属性分别表示视图页面在 webapp
目录中的位置及其文件扩展名。
Spring MVC 的 ViewResolver
接口将 Controller 返回的视图名称映射为实际的视图对象。ThymeleafViewResolver
实现了 ViewResolver
接口,用于根据视图名称确定要渲染的 Thymeleaf 视图。
整合的最后一步是将 ThymeleafViewResolver
添加为一个 Bean:
@Bean
@Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
3、Spring Boot 整合 Thymeleaf {#3spring-boot-整合-thymeleaf}
Spring Boot 通过添加 spring-boot-starter-thymeleaf
依赖,为 Thymeleaf 提供了自动配置功能:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
无需明确配置。默认情况下,HTML 文件应放在 resources/templates
位置。
4、渲染 Message Source(Properties 文件)中的值 {#4渲染-message-sourceproperties-文件中的值}
可以使用 th:text="#{key}"
标签属性来渲染 Properties 文件中的值。
为此,需要将 Properties 文件配置为 messageSource
Bean:
@Bean
@Description("Spring Message Resolver")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
渲染 welcome.message
的 KEY 值:
<span th:text="#{welcome.message}" />
5、渲染 Model 属性 {#5渲染-model-属性}
5.1、 示例属性 {#51-示例属性}
使用 th:text="${attributename}"
标签属性来渲染 Model 属性。
在 Controller 类中添加一个名为 serverTime
的 Model 属性:
model.addAttribute("serverTime", dateFormat.format(new Date()));
渲染 serverTime
属性:
Current time is <span th:text="${serverTime}" />
5.2、集合属性 {#52集合属性}
如果 Model 属性是一个对象集合,可以使用 th:each
标签属性对其进行遍历。
定义一个包含 id
和 name
两个字段的 Student
Model 类:
public class Student implements Serializable {
private Integer id;
private String name;
// 标准的 GET / SET
}
在 Controller 类中添加一个 List<Student>
作为 Model 属性:
List<Student> students = new ArrayList<Student>();
// 构建 students 的逻辑 ...
model.addAttribute("students", students);
最后,遍历 students
列表并渲染所有字段值:
<tbody>
<tr th:each="student: ${students}">
<td th:text="${student.id}" />
<td th:text="${student.name}" />
</tr>
</tbody>
6、条件分支 {#6条件分支}
6.1、if
和 unless
{#61if--和-unless}
使用 th:if="${condition}"
属性在满足条件时渲染视图的某个部分。如果不满足条件,使用 th:unless="${condition}"
属性来渲染视图的某个部分。
在 Student
model 中添加一个 gender
字段:
public class Student implements Serializable {
private Integer id;
private String name;
private Character gender;
// 标准的 GET 、SET 方法
}
假设这个字段有两个枚举值 (M
或 F
)来表示学生的性别。
如果想渲染 "Male" 或 "Female" 字样,而不是单个字符,可以使用 th:if
来实现:
<td>
<span th:if="${student.gender} == 'M'" th:text="Male" />
<span th:unless="${student.gender} == 'M'" th:text="Female" />
</td>
6.2、 switch
和 case
{#62-switch-和-case}
使用 th:switch
和 th:case
属性,通过 switch 语句结构有条件地渲染内容。
使用 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、处理用户输入 {#7处理用户输入}
可以使用 th:action="@{url}"
和 th:object="${object}"
属性来处理表单输入。使用 th:action
提供表单 action
URL,使用 th:object
指定要将提交的表单数据绑定到的对象。
单个字段使用 th:field="{name}"
属性映射,其中 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>
在上述代码中,/saveStudent
是表单 action URL,student
是保存所提交表单数据的对象。
saveStudent
方法处理表单提交:
@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
public String saveStudent(Model model, @ModelAttribute("student") Student student) {
// 处理输入数据的逻辑
}
@RequestMapping
注解将 Controller 方法与表单中提供的 URL 映射。注解方法 saveStudent()
对提交的表单执行所需的处理。最后,@ModelAttribute
注解将表单字段与 student
对象绑定。
8、渲染 Validation 验证错误 {#8渲染-validation-验证错误}
可以使用 #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
来表示所有字段。使用 th:each
属性来遍历每个字段可能存在的多个错误。
下面是使用通配符重写的 HTML 代码:
<ul>
<li th:each="err : ${#fields.errors('*')}" th:text="${err}" />
</ul>
下例使用了常量 all
:
<ul>
<li th:each="err : ${#fields.errors('all')}" th:text="${err}" />
</ul>
同样,也可以使用 global
常量在 Spring 中渲染全局错误。如下:
<ul>
<li th:each="err : ${#fields.errors('global')}" th:text="${err}" />
</ul>
此外,还可以使用 th:errors
属性来渲染错误信息。
使用 th:errors
属性重写之前在表单中渲染错误的代码:
<ul>
<li th:errors="*{id}" />
<li th:errors="*{name}" />
</ul>
9、 格式化和转换 {#9-格式化和转换}
使用双括号语法 {{}}
来格式化要渲染的数据。这使用了在 conversionService
Bean 中为该类型字段配置的 formatters
。
格式化 Student
类中的 name
字段:
<tr th:each="student: ${students}">
<td th:text="${{student.name}}" />
</tr>
上述代码使用了 NameFormatter
类。该类通过 WebMvcConfigurer
接口中的 addFormatters()
方法进行配置。如下:
@Configuration
类继承了 WebMvcConfigurerAdapter
类:
@Configuration
public class WebMVCConfig extends WebMvcConfigurerAdapter {
// ...
@Override
@Description("Custom Conversion Service")
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new NameFormatter());
}
}
NameFormatter
类实现了 Spring Formatter
接口。
还可以使用 #conversions
来转换对象。其语法是 #conversions.convert(Object, Class)
,其中 Object
将转换为 Class
类型。
去掉 student
对象 percentage
字段的小数部分(转换为 Integer
):
<tr th:each="student: ${students}">
<td th:text="${#conversions.convert(student.percentage, 'Integer')}" />
</tr>
10、总结 {#10总结}
本文介绍了如何在 Spring 应用中整合和使用 Thymeleaf。还介绍了如何渲染字段、处理表单输入、渲染验证错误和转换数据。
Ref:https://www.baeldung.com/thymeleaf-in-spring-mvc