Spring Controller中RequestDTO字段@NotNull验证失效求助
Spring @NotNull验证未生效的原因与解决方法
问题场景
以下是你的代码与请求情况:
Controller代码
@RestController public class CanvasController { @PostMapping("/canvas/pixel") public void placePixel(@Valid @RequestBody final PlacePixelRequest placePixelRequest) { try { canvasManager.placePixel(placePixelRequest); } catch (PixelOutOfBoundsException e) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Coordinates requested are out of bounds"); } } }
请求体类
import javax.validation.constraints.NotNull; @Data @ToString public class PlacePixelRequest { @NotNull private int x; @NotNull private int y; @NotNull private PixelColor pixelColor; @NotNull private String placedBy; }
测试请求
curl --location 'http://localhost:8080/canvas/pixel' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer <TOKEN>' \ --data '{ "x": "0", "y": "5" }'
依赖配置
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency>
现象:即使请求体缺少pixelColor和placedBy必填字段,请求仍返回200 OK,@NotNull验证未生效。
原因分析
基本类型的@NotNull注解无效
int是Java基本类型,默认值为0,永远不可能为null,因此@NotNull注解对基本类型字段完全不起作用,无法触发验证。依赖冲突
spring-boot-starter-validation已经内置了兼容版本的validation-api,手动额外引入指定版本的validation-api会导致依赖冲突,干扰Spring的验证机制正常工作。
解决方法
1. 将基本类型改为包装类
把请求体类中的int字段改为Integer包装类,包装类可以为null,@NotNull注解才能生效:
import javax.validation.constraints.NotNull; @Data @ToString public class PlacePixelRequest { @NotNull private Integer x; // 替换int为Integer @NotNull private Integer y; // 替换int为Integer @NotNull private PixelColor pixelColor; @NotNull private String placedBy; }
2. 移除多余的validation-api依赖
删除pom.xml中手动引入的javax.validation:validation-api依赖,仅保留spring-boot-starter-validation即可:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
3. 可选:添加全局异常处理器(自定义验证响应)
如果需要返回更友好的验证错误信息,可以添加全局异常处理器捕获MethodArgumentNotValidException:
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, String>> handleValidationErrors(MethodArgumentNotValidException ex) { Map<String, String> errorMap = new HashMap<>(); ex.getBindingResult().getAllErrors().forEach(error -> { String fieldName = ((FieldError) error).getField(); String errorMessage = error.getDefaultMessage(); errorMap.put(fieldName, errorMessage); }); return new ResponseEntity<>(errorMap, HttpStatus.BAD_REQUEST); } }
内容的提问来源于stack exchange,提问作者Shubham Dhingra
相关产品推荐
相关产品推荐

