1、简介 {#1简介}
本文将通过一个 Spring Boot 示例带你了解 Thymeleaf 中的变量。
2、Maven 依赖 {#2maven-依赖}
要使用 Thymeleaf,需要添加 spring-boot-starter-thymeleaf
和 spring-boot-starter-web
依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
3、Web Controller {#3web-controller}
首先,创建一个带有 GET 端点的 Web Controller,该端点返回一个包含文章列表的页面。
@GetMapping
方法只接受一个参数 - Model
。它包含所有可在 Thymeleaf
模板中使用的全局变量。在本例中,Model 只有一个参数,即文章列表。
Article
类由两个 String
字段(name
和 url
)组成:
public class Article {
private String name;
private String url;
// 构造函数、get、set 方法省略
}
Controller 方法的返回值应该是要渲染的 Thymeleaf
模板的名称。该名称应与 src/resource/template
目录中的 HTML 文件相对应。在本例中,就是 src/resource/template/articles-list.html
。
Controller 如下:
@Controller
@RequestMapping("/api/articles")
public class ArticlesController {
@GetMapping
public String allArticles(Model model) {
model.addAttribute("articles", fetchArticles());
return "articles-list";
}
private List<Article> fetchArticles() {
return Arrays.asList(
new Article(
"Spring Boot 中文文档",
"https://springdoc.cn/spring-boot/"
),
// 其他一些文章
);
}
}
运行应用后,访问 http://localhost:8080/articles
以查看文章页面。
4、Thymeleaf 模板 {#4thymeleaf-模板}
它具有标准的 HTML 文档结构,只是多了 Thymeleaf 命名空间定义:
<html xmlns:th="http://www.thymeleaf.org">
在后续的示例中,我们将以此为模板,只替换 <main>
标签的内容:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleaf Variables</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<main>
...
</main>
</body>
</html>
5、定义变量 {#5定义变量}
在 Thymeleaf 模板中定义变量有两种方法。第一种方法是在遍历数组时使用单个元素:
<div th:each="article : ${articles}">
<a th:text="${article.name}" th:href="${article.url}"></a>
</div>
渲染结果是一个 <div>
,其中包含多个 <a>
元素,与 articles
变量中的文章数量相对应。
另一种方法是根据另一个变量定义一个新变量。例如,可以取 articles
数组的第一个元素:
<div th:with="firstArticle=${articles[0]}">
<a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>
或者,也可以创建一个新变量,只保存文章的名称:
<div th:each="article : ${articles}", th:with="articleName=${article.name}">
<a th:text="${articleName}" th:href="${article.url}"></a>
</div>
在上例中,${article.name}
和 ${articleName}
渲染结果一样。
还可以定义多个变量。例如,可以创建两个单独的变量来保存文章名称和 URL:
<div th:each="article : ${articles}" th:with="articleName=${article.name}, articleUrl=${article.url}">
<a th:text="${articleName}" th:href="${articleUrl}"></a>
</div>
6、变量范围 {#6变量范围}
Controller 中传递给 Model 的变量具有全局范围(Global Scope)。这意味着它们可以在 HTML 模板的任何地方使用。
而在 HTML 模板中定义的变量具有局部范围。它们只能在其定义的元素范围内使用。
例如,下面的代码是正确的,因为 <a>
元素位于 firstDiv
中:
<div id="firstDiv" th:with="firstArticle=${articles[0]}">
<a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>
而,尝试在另一个 div
中使用 firstArticle
时:
<div id="firstDiv" th:with="firstArticle=${articles[0]}">
<a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>
<div id="secondDiv">
<h2 th:text="${firstArticle.name}"></h2>
</div>
这会在模板编译时抛出异常,提示 firstArticle
为 null
:
org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null
这是因为 <h2>
元素试图使用在 firstDiv
中定义的变量,而该变量已超出范围
如果仍然需要在 secondDiv
中使用 firstArticle
变量,就需要在 secondDiv
中再次定义它,或者将这两个 div
标签包在一个共同的元素中,并在其中定义 firstArticle
。
7、修改变量值 {#7修改变量值}
也可以在给定的作用域中覆盖变量的值:
<div id="mainDiv" th:with="articles = ${ { articles[0], articles[1] } }">
<div th:each="article : ${articles}">
<a th:text="${article.name}" th:href="${article.url}"></a>
</div>
</div>
如上,重新定义了 articles
变量,使其只有前 2 个元素。
注意,在 mainDiv
之外,articles
变量仍将保留其在 Controller 中传递的原始值。
8、总结 {#8总结}
本文介绍了如何在 Thymeleaf 中定义和使用变量,还介绍了变量的范围以及如何修改变量。
Ref:https://www.baeldung.com/thymeleaf-variables