RestController 中 MethodArgumentNotValidException 的 Spring Boot ExceptionHandler 永远不会被调用

Posted

技术标签:

【中文标题】RestController 中 MethodArgumentNotValidException 的 Spring Boot ExceptionHandler 永远不会被调用【英文标题】:Spring Boot ExceptionHandler for MethodArgumentNotValidException in RestController never gets invoked 【发布时间】:2021-05-27 23:15:44 【问题描述】:

我正在使用 Spring Boot v2.2.10 和 Spring v5.2.9。我创建了一个带有 @Valid @RequestBody 注释的 Rest 控制器。验证工作正常(我在提交约束之外的值时收到400 BAD REQUEST 响应),但我不喜欢默认错误消息,因为它揭示了太多内部信息。因此,我定义了一个@ExceptionHandler(MethodArgumentNotValidException.class) 方法,但是这个方法永远不会被调用。

这是带有异常处理程序的控制器:

import java.util.List;
import java.util.stream.Collectors;

import javax.validation.Valid;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import lombok.RequiredArgsConstructor;


@RestController
@RequiredArgsConstructor
@RequestMapping("/api/data")
public class DataController 

    @PostMapping(path = "/id", consumes = MediaType.APPLICATION_JSON_VALUE)
    private void postData(
            @PathVariable String id,
            @Valid @RequestBody MyDTO dto) 
        
        // DO SOMETHING

    
    
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public List<String> handleValidationExceptions(MethodArgumentNotValidException ex) 
        System.out.println("Handling method argument not valid exception");
        return ex.getBindingResult()
            .getAllErrors().stream()
            .map(ObjectError::getDefaultMessage)
            .collect(Collectors.toList());
     

DTO:

import javax.validation.constraints.Max;
import lombok.Getter;

@Getter
public class MyDTO 
    
    @Max(value = 1, message = "Value should not be greater than 1")
    private float value;
    

我还尝试将ExceptionHandler 放入一个额外的类中:

// Imports

@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
public class GlobalExceptionHandler 

    @ExceptionHandler(MethodArgumentNotValidException.class)
    // Same as before


正如我所说,我的ExceptionHandler 永远不会被调用。我可能做错了什么?

【问题讨论】:

【参考方案1】:

尝试从类 ResponseEntityExceptionHandler 扩展并覆盖 handleMethodArgumentNotValid

@Order(Ordered.HIGHEST_PRECEDENCE)
@ControllerAdvice
@Slf4j
public class ExceptionController extends ResponseEntityExceptionHandler 

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
        HttpHeaders headers, HttpStatus status, WebRequest request) 
    return ...;

【讨论】:

你的意思是来自 Spring MVC 的 ResponseEntityExceptionHandler 吗?我没有在我的项目中使用 Spring MVC。 @AnjaM Spring Boot 在底层使用 Spring MVC 或 Spring WebFlux 来处理与 Web 相关的事情。在您的代码示例中,您似乎正在使用 Spring MVC @MaciejWalkowiak 抱歉,我是新手,所以我不太了解它是如何工作的。我们在我们的项目中使用了很多 WebFlux(虽然没有在这个特定的 Controller 中),并且 pom.xml 中没有 Spring MVC。当我插入import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler 时,Eclipse 告诉它无法解析org.springframework.web.servlet。如果我将 Spring MVC 添加到 pom.xml 并尝试启动项目,我会得到一个 ClassNotFoundException for javax.servlet.ServletException

以上是关于RestController 中 MethodArgumentNotValidException 的 Spring Boot ExceptionHandler 永远不会被调用的主要内容,如果未能解决你的问题,请参考以下文章

Spring 注解中@RestController与@Controller的区别

Spring 注解中@RestController与@Controller的区别

Spring 注解中@RestController与@Controller的区别

在 @RestController 方法中限制并行请求的最佳方法

@RestController无法自动注入的问题

Spring中@Controller和@RestController之间的区别