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

Spring MVC中@Valid注解在Controller的DTO验证中失效问题排查

@Valid注解在非Spring Boot环境下未生效问题

向http://localhost:8080/student发送无效请求时,@Valid注解未生效,无效数据直接进入Controller、Service层级。

相关代码

Controller代码

import org.example.controller.dto.StudentDTO;
import org.example.service.interfaces.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.sql.SQLException;

@RestController
@RequestMapping("/student")
public class StudentController{
    private final StudentService service;

    @Autowired
    public StudentController(StudentService service) {
        this.service = service;
    }

    @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<StudentDTO> doPost(@RequestBody @Valid StudentDTO studentDTO) {
        try {
            StudentDTO studentDTOOut = service.saveNewStudent(studentDTO);
            return new ResponseEntity<>(studentDTOOut, HttpStatus.OK);
        } catch (SQLException e) {
            return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
        } catch (RuntimeException e) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
    }
}

DTO代码

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.UUID;

public class StudentDTO {

    @NotNull
    private UUID id;

    @NotBlank
    private String surname;

    // getters, setters
}

pom.xml核心配置

<properties>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>6.0.9</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>3.1.2</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.orm</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>6.1.7.Final</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.1.7.Final</version>
    </dependency>
    <dependency>
        <groupId>jakarta.validation</groupId>
        <artifactId>jakarta.validation-api</artifactId>
        <version>2.0.2</version>
    </dependency>
    <!-- 其他依赖省略 -->
</dependencies>

已尝试的无效操作

  • 在Controller类上添加@Validated注解
  • 给DTO字段添加@JsonProperty(required = true)
  • 删除@PostMapping的produces属性

疑问

在未使用Spring Boot的情况下,@Valid/@Validated注解是否能够正常工作?


问题分析与解决方案

核心原因

非Spring Boot环境下,Spring WebMvc不会自动配置Bean Validation的相关处理器,且当前依赖存在版本兼容性问题:

  1. Spring 6.x基于Jakarta EE 9+,但使用的jakarta.validation-api是2.0.2(属于Jakarta EE 8),版本不匹配
  2. hibernate-validator 6.1.x仅支持Jakarta Validation 2.0,无法适配Spring 6的规范

修复步骤

  1. 更新依赖版本
    替换为适配Spring 6的验证依赖:

    <!-- Jakarta Validation API 3.0.x(适配Jakarta EE 9) -->
    <dependency>
        <groupId>jakarta.validation</groupId>
        <artifactId>jakarta.validation-api</artifactId>
        <version>3.0.2</version>
    </dependency>
    <!-- Hibernate Validator 8.x(适配Jakarta Validation 3.0) -->
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>8.0.1.Final</version>
    </dependency>
    <!-- 验证注解处理器 -->
    <dependency>
        <groupId>org.hibernate.validator</groupId>
        <artifactId>hibernate-validator-annotation-processor</artifactId>
        <version>8.0.1.Final</version>
    </dependency>
    
  2. 手动配置验证器Bean
    创建Spring配置类,注册验证相关Bean:

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
    import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
    
    @Configuration
    public class ValidationConfig {
        // 全局验证器
        @Bean
        public LocalValidatorFactoryBean validator() {
            return new LocalValidatorFactoryBean();
        }
    
        // 支持@Validated方法级验证
        @Bean
        public MethodValidationPostProcessor methodValidationPostProcessor() {
            MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
            processor.setValidator(validator());
            return processor;
        }
    }
    
  3. 配置Spring MVC验证器
    在WebMvc配置类中绑定验证器:

    import org.springframework.context.annotation.Configuration;
    import org.springframework.validation.Validator;
    import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    
    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {
        private final LocalValidatorFactoryBean validator;
    
        public WebMvcConfig(LocalValidatorFactoryBean validator) {
            this.validator = validator;
        }
    
        @Override
        public Validator getValidator() {
            return validator;
        }
    }
    
  4. 添加全局异常处理器
    捕获验证异常并返回友好响应:

    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.ControllerAdvice;
    import org.springframework.web.bind.annotation.ExceptionHandler;
    
    import java.util.HashMap;
    import java.util.Map;
    
    @ControllerAdvice
    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);
        }
    }
    

验证效果

完成配置后,@Valid会在请求进入Controller方法前触发验证,无效数据会被拦截并抛出异常,不会流转到Service层级。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 17:25:55