Движок шаблонов Thymeleaf

В предыдущей статье я упомянул движок Thymeleaf, используемый в проекте для построения HTML-страниц. Я решил написать отдельный пост, посвящённый только Thymeleaf, а не углубляться в описание данной библиотеки в рамках той статьи, так как она получилась и без того достаточно большой.

Thymeleaf является хорошей заменой JSP и использует в качестве шаблонов валидные файлы XHTML и XML. Для использования Thymeleaf в шаблоне должно быть подключено пространство имён http://www.thymeleaf.org. Для HTML это будет выглядеть следующим образом:

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

Подстановка значений в шаблон

Самый элементарный пример подстановки значения в шаблон:

В данном случае вместо Hello! в шаблон будет подставлено значение переменной greeting. Обратите внимание, что Thymeleaf подставляет значения только в атрибуты из собственного пространства имён, при этом существующее значение атрибута будет заменено значением, полученным от Thymeleaf. Таким образом шаблон

будет преобразован в

Подстановка значений в строку

Кроме подстановки значений в атрибуты есть возможность подставлять значения прямо в текст при помощи двух пар квадратных скобок: [[…]]. Единственное условие — в одном из родительских элементов нужно указать атрибут th:inline, который в качестве значения может принимать textjavascript и none. Например:

Выражения

