1. Обзор
В этом руководстве мы покажем, как использовать фрагменты Thymeleaf для повторного использования некоторых общих частей сайта . После настройки очень простого проекта Spring MVC мы сосредоточимся на представлениях.
Если вы новичок в Thymeleaf, вы можете ознакомиться с другими статьями на этом сайте, такими как это введение , а также эта о версии движка 3.0.
2. Зависимости Maven
Нам понадобится пара зависимостей, чтобы включить Thymeleaf:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
Последнюю версию тимелеафа и тимелеаф-спринг5 можно найти на Maven Central.
3. Весенний проект
3.1. Весенняя конфигурация MVC
Чтобы включить Thymeleaf и установить суффикс шаблона, нам нужно настроить MVC с преобразователем представления и преобразователем шаблона .
Мы также установим каталог для некоторых статических ресурсов:
@Bean
public ViewResolver htmlViewResolver() {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(templateEngine(htmlTemplateResolver()));
resolver.setContentType("text/html");
resolver.setCharacterEncoding("UTF-8");
resolver.setViewNames(ArrayUtil.array("*.html"));
return resolver;
}
private ITemplateResolver htmlTemplateResolver() {
SpringResourceTemplateResolver resolver
= new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/views/");
resolver.setCacheable(false);
resolver.setTemplateMode(TemplateMode.HTML);
return resolver;
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**", "/css/**")
.addResourceLocations("/WEB-INF/resources/", "/WEB-INF/css/");
}
Обратите внимание, что если мы используем Spring Boot, эта конфигурация может не понадобиться, если только нам не нужно применить наши собственные настройки.
3.2. Контроллер
В этом случае контроллер — это просто средство для представления. Каждое представление показывает другой сценарий использования фрагмента.
Последний загружает некоторые данные, которые передаются через модель для отображения в представлении:
@Controller
public class FragmentsController {
@GetMapping("/fragments")
public String getHome() {
return "fragments.html";
}
@GetMapping("/markup")
public String markupPage() {
return "markup.html";
}
@GetMapping("/params")
public String paramsPage() {
return "params.html";
}
@GetMapping("/other")
public String otherPage(Model model) {
model.addAttribute("data", StudentUtils.buildStudents());
return "other.html";
}
}
Обратите внимание, что имена представлений должны содержать суффикс «.html»
из-за того, как мы настроили наш преобразователь. Мы также будем указывать суффикс при обращении к именам фрагментов.
4. Виды
4.1. Простое включение фрагмента
Прежде всего, мы будем использовать повторное использование общих частей на наших страницах.
Мы можем определить эти части как фрагменты либо в изолированных файлах, либо на общей странице. В этом проекте эти повторно используемые части определены в папке с именем фрагменты
.
Существует три основных способа включения контента из фрагмента:
insert —
вставляет содержимое внутри тегаreplace —
заменяет текущий тег на тег, определяющий фрагментinclude —
это устарело, но все еще может появляться в устаревшем коде.
В следующем примере, fragments.html,
показано использование всех трех способов. Этот шаблон Thymeleaf добавляет фрагменты в заголовок и тело документа:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleaf Fragments: home</title>
<!--/*/ <th:block th:include="fragments/general.html :: headerfiles">
</th:block> /*/-->
</head>
<body>
<header th:insert="fragments/general.html :: header"> </header>
<p>Go to the next page to see fragments in action</p>
<div th:replace="fragments/general.html :: footer"></div>
</body>
</html>
Теперь давайте взглянем на страницу, содержащую некоторые фрагменты. Он называется general.html
и представляет собой целую страницу с некоторыми частями, определенными как фрагменты, готовые к использованию:
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:fragment="headerfiles">
<meta charset="UTF-8" />
<link th:href="@{/css/styles.css}" rel="stylesheet">
</head>
<body>
<div th:fragment="header">
<h1>Thymeleaf Fragments sample</h1>
</div>
<p>Go to the next page to see fragments in action</p>
<aside>
<div>This is a sidebar</div>
</aside>
<div class="another">This is another sidebar</div>
<footer th:fragment="footer">
<a th:href="@{/fragments}">Fragments Index</a> |
<a th:href="@{/markup}">Markup inclussion</a> |
<a th:href="@{/params}">Fragment params</a> |
<a th:href="@{/other}">Other</a>
</footer>
</body>
</html>
Раздел <head>
содержит только таблицу стилей, но мы могли бы применить другие инструменты, такие как Bootstrap, jQuery или Foundation, либо напрямую, либо с помощью Webjars.
Обратите внимание, что все многоразовые теги этого шаблона имеют атрибут th:fragment
, но далее мы увидим, как включить любую другую часть страницы.
После рендеринга и включения фрагментов возвращаемый контент:
<!DOCTYPE HTML>
<html>
<head>
<title>Thymeleaf Fragments: home</title>
<meta charset="UTF-8" />
<link href="/spring-thymeleaf/css/styles.css" rel="stylesheet">
</head>
<body>
<header>
<div>
<h1>Thymeleaf Fragments sample</h1>
</div>
</header>
<p>Go to the next page to see fragments in action</p>
<footer>
<a href="/spring-thymeleaf/fragments">Fragments Index</a> |
<a href="/spring-thymeleaf/markup">Markup inclussion</a> |
<a href="/spring-thymeleaf/params">Fragment params</a> |
<a href="/spring-thymeleaf/other">Other</a>
</footer>
</body>
</html>
4.2. Селекторы разметки для фрагментов
Одна из замечательных особенностей фрагментов Thymeleaf заключается в том, что мы также можем захватить любую часть шаблона, просто используя простые селекторы , классы, идентификаторы или просто теги.
Эта страница, например, включает в себя некоторые компоненты из файла general.html : блок
aside
и блок div.another
:
<body>
<header th:insert="fragments/general.html :: header"> </header>
<div th:replace="fragments/general.html :: aside"></div>
<div th:replace="fragments/general.html :: div.another"></div>
<div th:replace="fragments/general.html :: footer"></div>
</body>
4.3. Параметризованные фрагменты
Мы можем передавать параметры ** ** фрагменту, чтобы изменить какую-то его часть. Для этого фрагмент должен быть определен как вызов функции, где мы должны объявить список параметров.
В этом примере мы определяем фрагмент для общего поля формы:
<div th:fragment="formField (field, value, size)">
<div>
<label th:for="${#strings.toLowerCase(field)}"> <span
th:text="${field}">Field</span>
</label>
</div>
<div>
<input type="text" th:id="${#strings.toLowerCase(field)}"
th:name="${#strings.toLowerCase(field)}" th:value="${value}"
th:size="${size}">
</div>
</div>
А вот простое использование этого фрагмента, где мы передаем ему параметры:
<body>
<header th:insert="fragments/general.html :: header"> </header>
<div th:replace="fragments/forms.html
:: formField(field='Name', value='John Doe',size='40')">
</div>
<div th:replace="fragments/general.html :: footer"></div>
</body>
И вот как будет выглядеть возвращаемое поле:
<div>
<div>
<label for="name"> <span>Name</span>
</label>
</div>
<div>
<input type="text" id="name"
name="name" value="John Doe"
size="40">
</div>
</div>
4.4. Выражения включения фрагментов
Фрагменты Thymeleaf предлагают другие интересные возможности, такие как поддержка условных выражений для определения необходимости включения фрагмента .
Используя оператор Elvis
с любым из выражений, предоставляемых Thymeleaf (например, безопасность, строки и коллекции), мы можем загружать разные фрагменты.
Например, мы можем определить этот фрагмент с некоторым содержимым, которое мы будем показывать в зависимости от заданного условия. Это может быть файл, содержащий различные типы блоков:
<div th:fragment="dataPresent">Data received</div>
<div th:fragment="noData">No data</div>
И вот как мы могли бы загрузить их выражением:
<div
th:replace="${#lists.size(data) > 0} ?
~{fragments/menus.html :: dataPresent} :
~{fragments/menus.html :: noData}">
</div>
Чтобы узнать больше о выражениях Thymeleaf, ознакомьтесь с нашей статьей здесь .
4.5. Гибкие макеты
В следующем примере также показаны два других интересных использования фрагментов для отображения таблицы с данными . Это многократно используемый фрагмент таблицы с двумя важными частями: заголовком таблицы, который можно изменить, и телом, в котором отображаются данные:
<table>
<thead th:fragment="fields(theadFields)">
<tr th:replace="${theadFields}">
</tr>
</thead>
<tbody th:fragment="tableBody(tableData)">
<tr th:each="row: ${tableData}">
<td th:text="${row.id}">0</td>
<td th:text="${row.name}">Name</td>
</tr>
</tbody>
<tfoot>
</tfoot>
</table>
Когда мы хотим использовать эту таблицу, мы можем передать заголовок нашей таблицы с помощью функции fields
. На заголовок ссылается класс myFields
. Тело таблицы загружается путем передачи данных в качестве параметра функции tableBody
:
<body>
<header th:replace="fragments/general.html :: header"> </header>
<table>
<thead th:replace="fragments/tables.html
:: fields(~{ :: .myFields})">
<tr class="myFields">
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<div th:replace="fragments/tables.html
:: tableBody(tableData=${data})">
</div>
</table>
<div th:replace="fragments/general.html :: footer"></div>
</body>
А вот так будет выглядеть конечная страница:
<body>
<div>
<h1>Thymeleaf Fragments sample</h1>
</div>
<div>Data received</div>
<table>
<thead>
<tr class="myFields">
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>1001</td>
<td>John Smith</td>
</tr>
<tr>
<td>1002</td>
<td>Jane Williams</td>
</tr>
</tbody>
</table>
<footer>
<a href="/spring-thymeleaf/fragments">Fragments Index</a> |
<a href="/spring-thymeleaf/markup">Markup inclussion</a> |
<a href="/spring-thymeleaf/params">Fragment params</a> |
<a href="/spring-thymeleaf/other">Other</a>
</footer>
</body>
5. Вывод
В этой статье мы показали, как повторно использовать компоненты представления с помощью Thymeleaf Fragments, мощного инструмента, упрощающего управление шаблонами.
Мы также представили некоторые другие интересные функции, выходящие за рамки основ. Мы должны принять это во внимание при выборе Thymeleaf в качестве нашего механизма рендеринга представлений.
Если вы хотите узнать о других функциях Thymeleaf, вам обязательно стоит взглянуть на нашу статью о диалектах макета .
Как всегда, полный код реализации примера доступен на GitHub .