JavaRush /Курсы /Модуль 5. Spring /Обработка форм в Spring MVC

Обработка форм в Spring MVC

Модуль 5. Spring
7 уровень , 8 лекция
Открыта

Формы — это основной способ взаимодействия пользователя с сервером через веб-интерфейс. Будь то регистрация, добавление данных или выполнение поискового запроса, формы являются мостом между фронтендом и бэкендом. Spring MVC предоставляет удобные инструменты для обработки пользовательских данных через формы, их валидации и передачи обратно в представления, если что-то пошло не так.


Обработка форм: пошаговый процесс

Чтобы лучше понять, как обрабатываются формы в Spring MVC, разобьём весь процесс на основные шаги:

  1. Создание формы в HTML с использованием Thymeleaf.
  2. Настройка модели для передачи данных.
  3. Создание контроллера для обработки данных формы.
  4. Валидация данных с помощью аннотации @Valid.
  5. Реакция на ошибки и отправка данных обратно в форму.

Создадим форму: HTML + Thymeleaf

Начнём с простого примера — регистрация пользователя. Вот HTML-фрагмент формы:


<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>Регистрация</title>
</head>
<body>
  <h1>Регистрация</h1>
  <form th:action="@{/register}" method="post" th:object="${user}">
    <label for="name">Имя:</label>
    <input type="text" id="name" th:field="*{name}" />
    <br/>
    <label for="email">Email:</label>
    <input type="email" id="email" th:field="*{email}" />
    <br/>
    <label for="password">Пароль:</label>
    <input type="password" id="password" th:field="*{password}" />
    <br/>
    <button type="submit">Зарегистрироваться</button>
  </form>
</body>
</html>

Разберём основные элементы:

  • th:action="@{/register}" — URL, куда будет отправлена форма. Здесь мы ссылаемся на контроллер с маршрутом /register.
  • th:object="${user}" — объект, связанный с этой формой (модель). В нашем случае это объект user.
  • th:field="*{name}" — связывает поле формы с полем объекта user.name.

Форма создаст HTTP POST-запрос с данными, введёнными пользователем.


Модель данных: создание класса DTO

Теперь создадим объект User для связывания данных, поступающих из формы. Это POJO-класс с нужными полями:


package com.example.demo.dto;

import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public class User {

    @NotBlank(message = "Имя не должно быть пустым")
    @Size(min = 2, max = 30, message = "Имя должно быть длиной от 2 до 30 символов")
    private String name;

    @NotBlank(message = "Email не должен быть пустым")
    @Email(message = "Введите корректный email")
    private String email;

    @NotBlank(message = "Пароль не должен быть пустым")
    @Size(min = 6, message = "Пароль должен быть длиной минимум 6 символов")
    private String password;

    // Getters и Setters
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

Интересные моменты:

  • Аннотации из пакета jakarta.validation.constraints помогут нам валидировать поля. Например, @Email проверит корректность email, а @Size ограничит длину текста.

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

Теперь сделаем контроллер, который будет показывать страницу с формой и обрабатывать отправленные данные.


package com.example.demo.controller;

import com.example.demo.dto.User;
import jakarta.validation.Valid;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class RegistrationController {

    @GetMapping("/register")
    public String showRegistrationForm(Model model) {
        model.addAttribute("user", new User());
        return "register";
    }

    @PostMapping("/register")
    public String processRegistrationForm(@Valid User user, BindingResult result, Model model) {
        if (result.hasErrors()) {
            return "register"; // Вернуть пользователя на форму, если есть ошибки
        }

        // Здесь вы можете сохранить данные в базу или отправить куда-то ещё
        model.addAttribute("message", "Регистрация прошла успешно!");
        return "success";
    }
}
  1. @GetMapping("/register"): показывает страницу с формой. Мы добавляем пустой объект User в модель, чтобы Thymeleaf мог с ним работать.
  2. @PostMapping("/register"): обрабатывает POST-запрос. Обратите внимание на аннотацию @Valid перед параметром User. Это говорит Spring, что нужно выполнить валидацию этого объекта.
  3. BindingResult result: хранит результаты валидации. Если есть ошибки, мы возвращаем пользователя обратно на форму.

Валидация на стороне сервера

Допустим, пользователь ввёл что-то некорректно. Нам нужно отобразить ошибки на странице:


<form th:action="@{/register}" method="post" th:object="${user}">
  <label for="name">Имя:</label>
  <input type="text" id="name" th:field="*{name}" />
  <div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
  <br/>
  <label for="email">Email:</label>
  <input type="email" id="email" th:field="*{email}" />
  <div th:if="${#fields.hasErrors('email')}" th:errors="*{email}"></div>
  <br/>
  <label for="password">Пароль:</label>
  <input type="password" id="password" th:field="*{password}" />
  <div th:if="${#fields.hasErrors('password')}" th:errors="*{password}"></div>
  <br/>
  <button type="submit">Зарегистрироваться</button>
</form>

Что происходит?

Если валидация объекта User выявила ошибки, метод #fields.hasErrors() вернёт true для полей с ошибками. Аннотация th:errors автоматически выведет описание ошибки, заданное в модели.


Глобальные ошибки формы (например, совпадение паролей)

Если вам нужно добавить общую ошибку для формы, это можно сделать через BindingResult:


if (!user.getPassword().equals(user.getConfirmPassword())) {
    result.rejectValue("password", "error.user", "Пароли не совпадают");
}

Или глобальную ошибку:


if (user.getEmail().contains("spam")) {
    result.reject("email.spam", "Email не может содержать 'spam'");
}

Подводные камни и типичные ошибки

Почему BindingResult всегда должен быть сразу после @Valid?

Spring обрабатывает валидацию и записывает результаты в объект BindingResult. Если вы поменяете порядок аргументов метода, это вызовет IllegalStateException.

Осторожно с названиями полей!

Имена полей формы (например, th:field="*{name}") должны точно совпадать с именами полей в объекте User. Иначе данные не будут связаны корректно.


Что дальше?

Теперь вы умеете обрабатывать формы, связывать их с объектами и валидировать данные. Эти знания пригодятся вам для создания функциональных интерфейсов регистрации, авторизации, создания или редактирования сущностей в вашем приложении.

Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
9 декабря 2025
в коде как будто не хватает шаблона "success"