Как в Spring MVC обработать исключение UserNotFoundException и выполнить redirect на страницу регистрации?

«Как в Spring MVC обработать исключение UserNotFoundException и выполнить redirect на страницу регистрации?» — вопрос из категории Spring, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Spring MVC для глобальной обработки исключений и выполнения перенаправления (redirect) используются аннотации @ControllerAdvice и @ExceptionHandler.

1. Создание пользовательского исключения

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
    // Можно добавить дополнительные поля, например, userId
}

2. Создание класса-обработчика исключений (@ControllerAdvice)

Класс, помеченный @ControllerAdvice, перехватывает исключения, выброшенные в любом контроллере.

@ControllerAdvice // Объявляет глобальный обработчик исключений
public class GlobalExceptionHandler {

    @ExceptionHandler(UserNotFoundException.class) // Указывает тип обрабатываемого исключения
    public String handleUserNotFoundException(UserNotFoundException ex,
                                               HttpServletRequest request,
                                               RedirectAttributes redirectAttributes) {
        // 1. Логирование исключения (обязательно для отладки)
        logger.error("User not found for request: " + request.getRequestURI(), ex);

        // 2. Добавление flash-атрибута для передачи сообщения на страницу регистрации
        // Flash-атрибуты живут ровно один redirect, что идеально подходит для этой задачи.
        redirectAttributes.addFlashAttribute("errorMessage",
                "Пользователь не найден. Пожалуйста, зарегистрируйтесь.");

        // 3. Выполнение redirect на URL страницы регистрации
        return "redirect:/register"; // Предполагается, что есть маппинг на "/register"
    }
}

3. Контроллер, который бросает исключение

@Controller
public class UserController {
    @GetMapping("/user/{id}")
    public String getUserProfile(@PathVariable Long id, Model model) {
        User user = userService.findById(id)
                .orElseThrow(() -> new UserNotFoundException("User with id " + id + " not found"));
        model.addAttribute("user", user);
        return "profile";
    }
}

4. Контроллер и страница регистрации

@Controller
public class RegistrationController {
    @GetMapping("/register")
    public String showRegistrationForm(Model model) {
        // Атрибут "errorMessage" будет автоматически подставлен из flash-атрибута
        // если он был установлен в обработчике исключений.
        if (!model.containsAttribute("userDto")) {
            model.addAttribute("userDto", new UserDto());
        }
        return "registration-page"; // Имя Thymeleaf/HTML шаблона
    }
}

В шаблоне registration-page.html (например, Thymeleaf) можно отобразить сообщение:

<div th:if="${errorMessage}" class="alert alert-danger">
    <span th:text="${errorMessage}"></span>
</div>
<!-- Остальная форма регистрации -->

Ключевые моменты:

  • @ControllerAdvice + @ExceptionHandler — стандартный и мощный механизм для централизованной обработки исключений.
  • RedirectAttributes используется для безопасной передачи данных между запросами при redirect.
  • Flash-атрибуты (addFlashAttribute) идеальны для передачи сообщений об ошибках, так как они не попадают в URL и существуют один запрос.
  • Всегда логируйте исключения для последующего анализа.
  • Этот подход отделяет логику обработки ошибок от бизнес-логики контроллеров, делая код чище и поддерживаемее.