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

SpringBoot+Java17中@Valid注解无法校验POJO的问题排查

Spring Boot 请求参数校验不生效问题解决

问题描述

我之前只用过Dropwizard和Java 11,最近在学习Spring和Java 17,想要在POST/PUT请求中对POJO做参数校验。参考示例实现后,本地测试发现校验完全未生效,一开始以为是Records的问题,换成普通Class后依然无法触发校验。

控制器代码

@RestController
public class HelloWorldController {

//... 其他GET接口

  @PostMapping("/userProfile")
  @ResponseStatus(HttpStatus.CREATED)
  public ResponseEntity<UserProfileClass> addUserProfile(@RequestBody @Valid UserProfileClass userProfile) {
    System.out.println("Inserting in the database: " + userProfile);
    return ResponseEntity.ok(userProfile);
  }
}

POJO代码

public class UserProfileClass {

    @NotNull @NotBlank String name;
    @NotBlank @NotNull String address;
    //... getters and setters
}

依赖配置

<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>2.0.1.Final</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

测试请求与结果

发送请求:

POST http://localhost:8080/userProfile
Content-Type: application/json

{
  "name": "some Name"
}

返回结果始终为200状态码,address字段为null也未触发校验,按预期应该返回4XX状态码,请问问题出在哪里?

原因分析

  • 依赖冲突:Java 17搭配的Spring Boot 3.x版本基于Jakarta EE 9+,校验API已从javax.validation迁移到jakarta.validation,手动引入的javax.validation:validation-api会和spring-boot-starter-validation自带的Jakarta版本校验API冲突,导致校验器无法正常加载。
  • 字段访问权限问题:POJO中的字段是默认包访问权限(无修饰符),JSR-380校验框架默认需要能够访问被注解的字段或对应的getter方法,包私有字段可能无法被校验器正确读取注解信息。

解决方案

1. 移除冲突的依赖

删除pom.xml中手动引入的javax.validation:validation-api依赖,spring-boot-starter-validation已经包含了适配当前Spring Boot版本的校验API(Jakarta版本)。

2. 调整POJO的字段访问权限与注解位置

将POJO字段改为private,并确保getter/setter方法存在,注解可以放在字段上(推荐)或者getter方法上,示例:

public class UserProfileClass {

    @NotNull
    @NotBlank
    private String name;

    @NotNull
    @NotBlank
    private String address;

    // 标准getter和setter方法
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

3. (可选)添加全局异常处理器(增强错误返回)

如果需要自定义校验失败的返回格式,可以添加全局异常处理器捕获MethodArgumentNotValidException:

@RestControllerAdvice
public class ValidationExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<Map<String, String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach(error -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
    }
}

验证步骤

修改后重新启动服务,发送同样的测试请求,此时应该返回400 Bad Request,并携带校验错误信息,说明校验已生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:08:18