Введение в Thymeleaf

В этой статье продолжим разбирать приложение из предыдущего примера. На этот раз сосредоточимся на синтаксисе шаблонов Thymeleaf. В пример будет добавлена проверка  поля и вывод в шаблон ошибок.

Maven-зависимость

Чтобы добавить Thymeleaf в Spring Boot приложение, мы прописали в POM-файле зависимость:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Отображение атрибутов модели

На главной странице мы добавляли в модель два атрибута: animals и animal:

Set<Animal> animals = animalCart.getAnimals();

model.addAttribute("animals", animals);
model.addAttribute("animal", new Animal());

animals — коллекция, animal объект.

В шаблоне атрибуты становятся переменными, к которым есть доступ.

Вообще наша страница выглядит так:

Как выглядит страница на основе шаблона index.html
Как выглядит страница на основе шаблона index.html

В шаблоне выводится коллекция animals. А перед ней находится форма, которая через заполненный animal отправляет введенное название животного в контроллер.

th:each — отображение коллекции

Начнем с коллекции animals. Мы ее выводим в виде таблицы:

<table>
    <thead>
    <tr>
        <th>ID</th>
        <th>Животное</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="an, iterStat : ${animals}"
         th:style="${iterStat.odd}? 'font-weight: bold;'">
        <td th:text="${iterStat.index}+1"></td>
        <td th:text="${an.name}"></td>
    </tr>
    </tbody>
</table>

${animals} — это обращение к переменной, содержащей коллекцию. Строка <tr> будет повторяться столько раз, сколько элементов в коллекции, для этого мы задаем для нее:

<tr th:each="an, iterStat : ${animals}"

Здесь an — текущее животное, iterStat — итератор.

Из него можно получить индекс:

${iterStat.index}

а также, является ли индекс нечетным числом:

${iterStat.odd}

th:style — задание стиля

Если является, ты мы задаем строке стиль:

th:style="${iterStat.odd}? 'font-weight: bold;'"

Так все нечетные строки будут выделены жирным шрифтом.

th:text — отображение текста внутри тега

Как вывести имя животного? Для этого есть очень популярный атрибут th:text:

<td th:text="${an.name}"></td>

Он заполняет тег значением из переменной.

Если название животного — «козел»,  то вышеприведенная запись преобразуется на итоговой странице в:

<td>козел</td>

Перейдем к форме.

Обработка формы: th:action, th:object, th:field

Форма у нас обрабатывается благодаря трем атрибутам:

  • th:action=»@{/}»
  • th:object=»${animal}»
  • th:field=»*{name}»

где первый атрибут th:action задает адрес /, по которому идет POST-запрос с формы, второй —  объект Animal, а третий — его поле name, которое заполняется и передается в контроллер. Обратите внимание, что переменная ${animal} задана в th:object, поэтому имя поля прописывается со звездочки.

<form th:action="@{/}" th:object="${animal}" th:method="post">
    <div>
        <label>Название:&nbsp;</label>
        <input type="text" th:field="*{name}"></input>
    </div>
    <div>
        <button type="submit">Добавить в корзину</button>
    </div>
</form>

Форма преобразуется в итоге:

<form action="/" method="post">
    <div>
        <label>Название:</label>
        <input type="text" id="name" name="name" value=""></input>
    </div>
    <div>
        <button type="submit">Добавить в корзину</button>
    </div>
</form>

th:value

Но можно обойтись без th:object, в этом случае тегу <input> прописываем атрибут th:value:

<input type="text" th:value="${animal.name}" name="name"/>

Разницы нет, в обоих случаях в теле POST-запроса уходит name=значение, а итоговый <input>:

<input type="text" value="" name="name"/>

Проверка поля и вывод ошибок — th:errors

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

Модель — @NotBlank и @Size(min=2, max=50)

Во-первых, добавим для поля name модели условие, при котором оно считается корректным:

@NoArgsConstructor
@Data
@Entity
public class Animal {
    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private long id;
    @NotBlank
    @Size(min=2, max=50)
    private String name;
}

То есть поле name должно быть не пустым (не состоять из пробелов) и иметь размер от 2 до 50.

Чтобы аннотации @NotBlank и@Size(min=2, max=50) компилировались и обрабатывались, необходимо добавить Maven-зависимость:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

@Valid и BindingResult в контроллере

Во-вторых, исправим контроллер.

Значение name должно проверяться, когда Animal приходит в контроллер в метод add().

Чтобы это происходило, аннотируем animal с помощью @Valid, а следующим аргументом добавим BindingResult (порядок важен):

@PostMapping("/")
public String add(@Valid Animal animal, BindingResult bindingResult, Model model) {
    if (bindingResult.hasErrors()) {
        model.addAttribute("animals", animalCart.getAnimals());
        return "index";
    }
    animalCart.add(animal);
    return "redirect:/";
}

Теперь перенаправление («redirect:/») на get() делаем только в случае успеха, иначе же просто возвращаем index.html с ошибками. Модель тоже надо заполнять, чтобы не терять список уже добавленных животных.

th:errors — вывод ошибок

После всех приготовлений вывести ошибки просто. Просто добавим под <input> тег:

<div th:errors="*{name}" class="error"/>

В итоге при попытке добавить пустую строку получим:

Вывод ошибок
Вывод ошибок

Итоги

Код примера доступен на GitHub. В нем добавлена проверка поля и вывод ошибок, касающихся этого поля.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *