HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>В этом уроке мы познакомимся с шаблонизаторами.</p>
1 <p>В этом уроке мы познакомимся с шаблонизаторами.</p>
2 <h2>Зачем нужны шаблонизаторы</h2>
2 <h2>Зачем нужны шаблонизаторы</h2>
3 <p>Javalin и другие подобные фреймворки позволяют создавать полноценные сайты без дополнительных инструментов. Рабочий сайт должен просто возвращать ответ с HTML-кодом, который браузер отобразит как страницу:</p>
3 <p>Javalin и другие подобные фреймворки позволяют создавать полноценные сайты без дополнительных инструментов. Рабочий сайт должен просто возвращать ответ с HTML-кодом, который браузер отобразит как страницу:</p>
4 <p>Здесь мы видим упрощенный пример, в котором мы возвращаем только заголовок H1.</p>
4 <p>Здесь мы видим упрощенный пример, в котором мы возвращаем только заголовок H1.</p>
5 <p>В реальных приложениях возвращаемый HTML состоит из сотен и тысяч строк. Работать с такими объемами стандартным способом очень сложно. Вот лишь некоторые проблемы, с которыми мы столкнемся:</p>
5 <p>В реальных приложениях возвращаемый HTML состоит из сотен и тысяч строк. Работать с такими объемами стандартным способом очень сложно. Вот лишь некоторые проблемы, с которыми мы столкнемся:</p>
6 <ul><li>Такой код сложно формировать, редактировать и поддерживать</li>
6 <ul><li>Такой код сложно формировать, редактировать и поддерживать</li>
7 <li>В таком коде очень легко допустить ошибку и очень сложно ее обнаружить</li>
7 <li>В таком коде очень легко допустить ошибку и очень сложно ее обнаружить</li>
8 <li>В таком коде будут возникать проблемы с одинарными или двойными кавычками, придется их экранировать и постоянно следить за этим</li>
8 <li>В таком коде будут возникать проблемы с одинарными или двойными кавычками, придется их экранировать и постоянно следить за этим</li>
9 </ul><p>Для решения этой проблемы используются<strong>шаблонизаторы</strong>. Это библиотеки, которые позволяют формировать HTML в отдельных файлах с подсветкой и удобной подстановкой данных. Другими словами, мы получаем не HTML внутри кода, а код внутри HTML.</p>
9 </ul><p>Для решения этой проблемы используются<strong>шаблонизаторы</strong>. Это библиотеки, которые позволяют формировать HTML в отдельных файлах с подсветкой и удобной подстановкой данных. Другими словами, мы получаем не HTML внутри кода, а код внутри HTML.</p>
10 <p>В Java-мире есть несколько разных шаблонизаторов. Для этого курса мы выбрали<a>jte</a>(<em>Java Template Engine</em>), потому что он официально поддерживается в Javalin.</p>
10 <p>В Java-мире есть несколько разных шаблонизаторов. Для этого курса мы выбрали<a>jte</a>(<em>Java Template Engine</em>), потому что он официально поддерживается в Javalin.</p>
11 <p>Посмотрим, как выглядит HTML c jte:</p>
11 <p>Посмотрим, как выглядит HTML c jte:</p>
12 <h2>Как начать работать с JTE</h2>
12 <h2>Как начать работать с JTE</h2>
13 <p>Чтобы начать работу с jte, нужно добавить в зависимости две строчки:</p>
13 <p>Чтобы начать работу с jte, нужно добавить в зависимости две строчки:</p>
14 <p>Пакет<em>javalin-rendering</em>добавляет в Javalin поддержку нескольких популярных шаблонизаторов, в том числе jte. В конфигурации приложения нужно указать, что мы хотим использовать jte в качестве шаблонизатора в нашем приложении:</p>
14 <p>Пакет<em>javalin-rendering</em>добавляет в Javalin поддержку нескольких популярных шаблонизаторов, в том числе jte. В конфигурации приложения нужно указать, что мы хотим использовать jte в качестве шаблонизатора в нашем приложении:</p>
15 <p>Шаблоны JTE с HTML хранятся в директории<em>src/main/jte</em>и имеют расширение<em>jte</em>. Чтобы попрактиковаться, добавим первый шаблон для главной страницы сайта. Для этого выполним два действия:</p>
15 <p>Шаблоны JTE с HTML хранятся в директории<em>src/main/jte</em>и имеют расширение<em>jte</em>. Чтобы попрактиковаться, добавим первый шаблон для главной страницы сайта. Для этого выполним два действия:</p>
16 <ol><li><p>Создадим шаблон<em>src/main/jte/index.jte</em>со следующим содержимым:</p>
16 <ol><li><p>Создадим шаблон<em>src/main/jte/index.jte</em>со следующим содержимым:</p>
17 </li>
17 </li>
18 <li><p>Укажем обработчику главной страницы использовать этот шаблон:</p>
18 <li><p>Укажем обработчику главной страницы использовать этот шаблон:</p>
19 </li>
19 </li>
20 </ol><p>Обратите внимание на метод ctx.render() в коде выше. Он выполняет рендеринг указанного шаблона и добавляет результат в HTTP-ответ.</p>
20 </ol><p>Обратите внимание на метод ctx.render() в коде выше. Он выполняет рендеринг указанного шаблона и добавляет результат в HTTP-ответ.</p>
21 <p>Путь до шаблона указывается относительно директории<em>src/main/jte</em>:</p>
21 <p>Путь до шаблона указывается относительно директории<em>src/main/jte</em>:</p>
22 <p>Сами шаблоны могут располагаться и на более глубоком уровне. Это становится важно, когда количество шаблонов увеличивается.</p>
22 <p>Сами шаблоны могут располагаться и на более глубоком уровне. Это становится важно, когда количество шаблонов увеличивается.</p>
23 <p>Шаблонизатор не задает правила именования и внутренней структуры шаблонов. Но работать без правил слишком сложно, поэтому со временем мы самостоятельно выработаем правила и будем их придерживаться.</p>
23 <p>Шаблонизатор не задает правила именования и внутренней структуры шаблонов. Но работать без правил слишком сложно, поэтому со временем мы самостоятельно выработаем правила и будем их придерживаться.</p>
24 <p>В директории<em>src/main/jte</em>помимо самих шаблонов может быть расположен файл<em>.jteroot</em>. Это просто пустой файл, который указывает JTE, где находится корневая директория с шаблонами. Хотя в Javalin наличие этого файла не является обязательным, так как шаблонизатор уже заранее сконфигурирован фреймворком для поиска шаблонов в директории<em>src/main/jte</em>, мы рекомендуем его создавать. Этот файл помогает IntelliJ IDEA точно определять расположение шаблонов и корректно подсвечивать синтаксис, что в свою очередь упрощает работу с проектом.</p>
24 <p>В директории<em>src/main/jte</em>помимо самих шаблонов может быть расположен файл<em>.jteroot</em>. Это просто пустой файл, который указывает JTE, где находится корневая директория с шаблонами. Хотя в Javalin наличие этого файла не является обязательным, так как шаблонизатор уже заранее сконфигурирован фреймворком для поиска шаблонов в директории<em>src/main/jte</em>, мы рекомендуем его создавать. Этот файл помогает IntelliJ IDEA точно определять расположение шаблонов и корректно подсвечивать синтаксис, что в свою очередь упрощает работу с проектом.</p>
25 <h2>Как работает отображение данных</h2>
25 <h2>Как работает отображение данных</h2>
26 <p>Как правило, HTML внутри шаблонов формируется на основе данных, которые мы хотим вывести. Например, чтобы вывести информацию о курсе на странице<em>/courses/{id}</em>, мы передаем объект этого курса в шаблон и формируем HTML на основе его содержимого.</p>
26 <p>Как правило, HTML внутри шаблонов формируется на основе данных, которые мы хотим вывести. Например, чтобы вывести информацию о курсе на странице<em>/courses/{id}</em>, мы передаем объект этого курса в шаблон и формируем HTML на основе его содержимого.</p>
27 <p>Попробуем проделать этот путь. Создадим класс для курса с тремя полями - идентификатором, названием и описанием:</p>
27 <p>Попробуем проделать этот путь. Создадим класс для курса с тремя полями - идентификатором, названием и описанием:</p>
28 <p>По идее, обработчик маршрута<em>/courses/{id}</em>получает курс из базы данных и передает его в шаблон. Для этого создадим дата-класс:</p>
28 <p>По идее, обработчик маршрута<em>/courses/{id}</em>получает курс из базы данных и передает его в шаблон. Для этого создадим дата-класс:</p>
29 <p>Осталось написать обработчик и посмотреть, как все это работает в связке:</p>
29 <p>Осталось написать обработчик и посмотреть, как все это работает в связке:</p>
30 <p>Рассмотрим, по какому алгоритму обработчики обычно работают с шаблонами:</p>
30 <p>Рассмотрим, по какому алгоритму обработчики обычно работают с шаблонами:</p>
31 <ol><li>Сначала они извлекают все необходимые данные</li>
31 <ol><li>Сначала они извлекают все необходимые данные</li>
32 <li>Затем они создают объект дата-класса и заполняют его этими данными</li>
32 <li>Затем они создают объект дата-класса и заполняют его этими данными</li>
33 <li>В итоге они передают этот объект в шаблон в виде Map, созданного при помощи статического метода model(), который предоставляет Javalin</li>
33 <li>В итоге они передают этот объект в шаблон в виде Map, созданного при помощи статического метода model(), который предоставляет Javalin</li>
34 </ol><p>Остался последний шаг - вывести данные курса в шаблоне. Для этого в шаблонах используется специальный синтаксис. Через него мы указываем, какой дата-класс мы используем и под каким именем хотим передать его объект в шаблон. В нашем случае это объект класса CoursePage, переданный под именем page:</p>
34 </ol><p>Остался последний шаг - вывести данные курса в шаблоне. Для этого в шаблонах используется специальный синтаксис. Через него мы указываем, какой дата-класс мы используем и под каким именем хотим передать его объект в шаблон. В нашем случае это объект класса CoursePage, переданный под именем page:</p>
35 <p>В первых двух строчках шаблона мы используем<strong>директивы</strong>- специальные конструкции, которые начинаются со знака @:</p>
35 <p>В первых двух строчках шаблона мы используем<strong>директивы</strong>- специальные конструкции, которые начинаются со знака @:</p>
36 <ul><li>Директива @import аналогична импорту в Java</li>
36 <ul><li>Директива @import аналогична импорту в Java</li>
37 <li>Директива @param указывает, какие данные нужно использовать внутри Map, переданного в шаблон. Доступ к данным внутри шаблона идет через это имя</li>
37 <li>Директива @param указывает, какие данные нужно использовать внутри Map, переданного в шаблон. Доступ к данным внутри шаблона идет через это имя</li>
38 </ul><p>Дальше мы видим подстановку данных внутрь HTML. Этот способ называется<strong>интерполяцией</strong>. Он работает через указание Java-кода внутри структуры ${}.</p>
38 </ul><p>Дальше мы видим подстановку данных внутрь HTML. Этот способ называется<strong>интерполяцией</strong>. Он работает через указание Java-кода внутри структуры ${}.</p>
39 <h2>Какие управляющие конструкции используются в jte</h2>
39 <h2>Какие управляющие конструкции используются в jte</h2>
40 <p>Кроме обычного вывода значений, в шаблонах часто используются условные конструкции и циклы. С их помощью показываются списки, прячутся или показываются определенные блоки и так далее.</p>
40 <p>Кроме обычного вывода значений, в шаблонах часто используются условные конструкции и циклы. С их помощью показываются списки, прячутся или показываются определенные блоки и так далее.</p>
41 <p>Подробнее обо всех этих конструкциях можно прочитать в официальной документации. А здесь мы разберем пример на базе маршрута /courses, по которому выводится список курсов с описанием и ссылками на курсы:</p>
41 <p>Подробнее обо всех этих конструкциях можно прочитать в официальной документации. А здесь мы разберем пример на базе маршрута /courses, по которому выводится список курсов с описанием и ссылками на курсы:</p>
42 <ol><li><p>Начнем с<strong>дата-класса</strong>. Кроме курсов, добавим еще и заголовок для разнообразия:</p>
42 <ol><li><p>Начнем с<strong>дата-класса</strong>. Кроме курсов, добавим еще и заголовок для разнообразия:</p>
43 </li>
43 </li>
44 <li><p>Перейдем к<strong>обработчику</strong>:</p>
44 <li><p>Перейдем к<strong>обработчику</strong>:</p>
45 </li>
45 </li>
46 <li><p>В конце переходим к<strong>шаблону</strong>:</p>
46 <li><p>В конце переходим к<strong>шаблону</strong>:</p>
47 </li>
47 </li>
48 </ol><p>Логика вывода здесь такая:</p>
48 </ol><p>Логика вывода здесь такая:</p>
49 <ul><li>Если список курсов пустой, то выводится соответствующее сообщение</li>
49 <ul><li>Если список курсов пустой, то выводится соответствующее сообщение</li>
50 <li>Если курсы в списке есть, то на основе этого списка формируются HTML-блоки с информацией о курсе и ссылкой на его страницу</li>
50 <li>Если курсы в списке есть, то на основе этого списка формируются HTML-блоки с информацией о курсе и ссылкой на его страницу</li>
51 </ul><p>Этих конструкций хватит для решения большинства стандартных задач, потому что внутри них можно использовать любой Java-код. Единственное, что нужно не забывать - это импортировать используемые классы через директиву @import.</p>
51 </ul><p>Этих конструкций хватит для решения большинства стандартных задач, потому что внутри них можно использовать любой Java-код. Единственное, что нужно не забывать - это импортировать используемые классы через директиву @import.</p>