You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中@Valid未返回自定义校验消息问题排查

问题场景

我在Spring Boot项目中编写了以下代码:

Controller方法

@PostMapping("/hello")
public Hello hello(@Valid @RequestBody Hello hello) {
    return hello;
}

POJO类

import jakarta.validation.constraints.NotBlank;

class Hello{
    @NotBlank(message = "msg must be present")
    String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

当使用空字符串的msg请求接口时:

{
    "msg":""
}

得到的响应是:

{
    "type": "about:blank",
    "title": "Bad Request",
    "status": 400,
    "detail": "Invalid request content.",
    "instance": "/hello"
}

预期应该返回自定义提示msg must be present,但未生效。

已尝试的操作:

  • 在application.properties添加配置:server.error.include-message: always
  • 添加了ConstraintViolationException的异常处理:
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException e) {
    return new ResponseEntity<Object>("ConstraintViolationException",
            HttpStatus.BAD_REQUEST);
}

发现移除项目中的@RestControllerAdvice后,校验消息能正常返回,但该组件是项目自定义异常处理必需的,需要解决保留@RestControllerAdvice同时返回自定义校验消息的问题。

解决方案

问题出在全局异常处理器没有处理RequestBody参数校验抛出的MethodArgumentNotValidException,你之前只处理了ConstraintViolationException(该异常通常用于URL参数、请求参数的校验,而非RequestBody的JSON参数校验)。

在你的@RestControllerAdvice类中添加针对MethodArgumentNotValidException的处理方法,提取校验失败的自定义消息即可:

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 保留原有的ConstraintViolationException处理(若需保留)
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<Object> handleConstraintViolationException(ConstraintViolationException e) {
        String message = e.getConstraintViolations().stream()
                .map(violation -> violation.getMessage())
                .findFirst()
                .orElse("参数校验失败");
        return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
    }

    // 添加RequestBody参数校验的异常处理
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Object> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 提取第一个校验失败的自定义消息
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .findFirst()
                .orElse("请求体参数校验失败");
        return new ResponseEntity<>(message, HttpStatus.BAD_REQUEST);
    }

    // 其他自定义异常处理方法...
}

如果需要返回和默认格式一致的结构化响应,可以封装错误响应类:

class ErrorResponse {
    private String type = "about:blank";
    private String title = "Bad Request";
    private int status = 400;
    private String detail;
    private String instance;

    public ErrorResponse(String detail, String instance) {
        this.detail = detail;
        this.instance = instance;
    }

    // getter/setter
}

修改异常处理方法返回结构化响应:

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ErrorResponse> handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) {
    String message = e.getBindingResult().getFieldErrors().stream()
            .map(FieldError::getDefaultMessage)
            .findFirst()
            .orElse("请求体参数校验失败");
    ErrorResponse response = new ErrorResponse(message, request.getRequestURI());
    return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}

这样既保留了@RestControllerAdvice的自定义异常处理能力,又能正确返回@NotBlank中定义的提示消息。

内容的提问来源于stack exchange,提问作者Rahul

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 11:25:34