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

RestController中@Valid注解始终返回200状态码问题求助

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

在Spring Boot 3.1.3项目中,按教程在@RequestBody前添加@Valid注解实现请求参数校验,但实际请求始终返回200/201状态码,JUnit测试却能正常校验约束。即使添加BindingResult参数,其错误数也显示为0。

DTO类

package practice.corejava.validators.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Positive;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class UserData {

    @NotBlank(message = "Name should not be blank")
    private String name;

    @NotNull(message = "Age should not be null")
    @Positive(message = "Age should be positive")
    private Integer age;

}

Controller类(Postman请求始终返回201)

package practice.corejava.validators.controller;

import practice.corejava.validators.dto.UserData;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
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.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import jakarta.validation.Valid;

import java.net.URI;

@RestController
@RequestMapping("api/v1/validations")
public class ValidationsController {

    @PostMapping(value = "/user-data", consumes = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<UserData> createUserData(@Valid @RequestBody UserData userData) {
        URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{name}").buildAndExpand(userData.getName()).toUri();
        return ResponseEntity.created(location).build();
    }

}

JUnit测试类(测试用例执行成功)

package practice.corejava.validators.dto;

import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
import jakarta.validation.ValidatorFactory;
import java.util.Set;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class UserDataTest {

    private static Validator validator;

    @BeforeAll
    public static void setUp() {
        try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
            validator = factory.getValidator();
        }
    }

    @Test
    void all_validation_success() {
        UserData userData = new UserData("SomeName", 30);
        Set<ConstraintViolation<UserData>> constraintViolations = validator.validate(userData);
        assertEquals(0, constraintViolations.size());
    }

    @Test
    void name_blank() {
        UserData userData = new UserData("", 30);
        Set<ConstraintViolation<UserData>> constraintViolations = validator.validate(userData);
        assertEquals(1, constraintViolations.size());
        assertEquals("Name should not be blank", constraintViolations.iterator().next().getMessage());
    }

}

Postman请求体(预期返回400,实际返回201)

{
    "name" : null,
    "age" : 30
}

依赖及版本信息

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.3</version>
    <relativePath/>
</parent>

<properties>
    <java.version>17</java.version>
</properties>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>3.0.2</version>
</dependency>

问题原因及解决方案

1. 依赖冲突问题

手动引入的jakarta.validation-api 3.0.2与spring-boot-starter-validation内置的依赖版本不兼容,导致Spring校验机制无法正常触发。Spring Boot的starter已经包含适配版本的validation-api,无需手动指定。

解决方法:移除手动添加的jakarta.validation-api依赖:

<!-- 删除以下依赖配置 -->
<!-- <dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>3.0.2</version>
</dependency> -->

2. 全局异常处理器检查

若项目存在@RestControllerAdvice或@ControllerAdvice注解的全局异常处理类,可能错误捕获了MethodArgumentNotValidException并返回2xx状态码。可添加自定义校验异常处理:

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>> 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);
    }
}

3. 验证注解导入

确保使用的是jakarta.validation.Valid而非旧版javax.validation.Valid(Spring Boot 3.x基于Jakarta EE规范,不再支持javax包)。

4. 重启测试

修改依赖并重启项目后,再次发送无效请求,应返回400状态码及对应错误信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 19:32:16