Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

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.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.