Thymeleaf предоставляет несколько вариантов выражений для различных ситуаций:

  • ${…} — выражение, вставляющее в шаблон результат выполнения операции внутри фигурных скобок. Проще говоря, это стандартное OGNL-выражение. Данный тип выражений является наиболее часто используемым.
  • *{…} — выражение выделения/выбора. Данный тип выражения позволяет уменьшить количество кода шаблона, предоставляя доступ к свойствам выбранного объекта. Допустим, у нас есть следующий Java-класс:

    Мы можем вывести свойства объекта следующим образом:

    вместо

    Данный способ очень удобен при работе с большим количеством свойств.
  • #{…} — выражение интернационализации. Thymeleaf подставляет вместо переданного аргумента соответствующее сообщение из файла локализации.Внутри фигурных скобок допускаются дополнительные операции, а также есть возможность передачи аргументов. Допустим, у нас есть следующий файл локализации:

    в контексте объявлены переменные prefix=prefixed. и name=Mate и шаблон

    В результате будет получен следующий HTML-код:
  • @{…} — ссылочные выражения. При помощи данного типа выражений можно создавать ссылки, которые можно использовать в тегах a, img, script, form и других. Примеры использования:

    Данные ссылки будут преобразованы в:

    Ссылки будут строиться относительно контекстного пути нашего приложения. Ссылки можно генерировать относительно контекстного пути приложения (@{../some/path}), относительно корня сервера (@{~/some/path}) или относительно протокола (@{//example.com}).
  • ~{…} — фрагментарные выражения, с помощью которых можно вставлять директивами th:insert и th:replace отдельные части шаблнонов. Например, вставка в шаблон навигации из другого шаблона:

Итеративный обход данных

Как и в любой другой библиотеке для работы с шаблонами, в Thymeleaf есть возможность интеративного обхода набора данных. Допустим, у нас есть переменная persons, которая является коллекцией. Мы можем обойти её следующим образом:

В качестве набора данных могут выступать реализации java.util.Iterable, java.util.Map, массивы, а также любые объекты, но в последнем случае набор будет состоять из одного элемента.

В левой части выражения может быть объявлена ещё одна переменная, через которую можно будет получить доступ к свойствам итерации:

Данная переменная имеет следующие свойства:

  • index — счётчик итерации, начинающийся с 0
  • count — счётчик итерации, начинающийся с 1
  • size — общее количество элементов в коллекции
  • current — свойства текущей итерации
  • even/odd — свойства, с помощью которых можно проверить чётность итерации
  • first/last — свойства, с помощью которых можно проверить, что текущий элемент — первый или последний элемент коллекции

Условные операторы

Thymeleaf предоставляет два условных оператора, применимых в шаблонах.

Первый оператор — if и его инвертированный аналог —  unless. Пример использования данных операторов:

Второй оператор — switch/case. Пример использования:

Полезные ссылки

  • Ozio

    Я правильно понял, что это более шустрый аналог jsp и он тоже обрабатывается на стороне сервера? Есть ли смысл использовать его для создания простого интернет магазина, или лучше учить javascript?

    • pvtjoke

      Да, это аналог JSP с обработкой на стороне сервера. Насчёт «более шустрый» — не факт, т.к. при кэшировании разницы почти нет. В целом Thymeleaf и другие движки имеют большие возможности и развиваются активнее JSP.
      Для проектов, которым важна индексация в поисковых системах и SEO, удобнее использовать движки, генерирующие страницы на стороне сервера, например тот же Thymeleaf.

      • Ozio

        То что удобно с этим не поспоришь, но сам сервер-то себя как будет чувствовать, если к примеру на сайт зайдут одновременно 100 пользователей? На сколько упадёт скорость обработки запросов и т.д, если учитывать, что VPS будет самим дешёвым?

        • pvtjoke

          Вполне себе спокойно сервер будет себя чувствовать, так как в реальных условиях используется кэширование шаблонов.

  • Ozio

    Не выходит переделать свой Spring boot 1.3.2.RELEASE проект с jsp на Thymeleaf. Для работы добавление одной строки в html файл не достаточно. Я так понял нужны dependencies и правки в бине:
    public UrlBasedViewResolver setupViewResolver() {
    UrlBasedViewResolver resolver = new UrlBasedViewResolver();
    resolver.setPrefix(«/WEB-INF/pages/»);
    resolver.setSuffix(«.jsp»);
    resolver.setViewClass(JstlView.class);

    return resolver;
    }
    Целый день ищу подходящий мне мануал. Ни один из них у меня почему-то не работает.

    • pvtjoke

      1. Нужна зависимость spring-boot-starter-thymeleaf
      2. Бин можно убрать, т.к. он будет автоматически сконфигурирован. Шаблоны будут находиться в src/main/resources/templates. Настройки Thymeleaf можно посмотреть здесь: https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
      3. Если есть необходимость в самостоятельной конфигурации (что маловероятно), то нужно использовать не UrlBasedViewResolver, а ThymeleafViewResolver

      • Ozio

        Спасибо! Уже сам разобрался. Это было довольно не легко для такого нуба, как я. Жаль, что так поздно сюда заглянул. Это бы облегчило мои страдания. 🙂

        • Старая модель нежити

          Поведайте в чем была проблема пожалуйста. Сам уже десяток часов убил на это дело.

          • Ozio

            Проблема в том, что много мануалов о Spring и Thymeleaf. А нужно было искать именно про Springboot и Thymeleaf. Что для меня было не совсем очевидно. Далее я пытался переделать уже имеющийся appconfig с кучей бинов для jsp, а достаточно было конфигурационный класс тупо удалить и добавить две зависимости в pom файл и всё заработало. Уважаемый pvtjoke об этом уже сказал выше. Но я всё таки создал конфигурационный классы чтобы поменять местонахождение шаблонов на «/WEB-INF/templates/» и выключить кеширование, для удобного тестирования. Если есть ещё вопросы, задавайте.

          • Старая модель нежити

            У меня сервер просто не хочет переводить шаблоны. Скачал готовый новый проект на springboot с зависимостью thymeleaf, но при запуске все равно просто отправляет шаблон как html файл.
            Зависимость starter-thymeleaf есть

          • Ozio

            Дайте ссылку на этот проэкт.

          • Старая модель нежити

            github.com/qzark1/beyronk

            там все по гайду с spring-projects.ru/guides/handling-form-submission/

          • pvtjoke

            попробуй удалить из pom.xml mustache

          • Старая модель нежити

            Помогло. Премного благодарен вам.

  • Alex

    Добрый день! Спасибо за статью! А можете подсказать, как с помощью Thymeleaf работать с полями checkbox, в часности с множественным выбором. Как передать значения в контроллер?

    • Alex

      Разобрался 🙂