Java: Веб-технологии
2026-02-26 18:08 Diff

В этом уроке мы познакомимся с шаблонизаторами.

Зачем нужны шаблонизаторы

Javalin и другие подобные фреймворки позволяют создавать полноценные сайты без дополнительных инструментов. Рабочий сайт должен просто возвращать ответ с HTML-кодом, который браузер отобразит как страницу:

Здесь мы видим упрощенный пример, в котором мы возвращаем только заголовок H1.

В реальных приложениях возвращаемый HTML состоит из сотен и тысяч строк. Работать с такими объемами стандартным способом очень сложно. Вот лишь некоторые проблемы, с которыми мы столкнемся:

  • Такой код сложно формировать, редактировать и поддерживать
  • В таком коде очень легко допустить ошибку и очень сложно ее обнаружить
  • В таком коде будут возникать проблемы с одинарными или двойными кавычками, придется их экранировать и постоянно следить за этим

Для решения этой проблемы используются шаблонизаторы. Это библиотеки, которые позволяют формировать HTML в отдельных файлах с подсветкой и удобной подстановкой данных. Другими словами, мы получаем не HTML внутри кода, а код внутри HTML.

В Java-мире есть несколько разных шаблонизаторов. Для этого курса мы выбрали jte (Java Template Engine), потому что он официально поддерживается в Javalin.

Посмотрим, как выглядит HTML c jte:

Как начать работать с JTE

Чтобы начать работу с jte, нужно добавить в зависимости две строчки:

Пакет javalin-rendering добавляет в Javalin поддержку нескольких популярных шаблонизаторов, в том числе jte. В конфигурации приложения нужно указать, что мы хотим использовать jte в качестве шаблонизатора в нашем приложении:

Шаблоны JTE с HTML хранятся в директории src/main/jte и имеют расширение jte. Чтобы попрактиковаться, добавим первый шаблон для главной страницы сайта. Для этого выполним два действия:

  1. Создадим шаблон src/main/jte/index.jte со следующим содержимым:

  2. Укажем обработчику главной страницы использовать этот шаблон:

Обратите внимание на метод ctx.render() в коде выше. Он выполняет рендеринг указанного шаблона и добавляет результат в HTTP-ответ.

Путь до шаблона указывается относительно директории src/main/jte:

Сами шаблоны могут располагаться и на более глубоком уровне. Это становится важно, когда количество шаблонов увеличивается.

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

В директории src/main/jte помимо самих шаблонов может быть расположен файл .jteroot. Это просто пустой файл, который указывает JTE, где находится корневая директория с шаблонами. Хотя в Javalin наличие этого файла не является обязательным, так как шаблонизатор уже заранее сконфигурирован фреймворком для поиска шаблонов в директории src/main/jte, мы рекомендуем его создавать. Этот файл помогает IntelliJ IDEA точно определять расположение шаблонов и корректно подсвечивать синтаксис, что в свою очередь упрощает работу с проектом.

Как работает отображение данных

Как правило, HTML внутри шаблонов формируется на основе данных, которые мы хотим вывести. Например, чтобы вывести информацию о курсе на странице /courses/{id}, мы передаем объект этого курса в шаблон и формируем HTML на основе его содержимого.

Попробуем проделать этот путь. Создадим класс для курса с тремя полями — идентификатором, названием и описанием:

По идее, обработчик маршрута /courses/{id} получает курс из базы данных и передает его в шаблон. Для этого создадим дата-класс:

Осталось написать обработчик и посмотреть, как все это работает в связке:

Рассмотрим, по какому алгоритму обработчики обычно работают с шаблонами:

  1. Сначала они извлекают все необходимые данные
  2. Затем они создают объект дата-класса и заполняют его этими данными
  3. В итоге они передают этот объект в шаблон в виде Map, созданного при помощи статического метода model(), который предоставляет Javalin

Остался последний шаг — вывести данные курса в шаблоне. Для этого в шаблонах используется специальный синтаксис. Через него мы указываем, какой дата-класс мы используем и под каким именем хотим передать его объект в шаблон. В нашем случае это объект класса CoursePage, переданный под именем page:

В первых двух строчках шаблона мы используем директивы — специальные конструкции, которые начинаются со знака @:

  • Директива @import аналогична импорту в Java
  • Директива @param указывает, какие данные нужно использовать внутри Map, переданного в шаблон. Доступ к данным внутри шаблона идет через это имя

Дальше мы видим подстановку данных внутрь HTML. Этот способ называется интерполяцией. Он работает через указание Java-кода внутри структуры ${}.

Какие управляющие конструкции используются в jte

Кроме обычного вывода значений, в шаблонах часто используются условные конструкции и циклы. С их помощью показываются списки, прячутся или показываются определенные блоки и так далее.

Подробнее обо всех этих конструкциях можно прочитать в официальной документации. А здесь мы разберем пример на базе маршрута /courses, по которому выводится список курсов с описанием и ссылками на курсы:

  1. Начнем с дата-класса. Кроме курсов, добавим еще и заголовок для разнообразия:

  2. Перейдем к обработчику:

  3. В конце переходим к шаблону:

Логика вывода здесь такая:

  • Если список курсов пустой, то выводится соответствующее сообщение
  • Если курсы в списке есть, то на основе этого списка формируются HTML-блоки с информацией о курсе и ссылкой на его страницу

Этих конструкций хватит для решения большинства стандартных задач, потому что внутри них можно использовать любой Java-код. Единственное, что нужно не забывать — это импортировать используемые классы через директиву @import.