«1. Введение

В этом уроке мы рассмотрим переменные в Thymeleaf. Мы создадим пример Spring Boot, который будет получать список статей Baeldung и отображать их в HTML-шаблоне Thymeleaf.

2. Зависимости Maven

Для работы с 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. Веб-контроллер ~ ~~ Сначала мы создадим веб-контроллер с конечной точкой GET, который возвращает страницу со списком статей Baeldung.

Метод, аннотированный @GetMapping, будет принимать единственный параметр — Модель. Он содержит все глобальные переменные, которые можно в дальнейшем использовать внутри шаблона Thymeleaf. В нашем случае у модели будет всего один параметр — список статей.

Класс Article будет состоять из двух строковых полей, имени и URL-адреса:

Возвращаемым значением метода нашего контроллера должно быть имя желаемого шаблона Thymeleaf. Это имя должно соответствовать файлу HTML, расположенному в каталоге src/resource/template. В нашем случае это будет src/resource/template/articles-list.html.

public class Article {
    private String name;
    private String url;

    // constructor, getters and setters
}

Давайте взглянем на наш контроллер Spring:

После запуска приложения страница статей будет доступна по адресу http://localhost:8080/articles.

@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(
            "Introduction to Using Thymeleaf in Spring",
            "https://www.baeldung.com/thymeleaf-in-spring-mvc"
          ),
          // a few other articles
        );
    }
}

4. Шаблон Thymeleaf

Теперь давайте перейдем к HTML-шаблону Thymeleaf. Он должен иметь стандартную структуру HTML-документа только с дополнительным определением пространства имен Thymeleaf:

Мы будем использовать его в качестве шаблона в дальнейших примерах, где мы будем заменять только содержимое тега \u003cmain\u003e:

<html xmlns:th="http://www.thymeleaf.org">

5. Определение переменных

<!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>

Есть два способа определить переменную в шаблоне Thymeleaf. Первый вариант — взять один элемент при переборе массива:

В результате мы получим \u003cdiv\u003e с несколькими элементами \u003ca\u003e, соответствующими количеству статей в переменной article.

<div th:each="article : ${articles}">
    <a th:text="${article.name}" th:href="${article.url}"></a>
</div>

Другой способ — определить новую переменную на основе другой. Например, мы можем взять первый элемент массива статей:

Или мы можем создать новую переменную, содержащую только название статьи:

<div th:with="firstArticle=${articles[0]}">
    <a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>

В приведенном выше примере ${article. name} и ${articleName} фрагменты являются заменяемыми.

<div th:each="article : ${articles}", th:with="articleName=${article.name}">
    <a th:text="${articleName}" th:href="${article.url}"></a>
</div>

Также можно определить несколько переменных. Например, мы можем создать две отдельные переменные для хранения названия статьи и URL-адреса:

6. Область действия переменных

<div th:each="article : ${articles}" th:with="articleName=${article.name}, articleUrl=${article.url}">
    <a th:text="${articleName}" th:href="${articleUrl}"></a>
</div>

Переменные, передаваемые в модель в контроллере, имеют глобальную область действия. Это означает, что их можно использовать в любом месте наших HTML-шаблонов.

С другой стороны, переменные, определенные в шаблоне HTML, имеют локальную область видимости. Их можно использовать только в пределах диапазона элемента, в котором они были определены.

Например, приведенный ниже код корректен, так как элемент \u003ca\u003e находится внутри firstDiv:

С другой стороны, когда мы пытаемся использовать firstArticle в другом div:

<div id="firstDiv" th:with="firstArticle=${articles[0]}">
    <a th:text="${firstArticle.name}" th:href="${firstArticle.url}"></a>
</div>

Мы получим исключение во время компиляции, говорящее, что firstArticle имеет значение null:

<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>

Это потому, что элемент \u003ch2\u003e пытается использовать переменную, определенную в firstDiv, которая выходит за рамки.

org.springframework.expression.spel.SpelEvaluationException: EL1007E: Property or field 'name' cannot be found on null

Если нам по-прежнему нужно использовать переменную firstArticle внутри secondDiv, нам нужно снова определить ее во secondDiv или обернуть эти два тега div в общий элемент и определить в нем firstArticle.

7. Изменение значения переменной

Также можно перезаписать значение переменной в заданной области:

В приведенном выше примере мы переопределили переменную article так, чтобы она содержала только два первых элемента.

<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>

Обратите внимание, что за пределами mainDiv исходное значение переменной article будет передано в контроллер.

8. Заключение

В этом уроке мы узнали, как определять и использовать переменные в Thymeleaf. Как всегда, весь исходный код доступен на GitHub.

«