HTML-шаблоны
Статический файл всегда одинаковый, а страница со списком постов должна меняться вместе с данными. Для этого используют шаблон — HTML-файл с местами для подстановки значений. Программа, которая заполняет шаблон, называется шаблонизатором. Javalin поддерживает несколько шаблонизаторов через отдельные модули; мы возьмём Mustache — у него самый простой синтаксис.
Зависимость
Добавьте модуль в pom.xml, в раздел dependencies:
<!-- pom.xml -->
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin-rendering-mustache</artifactId>
<version>${javalin.version}</version>
</dependency>Модуль уже содержит сам Mustache. Для других шаблонизаторов есть javalin-rendering-freemarker, javalin-rendering-thymeleaf, javalin-rendering-jte и другие — они подключаются так же.
Шаблон
Шаблоны лежат в classpath. Создайте файл в папке templates:
<!-- src/main/resources/templates/posts.mustache -->
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Блог</title>
</head>
<body>
<h1>Посты</h1>
{{#posts}}
<article>
<h2>{{title}}</h2>
<p>{{body}}</p>
<small>Автор: {{author}}</small>
</article>
{{/posts}}
{{^posts}}
<p>Постов пока нет.</p>
{{/posts}}
</body>
</html>| Запись | Что значит |
|---|---|
{{title}} | Подставить значение, спецсимволы HTML экранируются |
{{#posts}} ... {{/posts}} | Повторить блок для каждого элемента списка |
{{^posts}} ... {{/posts}} | Показать блок, если список пуст |
Mustache умеет читать компоненты записей: {{title}} вызывает метод title() у Post.
Подключение и вызов
Зарегистрируйте шаблонизатор в настройках и добавьте маршрут страницы в блок apiBuilder:
// src/main/java/com/example/blog/Main.java
config.fileRenderer(new JavalinMustache()); // io.javalin.rendering.template.JavalinMustache
config.routes.apiBuilder(() -> {
// ... маршруты /posts
get("/blog", posts::page);
});В контроллере метод page передаёт в шаблон модель — словарь с данными:
// src/main/java/com/example/blog/PostController.java
public void page(Context ctx) {
ctx.render("templates/posts.mustache", Map.of("posts", store.findAll()));
}ctx.render заполняет шаблон и отправляет HTML с заголовком Content-Type: text/html. Откройте http://localhost:8080/blog в браузере или вызовите curl:
curl http://localhost:8080/blog<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Блог</title>
</head>
<body>
<h1>Посты</h1>
<article>
<h2>Привет, Javalin</h2>
<p>Первый пост.</p>
<small>Автор: Анна</small>
</article>
<article>
<h2>Маршруты</h2>
<p>Как работают маршруты.</p>
<small>Автор: Олег</small>
</article>
</body>
</html>
Частая ошибка
Mustache ищет файл от корня classpath, поэтому путь пишут вместе с папкой. Вызов ctx.render("posts.mustache", ...) даёт ответ 500, а в логе:
com.github.mustachejava.MustacheNotFoundException: Template posts.mustache not found
Указывайте путь от src/main/resources: templates/posts.mustache.