betacode

Использование Fragments в Thymeleaf

  1. Что такое Fragment?
  2. th:insert, th:replace, th:include
  3. Fragment с параметрами
  4. th:assert

1. Что такое Fragment?

Один Fragment (Фрагмент) это часть в Template. Thymeleaf позволяет вам импортировать fragment у данного Template в другой Template. Имеются много способов определения одного Fragment. Например:
  • Выбрать все теги (tag) с атрибутом (attribute) th:fragment="search-fragment".
  • Выбрать тег по ID.
  • Выбрать все таги по Css-class.
  • ....
Главное, когда вы хотите импортировать Fragment у определенного Template, вам нужно описать его расположение.
Синтаксис описания расположения Fragment определенного Template:
~{/path-to-template/template-name :: selector}
Если вы хотите описать расположение Fragment определенного текущего Template, то можете использовать более краткий синтаксис:
~{:: selector}

~{this :: selector}
~{templatename: fragmentname} (th:fragment)
Выбрать fragment по названию.
~{templatename: tagname} (Tag Name)
Выбрать fragment по названию тега.
Выбрать подтеги тега. Например, выбрать все теги <script> расположенные в теге <header>:
~{templatename: #id} (ID)
Выбрать fragment по значению атрибута (attribute) ID тега.
~{templatename: .classname},~{templatename: tagname.classname} (Css Class)
Выбрать fragment по Css Class:
~{templatename} (Everything)
Выбрать все в Template:
Other...
Другие примеры:
~{fragments/my-template :: #tagId/text() }

~{fragments/my-template :: fragmentName/text() }

~{fragments/my-template :: tagName/text() }

2. th:insert, th:replace, th:include

Данное свойство позволяет импортировать fragment из одного Template в другой Template действительно отлично, он помогает делать дизайн интерфейса вебсайта легче. Посмотрим пример ниже:
В данном примере, файл my-template.html содержит многие fragment, где другие Template могут импортировать для использования.
/fragments/my-template.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>My Template</title>
    <link rel="stylesheet" type="text/css" th:href="@{/main.css}"/>
    <link rel="stylesheet" type="text/css" th:href="@{/secondary.css}"/>
    <script type="text/javascript" th:src="@{/main.js}"></script>
    <script type="text/javascript" th:src="@{/secondary.js}"></script>
</head>
<body>
    <!-- Script in body -->
    <script type="text/javascript" th:src="@{/script-in-body.js}"></script>
    <ul th:fragment="my-fragment1">
        <li><a th:href="@{/}">Home</a></li>
        <li><a th:href="@{/products}">Products</a></li>
        <li><a th:href="@{/about}">About</a></li>
    </ul>
    <ul th:fragment="my-fragment2">
        <li><a th:href="@{/admin/products}">Product Management</a></li>
        <li><a th:href="@{/admin/orders}">Order Management</a></li>
    </ul>
    <div id = "my-id1">
         Element DIV with id = 'my-id1'
    </div>
    <aside>
        <div>This is a sidebar</div>
    </aside>
    <p class="my-class">Element P with class (my-class)</p>
    <p>Element P without class</p>
    <p class="my-class">Element P with class (my-class)</p>
</body>
</html>
Файл my-page.html является Template, он импортирует некоторые fragment у my-template.html:
my-page.html (Template)
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8" />
<title th:replace = "~{fragments/my-template :: title}">Title</title>
<th:block th:insert="~{fragments/my-template :: link}"></th:block>
<th:block th:insert="~{fragments/my-template :: head/script}"></th:block>
</head>
<body>
   <h1>My Page</h1>
   <p>Some Content of My Page</p>
   <div th:insert="~{fragments/my-template :: my-fragment1}"></div>
   <div th:insert="~{fragments/my-template :: my-fragment2}"></div>
   <div th:insert="~{fragments/my-template :: #my-id1}"></div>
   <div th:insert="~{fragments/my-template :: p.my-class }"></div>
</body>
</html>
Результат, который вы получаете:
(HTML Result)
<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8" />
    <title>My Template</title>
    <link rel="stylesheet" type="text/css" href="/main.css" />
    <link rel="stylesheet" type="text/css" href="/secondary.css" />
    <script type="text/javascript" src="/main.js"></script>
    <script type="text/javascript" src="/secondary.js"></script>
</head>
<body>
    <h1>My Page</h1>
    <p>Some Content of My Page</p>
    <div>
        <ul>
            <li><a href="/">Home</a></li>
            <li><a href="/products">Products</a></li>
            <li><a href="/about">About</a></li>
        </ul>
    </div>
    <div>
        <ul>
            <li><a href="/admin/products">Product Management</a></li>
            <li><a href="/admin/orders">Order Management</a></li>
        </ul>
    </div>
    <div>
        <div id="my-id1">
            Element DIV with id = 'my-id1'
        </div>
    </div>
    <div>
        <p class="my-class">Element P with class (my-class)</p>
        <p class="my-class">Element P with class (my-class)</p>
    </div>
</body>
</html>
th:insert, th:replace, th:include
  • th:insert вставит Fragment становится подтегом целевого тега (Target tag).
  • th:replace заменит целевой тег с помощью Fragment.
  • th:include вставит дочерний Fragment становит дочерним целевым тегом.
Примечание: Атрибут(attribute) th:include используется в Thymeleaf 2, и не используется больше в версииThymeleaf 3.
/path/mytemplate.html (Fragments)
<footer th:fragment="copyright">
  &copy; o7planning.org
</footer>
Target Template:
(Target Template)
<body>
  ...
  <!-- th:insert -->
  <div th:insert="~{/path/mytemplate :: copyright}"></div>
  <!-- th:replace -->
  <div th:replace="~{/path/mytemplate :: copyright}"></div>
  <!-- th:include -->
  <div th:include ="~{/path/mytemplate :: copyright}"></div>
</body>
Результат:
(HTML Result)
<body>
  ...
  <!-- th:insert -->
  <div>
    <footer>
      &copy; o7planning.org
    </footer>
  </div>
  <!-- th:replace -->
  <footer>
    &copy; o7planning.org
  </footer>
  <!-- th:include -->
  <div>
    &copy; o7planning.org
  </div>
</body>

3. Fragment с параметрами

Один fragment больше похож на функцию (function) если он имеет параметры, и удачно, что Thymeleaf это поддерживает.
Явный параметр:
Если вы объявите fragment и перечислите явным способом его параметры. Данные параметры будут обязательными параметрами. Как в примере ниже:
<div th:fragment="person (firstName, lastName)" class="box">
    <p>First Name: <span th:utext="${firstName}"></span></p>
    <p>Last Name: <span th:utext="${lastName}"></span></p>
    <p>Full Name: <span th:utext="${firstName} + ' '+ ${lastName}"></span></p>
</div>
Передача параметров, когда вы вызываете fragment:
<div th:replace="~{fragments/my-template2 :: person('Donald', 'Trump') }"></div>
    
<div th:replace="~{fragments/my-template2 :: person( firstName='Donald', lastName= 'Trump') }"></div>

<div th:replace="~{fragments/my-template2 :: person( ${u.firstName}, ${u.lastName}) }"></div>

<div th:replace="~{fragments/my-template2 :: person( firstName=${u.firstName}, lastName= ${u.lastName}) }"></div>
Неявный параметр
Вы можете создать fragment с неявными параметрами, они являются необязательными параметрами, как в следующем примере:
<!-- Fragment with implicit parameters. -->
<div th:fragment="greeting" class="box">
    <p>Hello
       <span th:utext="${title}"></span>
       <span th:utext="${name} ?: 'There'"></span>
    </p>
</div>
Вызвать fragment с неявными параметрами.
<div th:replace="~{fragments/my-template2 :: greeting(title='Mr.', name = 'Tom') }"></div>    
    
<div th:replace="~{fragments/my-template2 :: greeting }"></div>

4. th:assert

Атрибут (attribute) th:assert помогает вам оценить выражение или много выражений (Выражения отделены запятой). Если выражения оценены как true (верно) нет никаких проблем, если есть 1 выражение оцененное как false (ошибка) выбрасывается исключение.
<div th:fragment="employee (firstName, lastName)" class="box"
     th:assert= "${!#strings.isEmpty(firstName)}, ${!#strings.isEmpty(lastName)}">
    
    <p>First Name: <span th:utext="${firstName}"></span></p>
    <p>Last Name: <span th:utext="${lastName}"></span></p>
    <p>Full Name: <span th:utext="${firstName} + ' '+ ${lastName}"></span></p>
</div>