本文主要是介绍Spring常见错误之Web嵌套对象校验失效解决办法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
《Spring常见错误之Web嵌套对象校验失效解决办法》:本文主要介绍Spring常见错误之Web嵌套对象校验失效解决的相关资料,通过在Phone对象上添加@Valid注解,问题得以解决,需要的朋...
问题复现
当开发一个学籍管理系统时,我们会提供了一个 API 接口去添加学生的相关信息,学生中有个嵌套属性联系电话,其对象定义参考下面的代码:
import lombok.Data; import Javax.validation.constraints.Size; @Data public class Student { @Size(max = 10) private String name; private short age; private Phone phone; } @Data class Phone { @Size(max = 10) private String number; }
这里我们也给 Phone 对象做了合法性要求(@Size(max = 10)),当我们使用下面的请求(请求 body 携带一个联系电话信息超过 10 位),测试校验会China编程发现这个约束并不生效。
定义完对象后,我们再定义一个 Controller 去使用它,使用方法如下:
import lombok.extern.slf4j.Slf4j;
import org.springframewww.chinasem.cnwork.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
@Validated
public class StudentController {
@RequestMapping(path = "students", method = RequestMethod.POST)
public void addStudent(@Validated @RequestBody Student student){
log.info("add new student: {}", student.toString());
//省略业务代码
};
}
我们提供了一个支持学生信息添加的接口。启动服务后,使用 IDEA 自带的 HTTP Client 工具来发送下面的请求以添加一个学生:
POST http://localhost:8080/students Content-Type: application/json { "name": "xiaoming", "age": 10, "phone": {"number":"12306123061230612306"} }
发现校验器并没有生效。
案例解析
关于 student 本身的 Phone 类型成员是否校验是在校验过程中(即案例 1 中的代码行 binder.validate(validationHints))决定的。
在校验执行时,首先会根据 Student 的类型定义找出所有的校验点,然后对 Student 对象实例执行校验,这个逻辑过程可以参考代码 ValidatorImpl#validate:
@Override public final <T> Set<ConstraintViolation<T>> validate(T object, Class<?>... groups) { //省略部分非关键代码 Class<T> rootBeanClass = (Class<T>) object.getClass(); //获取校验对象类型的“信息”(包含“约束”) BeanMetaData<T> rootBeanMetaData = beanMetaDataManager.getBeanMetaData( rootBeanClass ); if ( !rootBeanMetaData.hasConst编程raints() ) { return Collections.emptySet(); } //省略部分非关键代码 //执行校验 return validateInContext( validationContext, valueContext, validationOrder ); }
这里语句"beanMetaDataManager.getBeanMetaData( rootBeanClass )"根据 Student 类型组装出 BeanMetaData,BeanMetaData 即包含了需要做的校验(即 Constraint)。
在组装 BeanMetaData 过程中,会根据成员字段是否标记了 @Valid 来决定(记录)这个字段以后是否做级联校验,参考代码 AnnotationMetaDataProvider#getCascadingMetaData:
private CascadingMetaDataBuilder getCascadingMetaData(Type type, AnnotatedElement annotatedElement, Map<TypeVariable<?>, CascadingMetaDataBuilder> containerElementTypesCascadingMetaData) { return CascadingMetaDataBuilder.annotatedObject( type, annotatedElement.isAnnotationPresent( Valid.class ), containerElementTypesCascadingMetaData, getGroupConversions( annotatedElement ) ); }
在上述代码中"annotatedElement.isAnnotationPresent( Valid.class )"决定了 CascadingMetaDataBuilder#cascading 是否为 true。如果是,则在后续做具体校验时,做级联校验,而级联校验的过程与宿主对象(即 Student)的校验过程大体相同,即先根据对象类型获取定义再来做校验。
在当前案例代码中,phone 字段并没有被 @Valid 标记,所以关于这个字段信息的 cascading 属性肯定是 false,因此在校验 Student 时并不会级联校验它。
问题修正
从源码级别了解了嵌套 Validation 失败的原因后,我们会发现,要让嵌套校编程验生效,解决的方法只有一种,就是加上 @Valid,javascript修正代码如下:
@Valid private Phone phone;
当修正完问题后,我们会发现校验生效了。而如果此时去调试修正后的案例代码,会看到 phone 字段 MetaData 信息中的 cascading 确实为 true 了,参考下图:
总结
到此这篇关于Spring常见错误之Web嵌套对象校验失效解决办法的文章就介绍到这了,更多相关Spring Web嵌套对象校验失效内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程China编程(www.chinasem.cn)!
这篇关于Spring常见错误之Web嵌套对象校验失效解决办法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!