MethodArgumentNotValidException与NoHandlerFoundException映射冲突问题
问题根源
你继承了ResponseEntityExceptionHandler类,该父类已经通过内置的@ExceptionHandler逻辑处理了MethodArgumentNotValidException。但你自定义的handleMethodArgumentNotValid方法既注释掉了@Override,又额外添加了@ExceptionHandler(MethodArgumentNotValidException.class)注解,导致Spring识别到两个可处理MethodArgumentNotValidException的方法(父类的handleException方法和你自定义的方法),从而触发模糊映射异常。
修复方案
步骤1:修正MethodArgumentNotValidException处理方法
恢复@Override注解,同时移除方法上的@ExceptionHandler(MethodArgumentNotValidException.class)注解。继承ResponseEntityExceptionHandler后,重写该方法是自定义参数校验异常处理的标准方式,无需额外添加@ExceptionHandler。
修改后的代码如下:
@Slf4j @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { @ExceptionHandler({NoHandlerFoundException.class}) @ResponseBody @ResponseStatus(HttpStatus.NOT_FOUND) public ResponseEntity<ErrorListResponse> notFound(final NoHandlerFoundException exception) { log.error("{} {}", 404, exception.getMessage()); ErrorListResponse errorListResponse = errorResponse("Request URI Not Found", exception); return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorListResponse); } @Override // 恢复@Override注解 @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatusCode status, WebRequest request) { List<FieldError> errors = ex.getBindingResult().getFieldErrors(); List<ErrorListResponse.ErrorDetails> errorDetails = new ArrayList<>(); for (FieldError fieldError : errors) { ErrorListResponse.ErrorDetails error = new ErrorListResponse.ErrorDetails(); error.setReason(fieldError.getDefaultMessage()); error.setCode("BAD_REQUEST"); error.setDatetime(new DateTimeResponse(Instant.now().toString(), "America/New_York")); errorDetails.add(error); } ErrorListResponse errorResponse = new ErrorListResponse(); errorResponse.setErrors(errorDetails); log.error("{} {}", 400, "Multiple fields are invalid"); return new ResponseEntity(errorResponse, HttpStatus.BAD_REQUEST); } }
步骤2:确保NoHandlerFoundException能被抛出(必要配置)
默认情况下Spring不会抛出NoHandlerFoundException,需要在Spring Boot配置中添加以下参数:
# application.properties spring.mvc.throw-exception-if-no-handler-found=true spring.web.resources.add-mappings=false
或者在application.yml中:
# application.yml spring: mvc: throw-exception-if-no-handler-found: true web: resources: add-mappings: false
原理说明
ResponseEntityExceptionHandler是Spring提供的全局异常处理基类,已经为MethodArgumentNotValidException等常见Web异常定义了处理逻辑,并通过@ExceptionHandler标记。继承该类并重写对应方法时,Spring会优先使用你自定义的逻辑,无需重复添加@ExceptionHandler,否则会与父类的处理逻辑产生映射冲突。
内容的提问来源于stack exchange,提问作者Nitin Gangwar

