Spring MVC中@ExceptionHandler无法捕获MethodArgumentNotValidException
Let's break down why your MethodArgumentNotValidException handler isn't picking up form validation failures—it's a common Spring quirk!
The Root Cause
When you use @ModelAttribute to bind form data (like your registration form), Spring throws a BindException when validation rules are violated. MethodArgumentNotValidException is only thrown for request body validation (e.g., JSON payloads with @RequestBody), not traditional form submissions. That's why your handler is missing the error—you're listening for the wrong exception type.
Fixes to Try
Option 1: Handle Both Exception Types (Flexible Solution)
Update your handler to catch both BindException and MethodArgumentNotValidException, so it works for both form and API validation scenarios. You can reuse your existing error logic by extracting the BindingResult from either exception:
@ExceptionHandler({MethodArgumentNotValidException.class, BindException.class}) public String handleValidationErrors(Exception ex, Model model) { BindingResult bindingResult; // Extract validation results from whichever exception was thrown if (ex instanceof MethodArgumentNotValidException) { bindingResult = ((MethodArgumentNotValidException) ex).getBindingResult(); } else { bindingResult = ((BindException) ex).getBindingResult(); } // Your existing error formatting logic String errorFields = bindingResult.getAllErrors().stream() .map(err -> ((FieldError) err).getField()) .distinct() .collect(Collectors.joining(", ")); String message = String.format("The next fields are incorrectly filled: %s!", errorFields); model.addAttribute("error", "Registration failed"); model.addAttribute("cause", message); return "error"; }
Option 2: Target Only BindException (Simpler for Form-Only Use)
If you don't plan to use request body validation in this controller, you can simplify the handler to only catch BindException:
@ExceptionHandler(BindException.class) public String handleIncorrectRequests(BindException ex, Model model) { String errorFields = ex.getBindingResult() .getAllErrors().stream() .map(err -> ((FieldError) err).getField()) .distinct() .collect(Collectors.joining(", ")); String message = String.format("The next fields are incorrectly filled: %s!", errorFields); model.addAttribute("error", "Registration failed"); model.addAttribute("cause", message); return "error"; }
Why Your EmailAlreadyInUseException Handler Works
Your custom EmailAlreadyInUseException handler works because you're explicitly throwing this exception from userService.registerUser(user). Spring routes this directly to your matching handler without any type mismatch issues—no hidden Spring exception type switches here!
内容的提问来源于stack exchange,提问作者samax

