Диалект Layout — это диалект Thymeleaf, который позволяет пользователям создавать макеты и шаблоны для повторного использования HTML кода. Он имеет иерархический подход и использует шаблон декоратора для «декорирования» файлов макета. Layout Dialect является отдельным проектом и не поставляется с Thymeleaf. Тем не менее, это открытый исходный код, доступный на GitHub, он хорошо документирован и, как кажется, также поддерживается в хорошем состоянии.

Установка


Нам нужно будет добавить стартовый пакет Thymeleaf к вашему Spring Boot pom:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>

Однако, начиная с Spring Boot 2, этого уже недостаточно. Pom диалекта не является частью Spring Boot, и мы должны добавить его самостоятельно:

    <dependency>
        <groupId>nz.net.ultraq.thymeleaf</groupId>
        <artifactId>thymeleaf-layout-dialect</artifactId>
        <version>2.3.0</version>
    </dependency>

В примерах кода также используется Bootstrap, поэтому необходимо также добавить веб-файлы:

    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>bootstrap</artifactId>
        <version>4.0.0</version>
    </dependency>

В качестве последнего шага нам нужно создать bean-компонент LayoutDialect в аннотированном классе @Configuration.

    @Bean
    public LayoutDialect layoutDialect() {
        return new LayoutDialect();
    }

Пошли далее.

Layout Dialect пример


Этот пример покажет, как мы можем использовать Layout Dialect, чтобы определить макеты для наших страниц, чтобы мы могли лучше использовать код повторно: с помощью страницы index.html, которая использует layout.html в качестве макета. Имя Layout.html — произвольное и может быть любым. Там добавлено еще несколько файлов, но они только для демонстрации.



На картинке структура папки ресурсов. Spring Boot автоматически найдет все шаблоны Thymeleaf в каталоге resources/templates.

Layout.html



    <!DOCTYPE html>
    <html>
        <head>
            <title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Igorski.co</title>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
            <link th:href="@{/webjars/bootstrap/4.0.0/css/bootstrap.min.css}" rel="stylesheet" media="screen" />
        </head>
        <body>
            <div th:replace="fragments/header :: header"> This header content is going to be replaced.</div>
            <div class="container">
                <div class="row">
                    <div class="col-2" layout:fragment="sidebar">
                        <h1>This is the layout's sidebar</h1>
                        <p>This content will be replaced if the page
                        using the layout also defines a layout:fragment="sidebar" segment.</p>
                    </div>
                    <div class="col" layout:fragment="content">
                        <h1>This is the Layout's main section</h1>
                        <p>This content will be replaced if the page
                            using the layout also defines a layout:fragment="content" segment. </p>
                    </div>
                </div>
            </div>
            <footer th:insert="fragments/footer :: footer" class="footer">
                This content will remain, but other content will be inserted after it.
            </footer>
        </body>
    </html>

В layout.html используются два из пяти процессоров, представленных в Layout Dialect. Во-первых, это макет: процессор шаблонов заголовков. Процессор шаблона заголовка помогает пользователю определить лучший заголовок для получающейся страницы. В этом примере он определяет окончательный заголовок как комбинацию заголовка страницы и заголовка макета. Для этого используются два специальных токена, представленных в Layout Dialect, $LAYOUT_TITLE и $CONTENT_TITLE.

Наибольшее значение в layout.html имеют два заполнителя (или фрагмента), определенных макетом: процессор фрагмента. Этот процессор позволяет нам определять заполнители контента в наших макетах. Содержимое этих заполнителей будет позже заменено содержимым страниц, использующих макет. В примере определены два разных фрагмента, один для боковой панели, а другой для основного контента. Мы, однако, можем иметь столько фрагментов, сколько пожелаем, при условии, что все они имеют разные имена.

Index.html


    <!DOCTYPE html>
    <html xmlns:layout="http://www.w3.org/1999/xhtml" layout:decorate="~{layouts/layout}">
        <head>
            <title>Home Page</title>
            <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
            <link th:href="@{/css/core.css}" rel="stylesheet" media="screen" />
        </head>
        <body>
            <div class="container">
                <div class="row">
                    <div class="col-2" layout:fragment="sidebar">
                        <h1>Sidebar</h1>
                        <a href="#">Login</a>
                    </div>
                    <div class="col" layout:fragment="content">
                        <h1>Welcome to the Index page</h1>
                        <br>This content is replacing the content of the layout:fragment="content"<br>
                        placeholder in layout.html</p>
                    </div>
                </div>
            </div>
        </body>
    </html>

Мы заявляем, что index.html использует layout.html в качестве своего макета с процессором layout: decorate. Сделав это, мы объявляем, что index.html будет использовать шаблон layout.html. Здесь самое главное — использование процессора фрагментов. Он указывает содержимое, которое будет использоваться вместо содержимого фрагментов макета с тем же именем. Еще одна вещь, которую стоит упомянуть, это заголовок. На полученной странице index.html, которую мы получим, после обработки заголовок будет представлять собой комбинацию двух заголовков, один из index.html, а другой из макета. Они будут объединены.

Как layout.html, так и index.html можно просматривать в браузере без какой-либо обработки. Но после обработки мы видим, что index.html сильно отличается. Содержимое index.html используется для оформления макета и размещения содержимого внутри макета на основе того, что определяет макет.

В примере присутствуют два других элемента: верхний и нижний колонтитулы. Однако они используют процессоры Thymeleaf Standard Layout th:replace и th:insert. Очень похожи на последние два из пяти процессоров, представленных в Layout Dialect, layout:insert и layout:replace. Они более или менее делают то же самое. В отличие от предыдущих процессоров, которые мы обсуждали, эти два используют не иерархический, а включающий подход. Это больше характерно для типовой формы Thymeleaf.



На картинке окончательный вид страницы. Он имеет как верхний, так и нижний колонтитулы, хотя ни один из них не упоминается в разметке index.html.

Комментарии (2)


  1. gkislin
    03.03.2019 14:12

    Спасибо, не знал раньше про thymeleaf-layout-dialect! Буду внедрять, вещь полезная.
    Хотя опыт с thymleaf есть, понял статью не сразу… Конкретно не скажу, что поправить- но ясности не хватает… Здесь еще паралельно почитал: https://www.baeldung.com/thymeleaf-spring-layouts
    Для автозаполнения полагаю xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" нужно добавить.
    "два из пяти процессоров, представленных в Layout Dialect" — вот это трудности вызвало:)
    как минимум attribute processors. А еще лучше — обработчик тэгов…
    Версию thymeleaf-layout-dialect также не надо указывать- она наследуется из parent.


    1. pilot911 Автор
      03.03.2019 17:22

      спасибо за поправки