Spring 整合 Thymeleaf 模板引擎
1、概览
Thymeleaf 是一个 Java 模板引擎,用于处理和创建 HTML、XML、JavaScript、CSS 和文本。
本文将带你了解如何在 Spring 和 Spring Boot 应用中整合、使用 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 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
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 文件)中的值
可以使用 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.1、 示例属性
使用 th:text="${attributename}" 标签属性来渲染 Model 属性。
在 Controller 类中添加一个名为 serverTime 的 Model 属性:
model.addAttribute("serverTime", dateFormat.format(new Date()));
渲染 serverTime 属性:
Current time is <span th:text="${serverTime}" />
5.2、集合属性
如果 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.1、if 和 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
使用 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、处理用户输入
可以使用 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 验证错误
可以使用 #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、 格式化和转换
使用双括号语法 {{}} 来格式化要渲染的数据。这使用了在 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、总结
本文介绍了如何在 Spring 应用中整合和使用 Thymeleaf。还介绍了如何渲染字段、处理表单输入、渲染验证错误和转换数据。
Ref:https://www.baeldung.com/thymeleaf-in-spring-mvc