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

Spring Boot请求参数校验问题:@NotNull注解未生效

问题:@NotNull注解在Spring Boot请求参数校验中未生效

我尝试为REST端点的请求参数添加校验,发现@NotBlank注解可以正常触发ConstraintViolationException异常,但@NotNull注解未生效。

代码示例

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.springframework.http.ResponseEntity;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/test")
@Validated
class MyController{

    @GetMapping(value = "/data", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<Data> getData(
         @RequestParam @NotNull(message = "age is required") Integer age,
         @RequestParam @NotBlank(message = "name is required") String name){
           
         //do something  
     }
}

使用依赖

implementation 'org.springframework.boot:spring-boot-starter-validation'

测试情况(Postman)

  • http://localhost:8080/myApp/test/data?age=&name='myname' - 未抛出ConstraintViolationException
  • http://localhost:8080/myApp/test/data?age=null&name='myname' - 未抛出ConstraintViolationException
  • http://localhost:8080/myApp/test/data?name='myname' - 未抛出ConstraintViolationException
  • http://localhost:8080/myApp/test/data?age=22&name='' - 抛出ConstraintViolationException

使用环境

Java 17、Spring Boot 2.7.7

请问我可能遗漏了什么?


解答

这是Spring处理@RequestParam参数的类型转换逻辑与JSR-380校验注解的触发条件不匹配导致的,具体原因和解决方法如下:

1. 核心问题拆解

  • 不传age参数:@RequestParam默认required=false,Spring会直接将age赋值为null,但此时不会触发@NotNull校验——因为@Validated触发的校验是在参数绑定完成后执行,而Spring默认允许非必填参数为null。
  • 传age=:空字符串转换Integer会直接抛出TypeMismatchException,这个异常属于Spring的类型转换异常,会被全局异常处理器优先捕获,根本走不到@NotNull的校验流程。
  • 传age=null:URL中的null是字符串值,转换Integer同样会抛出TypeMismatchException,同样无法触发@NotNull校验。

2. 解决方法

方法一:给@RequestParam添加required=true

结合@NotNull使用,既强制参数必须传递,又校验参数不能为null:

@RequestParam(required = true) @NotNull(message = "age is required") Integer age

此时不传age会先抛出MissingServletRequestParameterException,若参数传递后为合法的null值(如通过其他绑定方式传入),则会触发@NotNull的校验异常。

方法二:处理类型转换异常

自定义全局异常处理器,捕获TypeMismatchException,针对age这类数值型参数,抛出类似校验失败的提示,统一异常返回格式:

@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(TypeMismatchException.class)
    public ResponseEntity<String> handleTypeMismatch(TypeMismatchException e) {
        String paramName = ((ServletRequestBindingException) e).getParameterName();
        if ("age".equals(paramName)) {
            return ResponseEntity.badRequest().body("age is required and must be a valid integer");
        }
        return ResponseEntity.badRequest().body("Invalid parameter type");
    }
}

补充:注解适用场景区分

  • @NotNull:用于非字符串类型(Integer、Long等),仅校验对象不能为null,不处理类型转换异常。
  • @NotBlank:仅用于字符串,校验字符串不能为null且去除首尾空格后长度大于0,刚好适配字符串空值的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:35:10