在 Spring MVC 中使用 Thymeleaf
1.概述
Thymeleaf 是一个 Java 模板引擎,用于处理和创建 HTML、XML、JavaScript、CSS 和文本。
在本教程中,我们将讨论如何在 Spring MVC 应用程序的视图层中使用 Thymeleaf以及一些基本用例。
该库具有极强的可扩展性,其自然的模板功能确保我们可以在没有后端的情况下制作模板原型。与其他流行的模板引擎(例如 JSP)相比,这使得开发速度非常快。
2. 将 Thymeleaf 与 Spring 集成
首先,让我们看看与 Spring 集成所需的配置。集成需要thymeleaf-spring库。 我们将以下依赖项添加到我们的 Maven POM 文件中:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.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接口将控制器返回的视图名称映射到实际的视图对象。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. 显示来自消息源(属性文件)的值
我们可以使用*th:text=”#{key}”*标签属性来显示属性文件中的值。
为此,我们需要将属性文件配置为messageSource bean:
@Bean
@Description("Spring Message Resolver")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
这是 Thymeleaf HTML 代码,用于显示与键welcome.message关联的值:
<span th:text="#{welcome.message}" />
5. 显示模型属性
5.1. 简单属性
我们可以使用*th:text=”${attributename}”*标签属性来显示模型属性的值。
让我们在控制器类中添加一个名为serverTime的模型属性:
model.addAttribute("serverTime", dateFormat.format(new Date()));
这是显示serverTime属性值的 HTML 代码:
Current time is <span th:text="${serverTime}" />
5.2. 集合属性
如果模型属性是对象的集合,我们可以使用th:each标签属性对其进行迭代。
让我们定义一个包含两个字段id 和name的Student模型类:
public class Student implements Serializable {
private Integer id;
private String name;
// standard getters and setters
}
现在我们将在控制器类中添加一个学生列表作为模型属性:
List<Student> students = new ArrayList<Student>();
// logic to build student data
model.addAttribute("students", students);
最后,我们可以使用 Thymeleaf 模板代码遍历学生列表并显示所有字段值:
<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)来指示学生的性别。 如果我们希望显示单词“Male”或“Female”而不是单个字符,我们可以使用这个 Thymeleaf 代码来做到这一点:
<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 提供表单操作 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>
在上面的代码中,/saveStudent是表单操作 URL,*student *是保存提交的表单数据的对象。 StudentController类处理表单提交:
@Controller
public class StudentController {
@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
public String saveStudent(@ModelAttribute Student student, BindingResult errors, Model model) {
// logic to process input data
}
}
@RequestMapping注解将控制器方法映射到表单中提供的 URL。带注释的方法saveStudent()对提交的表单执行所需的处理。最后,@ModelAttribute注释将表单字段绑定到*student *对象。
8. 显示验证错误
我们可以使用*#fields.hasErrors()函数来检查一个字段是否有任何验证错误。我们使用#fields.errors()*函数来显示特定字段的错误。字段名称是这两个函数的输入参数。
让我们看一下用于迭代并显示表单中每个字段的错误的 HTML 代码:
<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 中显示全局错误。 这是显示全局错误的 HTML 代码:
<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 中的该类型字段配置的conversionService 。 让我们看看如何格式化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 *:
<tr th:each="student: ${students}">
<td th:text="${#conversions.convert(student.percentage, 'Integer')}" />
</tr>