Работая на Хекслете, вы не раз видели сообщение о результатах выполнения любого действия — будь то аутентификация, регистрация или вступление в курс. Выглядят эти сообщения так:
В веб-разработке это называется флеш-сообщениями. Они обычно используются после редиректа для индикации успешности или неудачи предыдущего действия. Например, после регистрации сайт выполняет перенаправление на страницу, с которой пришел пользователь, а затем выводит сообщение «Регистрация выполнена».
Особенность флеш-сообщений в том, что они появляются только один раз и пропадают после обновления страницы.
Иногда фреймворки поддерживают флеш-сообщения самостоятельно или с помощью соответствующих дополнений. В случае Java-фреймворков таких решений нет, но их легко имитировать с помощью механизма сессий. В Javalin нам для этого понадобится два метода:
// Этот метод устанавливает в сессию значение по ключу
ctx.sessionAttribute("key", "value");
// Этот метод читает сообщение из сессии и тут же удаляет его
ctx.consumeSessionAttribute("key");
Метод consumeSessionAttribute()
идеально подходит для реализации сессии. Он читает сообщение из сессии и удаляет его, что автоматически прячет сообщение при обновлении страницы или клику по любой ссылке.
Добавим флеш-сообщение в процесс создания курса. Для этого нам понадобится установить сообщение, которое будет выводиться после успешного создания курса:
app.post(NamedRoutes.coursesPath(), ctx -> {
var name = ctx.formParam("name");
var description = ctx.formParam("description");
var course = new Course(name, description);
CourseRepository.save(course);
// Добавляем сообщение в сессию
// Ключ может иметь любое название, здесь мы выбрали flash
ctx.sessionAttribute("flash", "Course has been created!");
ctx.redirect(NamedRoutes.coursesPath());
});
Сразу после установки сообщения выполняется редирект и загрузка какой-то другой страницы — в нашем случае это список курсов. Это означает, что вывод сообщения должен происходить на этом списке. Для этого нам понадобится извлечь сообщение из сессии, передать его в шаблон и вывести:
app.get(NamedRoutes.coursesPath(), ctx -> {
String flash = ctx.consumeSessionAttribute("flash");
// Добавляем flash в определение CoursesPage
var page = new CoursesPage(courses, term, flash);
ctx.render("courses/index.jte", model("page", page));
});
Метод ctx.consumeSessionAttribute()
извлекает данные по указанному ключу и удаляет их. Это важно, потому что повторная загрузка страницы приведет к пропаданию флеш-сообщения. Дальше сообщение передается в CoursePage
. Осталось сделать вывод в шаблоне:
@if(page.getFlash() != null)
<p>${page.getFlash()}</p>
@endif
Использование макета
Логика вывода флеш-сообщений идентична для всех страниц сайта, поэтому перенесем их вывод в макет. Но как их передать туда с учетом, что такие сообщения передаются в шаблон в разных Page
объектах?
Самый простой способ — это создание базового класса для всех Page
, в котором сосредоточится логика работы с флеш-сообщениями:
// src/main/java/org/example/hexlet/dto/BasePage.java
package org.example.hexlet.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class BasePage {
private String flash;
}
Класс CoursesPage
при этом будет наследоваться от базового класса Page
package org.example.hexlet.dto.courses;
import org.example.hexlet.dto.BasePage;
import lombok.AllArgsConstructor;
import lombok.Getter;
// остальные импорты
@AllArgsConstructor
@Getter
public class CoursesPage extends BasePage {
private List<Course> courses;
private String term;
}
Теперь в нужном месте мы можем добавлять сообщения так:
app.get(NamedRoutes.coursesPath(), ctx -> {
var page = new CoursesPage(courses, term);
page.setFlash(ctx.consumeSessionAttribute("flash"));
ctx.render("courses/index.jte", model("page", page));
});
Затем мы должны передать этот page
в макет в шаблоне этого обработчика:
@import org.example.hexlet.util.NamedRoutes
@import org.example.hexlet.dto.courses.CoursesPage
@param CoursesPage page
@template.layout.page(
page = page,
content = @`
Тут шаблон
`
)
И наконец вывод в макете:
@import org.example.hexlet.util.NamedRoutes
@import org.example.hexlet.dto.BasePage // Импортируем базовый класс
@import gg.jte.Content
@param Content content
@param BasePage page = null // Если не передали, то игнорируем
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Hexlet Javalin Example</title>
</head>
<body>
@if(page != null && page.getFlash() != null)
<p>${page.getFlash()}</p>
@endif
${content}
</body>
</html>
Самостоятельная работа
- Проделайте все шаги из урока на своем компьютере
- Добавьте в приложение вывод флеш-сообщения об успехе или неудаче при регистрации нового пользователя
- Подсветите сообщения разными цветами с помощью Bootstrap:
- Зеленым — при успешной регистрации
- Красным — если возникла ошибка
- Залейте изменения на GitHub
Дополнительные материалы
Остались вопросы? Задайте их в разделе «Обсуждение»
Вам ответят команда поддержки Хекслета или другие студенты
Для полного доступа к курсу нужен базовый план
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.