在 Spring Boot 应用程序启动时,为 MethodArgumentNotValidException 映射不明确的 @ExceptionHandler 方法

问题描述 投票:0回答:5

我已经为我的一个 Spring 控制器编写了自定义异常处理程序类,以验证请求参数中的电子邮件属性是否采用正确的格式。因此创建了一个扩展

ResponseEntityExceptionHandler
类的新类,并使用
@ExceptionHandler
编写了一个方法。

但是在 Spring Boot 应用程序启动期间,我遇到了以下异常,该异常正在停止运行我的项目。有人可以帮我解决这个问题吗?

服务器启动时出现异常:

org.springframework.beans.factory.BeanCreationException:创建类路径资源中定义的名为“handlerExceptionResolver”的bean时出错[org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]:通过工厂方法实例化Bean失败;
嵌套异常是 org.springframework.beans.BeanInstantiationException:无法实例化 [org.springframework.web.servlet.HandlerExceptionResolver]:工厂方法“handlerExceptionResolver”抛出异常;
嵌套异常是 java.lang.IllegalStateException: 映射为 [class org.springframework.web.bind.MethodArgumentNotValidException] 的不明确 @ExceptionHandler 方法: {public com.TestVO com.handler.exception.TestExceptionHandler.methodArgumentNotValidException(org.springframework.web.bind) .MethodArgumentNotValidException),公共最终org.springframework.http.ResponseEntity org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler.handleException(java.lang.Exception,org.springframework.web.context.request.WebRequest)抛出java.lang.Exception}

自定义类来处理

MethodArgumentNotValidException

@ControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public ErrorVO processValidationError(MethodArgumentNotValidException ex) {
        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();
        FieldError fieldError = fieldErrors.get(0);
        ErrorVO dto = new ErrorVO(fieldError.getDefaultMessage());
        return dto;
    }
}
java spring spring-boot exceptionhandler
5个回答
74
投票

歧义是因为两个类中都有相同的方法 - @ExceptionHandler - ResponseEntityExceptionHandler、MethodArgumentNotValidException。您需要编写如下重写方法来解决此问题 -

   @Override
   protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                 HttpHeaders headers, HttpStatus status, WebRequest request) {
          String errorMessage = ex.getBindingResult().getFieldErrors().get(0).getDefaultMessage();
          List<String> validationList = ex.getBindingResult().getFieldErrors().stream().map(fieldError->fieldError.getDefaultMessage()).collect(Collectors.toList());
          LOGGER.info("Validation error list : "+validationList);
          ApiErrorVO apiErrorVO = new ApiErrorVO(errorMessage);
          apiErrorVO.setErrorList(validationList);
          return new ResponseEntity<>(apiErrorVO, status);
   }

25
投票

您在这里遇到的问题是可以预料到的。您正在有效地扩展 Spring

ResponseEntityExceptionHandler
,默认情况下它已经在其自己的
MethodArgumentNotValidException
注释中包含
@ExceptionHandler
的声明。

您可以从课程的来源轻松检查这一点:

https://github.com/spring-projects/spring-framework/blob/master/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ResponseEntityExceptionHandler.java

这就是您在日志中看到这一点错误的原因:

java.lang.IllegalStateException: Ambiguous @ExceptionHandler method mapped for [class org.springframework.web.bind.MethodArgumentNotValidException]

基于上述所有内容,您应该删除自己的异常处理程序方法并覆盖其中的方法。


8
投票

Spring 有一个内置的

ResponseEntityExceptionHandler
来表示
MethodArgumentNotValidException
。所以你有两个处理程序来处理同一个异常,这是不允许的。

您可以尝试覆盖

ResponseEntityExceptionHandler.handleMethodArgumentNotValid()


1
投票

我找到了解决这个问题的方法!

我将 Rest 控制器的 @ControllerAdvice 注释更改为 @RestControllerAdvice。

Spring boot 和 ControllerAdvice 结构已经包含 MethodArgumentNotValidException。然后我通过 intellij idea / 或不同的 ide 调用覆盖方法来覆盖默认情况下的 MethodArgumentNotValidExcetion 函数。

并且成功了! :) 希望对您有帮助! :)

示例

@Override
@ResponseStatus
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {

    for (ObjectError methodArgumentNotValidException : ex.getBindingResult().getAllErrors()){
        localerrorEntitiesList.add(new ErrorEntity(methodArgumentNotValidException.getDefaultMessage(),methodArgumentNotValidException.getCode()));
    }

    try {
        return new ResponseEntity<>(new ErrorResponse(localerrorEntitiesList),HttpStatus.BAD_REQUEST);
    }catch (Exception e){
        return new ResponseEntity<>(new ErrorResponse(localerrorEntitiesList),HttpStatus.BAD_REQUEST);
    }

}

0
投票

Spring Boot 3 更新。

如果您要扩展

ResponseEntityExceptionHandler
类并重写其方法,则不应使用
@ExceptionHandler
注释。

否则 Spring 的

org.springframework.web.servlet.HandlerExceptionResolver
会为同一个异常类找到多个处理程序并报告错误。

这对于仅处理这些异常而不覆盖处理程序方法的方法也有效。即使有不同的签名和/或在不同的类中也不会扩展

ResponseEntityExceptionHandler
。此处列出了例外情况:

@ExceptionHandler({
    HttpRequestMethodNotSupportedException.class,
    HttpMediaTypeNotSupportedException.class,
    HttpMediaTypeNotAcceptableException.class,
    MissingPathVariableException.class,
    MissingServletRequestParameterException.class,
    MissingServletRequestPartException.class,
    ServletRequestBindingException.class,
    MethodArgumentNotValidException.class,
    HandlerMethodValidationException.class,
    NoHandlerFoundException.class,
    NoResourceFoundException.class,
    AsyncRequestTimeoutException.class,
    ErrorResponseException.class,
    MaxUploadSizeExceededException.class,
    ConversionNotSupportedException.class,
    TypeMismatchException.class,
    HttpMessageNotReadableException.class,
    HttpMessageNotWritableException.class,
    MethodValidationException.class,
    BindException.class
})

解决方案

从处理与

@ExceptionHandler
(上面列出)中相同的异常的方法中删除
ResponseEntityExceptionHandler
注释。对于这些异常,您应该始终重写处理程序方法,而不是定义自己的方法。

© www.soinside.com 2019 - 2024. All rights reserved.