Spring @Valid 不生效 问题记录
综上所述,Spring解析@Valid的过程主要涉及到MethodValidationPostProcessor后置处理器,在BeanPostProcessor的postProcessBeforeInitialization方法中生成代理对象,并在方法执行前执行校验注解的过程。在拦截器中,会先获取方法上的校验注解,然后根据注解的类型,调用不同的校验器进行校验。在Controller的方法参数中添加
校验的简单使用:
在Spring中,我们可以使用@Valid注解对实体进行校验。在Controller的方法参数中添加@Valid注解,然后在实体类的属性上添加校验注解,例如@NotNull、@Size等。例如:
@RestController public class UserController { @PostMapping("/users") public ResponseEntity<User> createUser(@Valid @RequestBody User user) { userService.createUser(user); return new ResponseEntity<>(user, HttpStatus.CREATED); } }
在这个例子中,我们使用@Valid注解对User实体进行校验,并在User类的属性上添加了@NotNull和@Size注解。当请求到达Controller时,Spring会自动对User实体进行校验,如果校验失败则会抛出MethodArgumentNotValidException异常。我们可以使用@ControllerAdvice和@ExceptionHandler来处理校验异常,并返回自定义的错误信息。例如:
@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<ErrorResponse> handleValidationException(MethodArgumentNotValidException ex) { BindingResult result = ex.getBindingResult(); List<FieldError> fieldErrors = result.getFieldErrors(); List<String> errors = new ArrayList<>(); for (FieldError fieldError : fieldErrors) { errors.add(fieldError.getField() + ": " + fieldError.getDefaultMessage()); } ErrorResponse errorResponse = new ErrorResponse(HttpStatus.BAD_REQUEST, "Validation failed", errors); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } }
在这个例子中,我们使用@ControllerAdvice注解来定义全局的异常处理器,并使用@ExceptionHandler注解来处理MethodArgumentNotValidException异常。在处理过程中,我们从异常中获取校验结果并转换成自定义的错误信息,然后封装成ErrorResponse对象并返回。如果请求中包含了校验错误,Spring会自动调用该处理器并返回错误信息。
@Valid @Validated 有什么区别
@Valid和@Validated注解都可以用于实体类属性的校验。它们的主要区别在于支持的校验分组和校验器的不同。
@Valid注解只支持默认分组,即没有使用任何分组的校验注解。它使用的是javax.validation包下的校验器。
@Validated注解支持分组校验,即可以使用指定分组的校验注解进行校验。它使用的是Spring自己的校验器,支持JSR-303和JSR-349规范。
此外@Validated 注解还可以用于方法级别的校验,例如:
@Service public class UserService { @Validated public void createUser(@NotNull User user) { //... } }
在这个例子中,我们使用@Validated注解对createUser方法进行校验,并使用@NotNull注解对User参数进行非空校验。如果校验失败,Spring会抛出ConstraintViolationException异常。
Spring 是如何实现校验的
简单理解:
在Spring中,我们可以使用@NotBlank注解对字符串进行非空校验。在实体类的属性上添加@NotBlank注解即可。例如:
public class User { @NotBlank private String username; //... }
在这个例子中,我们使用@NotBlank注解对username属性进行非空校验。当请求到达Controller时,Spring会自动对User实体进行校验,如果校验失败则会抛出MethodArgumentNotValidException异常。
深入理解:
在Spring中,在方法执行前执行校验注解的过程是由MethodValidationInterceptor
拦截器实现的。这个拦截器会在方法调用前执行校验注解,如果校验失败会抛出异常。在拦截器中,会先获取方法上的校验注解,然后根据注解的类型,调用不同的校验器进行校验。如果校验失败,会抛出ConstraintViolationException异常。
MethodValidationInterceptor
会被Spring的其中一个BeanPostProcessor: MethodValidationPostProcessor
在Bean初始化时作为默认的方法校验增强器进行创建。
整体理解:
当Spring框架在执行方法时,会先查找是否存在MethodValidationPostProcessor后置处理器。如果存在,它会在方法执行之前执行校验注解的过程。
MethodValidationPostProcessor后置处理器会在BeanPostProcessor的postProcessBeforeInitialization方法中执行,具体流程如下:
- Spring容器启动时,会扫描所有的BeanDefinition,包括MethodValidationPostProcessor。
- 当容器实例化MethodValidationPostProcessor时,会调用BeanPostProcessor的postProcessBeforeInitialization方法。
- 在postProcessBeforeInitialization方法中,MethodValidationPostProcessor会检查Bean是否包含@Validated注解,并生成一个代理对象。
- 当原始Bean方法被调用时,代理对象会执行校验注解的过程。如果校验失败,会抛出异常。
- 如果代理对象的校验通过,会调用原始Bean方法并返回结果。
综上所述,Spring解析@Valid的过程主要涉及到MethodValidationPostProcessor后置处理器,在BeanPostProcessor的postProcessBeforeInitialization方法中生成代理对象,并在方法执行前执行校验注解的过程。
校验所需的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.7.10</version>
<exclusions>
<exclusion>
<artifactId>spring-boot-starter-logging</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</exclusion>
</exclusions>
</dependency>
如果是SpringBoot项目需要注意判断是否已经存在必须的依赖 spring-boot-starter-validation
,注意如果Spring-boot的版本大于3.0必须最第使用JDK17。上面的依赖版本是3.0以下可用的最高版本。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)