初步认识

spring数据验证核心类:①:Validator ②:Errors,两者之间的纽带是Validator中定义的validate方法。

public interface Validator {// 限定Validator的职责,不可能所有的校验全部交给一个Validator来做boolean supports(Class<?> clazz);// 将target校验错误信息放入Errors中void validate(Object target, Errors errors);
}

简单使用

@Data
public class Customer {private String name;private String sex;private PhoneNumber phoneNumber;
}
@Data
public class PhoneNumber {private String number;private String areaCode;
}
public class CustomerValidator implements Validator {private PhoneNumberValidator phoneNumberValidator;@Overridepublic boolean supports(Class<?> aClass) {return ClassUtils.isAssignable (aClass,Customer.class);}@Overridepublic void validate(Object target, Errors errors) {Customer customer = (Customer) target;// 最后一个参数可以替换掉messages_zh_CN.properties中对应errorCode消息中的占位符ValidationUtils.rejectIfEmpty (errors,"name","name.empty",new Object[]{1,2});ValidationUtils.rejectIfEmpty (errors,"sex","sex.empty");PhoneNumber phoneNumber = customer.getPhoneNumber ();// 这里涉及到嵌套校验,需要改变校验对象的上下文路径// 这个名称并不是随便写的,和你声明的对象名称一致就好了,如果是list,比如List<PhoneNumber> // phoneNumbers ;那么这里就变成循环校验,上下文路径就应该是phoneNumbers[i],i是循环变量,1,2,3...errors.pushNestedPath ("phoneNumber");ValidationUtils.invokeValidator (phoneNumberValidator,phoneNumber,errors);errors.popNestedPath ();}public void setPhoneNumberValidator(PhoneNumberValidator phoneNumberValidator) {this.phoneNumberValidator = phoneNumberValidator;}
}
public class PhoneNumberValidator implements Validator {@Overridepublic boolean supports(Class<?> aClass) {return ClassUtils.isAssignable (aClass,PhoneNumber.class);}@Overridepublic void validate(Object target, Errors errors) {PhoneNumber phoneNumber = (PhoneNumber) target;if(phoneNumber == null)errors.reject ("PhoneNumber is null");if(!StringUtils.isNumeric (phoneNumber.getAreaCode ()))errors.rejectValue ("areaCode","areaCode.numeric","areaCode cannot be empty");if(!StringUtils.isNumeric (phoneNumber.getNumber ()))errors.rejectValue ("number","number.numeric");}
}
public class TestDemo {public static void main(String[] args) {CustomerValidator customerValidator = new CustomerValidator ();customerValidator.setPhoneNumberValidator (new PhoneNumberValidator ());ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource ();messageSource.setBasename ("messages");Customer customer = new Customer ();PhoneNumber phoneNumber = new PhoneNumber ();customer.setPhoneNumber (phoneNumber);BindException errors = new BindException (customer, "customer");ValidationUtils.invokeValidator (customerValidator,customer,errors);if(errors.hasErrors ()){List<ObjectError> allErrors = errors.getAllErrors ();for (int i = 0; i < allErrors.size (); i++) {String message = messageSource.getMessage (allErrors.get (i).getCode (), allErrors.get (i).getArguments (), Locale.CHINA);System.out.println (message);}}}
}



当然在spring中,我们没有必要自己去定义Validator,它给我们提供了相关的实现类LocalValidatorFactoryBean。

但是它并未帮助我们实现校验的相关逻辑,想想也不可能嘛,它咋知道我们想要怎样的校验,于是它委托其他类来实现,同时我们也不需要自己绑定消息源了,我们只要告诉消息源的位置就可以了。
这里委托校验的类很关键,而已知的hibernate校验框架就可以实现这个功能,它内置了很多的约束校验器,我们只需通过注解就能完成对应的校验功能,当然也可以自定义,这个放在后面讲。
springMVC中我们可以这么配置:

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"><property name="providerClass" value="org.hibernate.validator.HibernateValidator"/><property name=''validationMessageSource'' value=""/>
</bean>

其实我们在pom.xml中引入了hibernate-validator的jar包后,provideClass这个属性我们可以不用配置,LocalValidatorFactoryBean在初始化的时候,如果发现provideClass未配置,会去jar包中找。所以如果使用springBoot,我们完全可以不用进行配置,当然如果需要指定消息源,则需要进行相关配置了。

@Configuration
public class CustomConfiguration {@Beanpublic MessageSource messageSource() {ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();messageSource.setBasenames("classpath:/messages");messageSource.setUseCodeAsDefaultMessage(false);messageSource.setCacheSeconds((int) TimeUnit.HOURS.toSeconds(1));messageSource.setFallbackToSystemLocale(false);return messageSource;}@Beanpublic LocalValidatorFactoryBean validator() {LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();factoryBean.setValidationMessageSource(messageSource());return factoryBean;}
}

自定义约束校验器

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Constraint(validatedBy = NotXListValidator.class)
public @interface NotXList {String message() default "Should not be X";Class<?>[] groups() default {};Class<? extends Payload>[] payload() default {};
}
public class NotXListValidator implements ConstraintValidator<NotXList, List<String>> {@Overridepublic void initialize(NotXList constraintAnnotation) {}@Overridepublic boolean isValid(List<String> list, ConstraintValidatorContext context) {boolean valid = true;for (int i = 0; i < list.size(); i++) {if ("X".equals(list.get(i))) {valid = false;}}return valid;}
}
  public class ListContainer {@NotXListprivate List<String> list = new LinkedList<>();public void addString(String value) {list.add(value);}public List<String> getList() {return list;}public static void main(String[] args) {LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();validator.afterPropertiesSet();ListContainer listContainer = new ListContainer();listContainer.addString("A");listContainer.addString("X");BeanPropertyBindingResult errors = new BeanPropertyBindingResult(listContainer, "listContainer");validator.validate(listContainer, errors);}
}

一些简单的校验器Hibernate校验框架已经提供了,大家可以参考,我用的6.0.20的包,都位于org.hibernate.validator.internal.constraintvalidators.bv包下面。

请求参数的校验

// 使用@Valid或者@Validated将会对请求参数进行校验
@Controller
@RequestMapping("/test")
public class ValidationTestController {@ResponseBody@RequestMapping("/test1")public String test1(@Valid User user){return "test1";}
}

原理:请求参数在解析的过程中会进行校验,下面是校验的逻辑

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {Annotation[] annotations = parameter.getParameterAnnotations();for (Annotation ann : annotations) {Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class);if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) {Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann));Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});binder.validate(validationHints);break;}}}

方法校验

public interface MyValidInterface<T> {@NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2);T myGenericMethod(@NotNull T value);
}
// 这个注解一定要有,不然不起作用
@Validated
@Service
public  class MyValidBean implements MyValidInterface<String> {@Overridepublic Object myValidMethod(String arg1, int arg2) {return (arg2 == 0 ? null : "value");}@Overridepublic String myGenericMethod(String value) {return value;}
}

springBoot中

@Controller
public class ValidController{@Autowiredprivate MyValidBean validBean;@RequestBody@RequestMapping("/valid")public String testValid(String type,int age){// 这里如果参数不满足指定方法的校验要求,就会报错return validBean.myValidMethod(type,age);}
}

spring中需要配置MethodValidationPostProcessor

<bean id="methodValidationPostProcessor" class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor">
</bean>

MethodValidationPostProcessor的实现原理就是定义了一个切面,这有关springAOP的内容,在这篇博客里面我不打算深入讲解。

有关Validator的内容暂时先写到这里,以后有内容需要补充再记录。

spring之Validator相关推荐

  1. 使用Spring的Validator接口进行校验

    你可以使用Spring提供的validator接口进行对象的校验.Validator接口与Errors协同工作,在Spring做校验的时候,它会将所有的校验错误汇总到Errors对象中去. 来看这个简 ...

  2. Spring Boot validator参数验证restful自定义错误码响应

    2019独角兽企业重金招聘Python工程师标准>>> 关于spring web应用中关于如何使用 Bean Validation API和hibernate-validator的文 ...

  3. Spring验证示例 - Spring MVC Form Validator

    Spring验证示例 - Spring MVC Form Validator 当我们在任何Web应用程序中接受用户输入时,就有必要对它们进行验证.我们可以使用JavaScript验证客户端的用户输入, ...

  4. 70.打印所有Spring boot载入的bean【从零开始学Spring Boot】

    [从零开始学习Spirng Boot-常见异常汇总] 问题的提出: 我们在开发过程当中,我们可能会碰到这样的问题:No qualifying bean  就是我们定义的bean无法进行注入,那到底是什 ...

  5. 64.JPA命名策略【从零开始学Spring Boot】

    [从零开始学习Spirng Boot-常见异常汇总] 在(39.2). Spring Boot Shiro权限管理[从零开始学Spring Boot] 这一章节中有人碰到这样一个问题"导入的 ...

  6. 17、Spring Boot普通类调用bean【从零开始学Spring Boot】

    转载:http://blog.csdn.net/linxingliang/article/details/52013017 我们知道如果我们要在一个类使用spring提供的bean对象,我们需要把这个 ...

  7. 78. Spring Boot完美使用FastJson解析JSON数据【从零开始学Spring Boot】

    [原创文章,转载请注明出处] 个人使用比较习惯的json框架是fastjson,所以spring boot默认的json使用起来就很陌生了,所以很自然我就想我能不能使用fastjson进行json解析 ...

  8. Spring MVC 学习总结(五)——校验与文件上传

    目录 一.Spring MVC验证器Validator 1.1.定义验证器 1.2.执行校验 1.3.在UI中添加错误标签 1.4.测试运行 二.JSR303验证器 2.1.添加hibernate-v ...

  9. Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion

    本篇太乱,请移步: Spring Framework 官方文档学习(四)之Validation.Data Binding.Type Conversion(一) 写了删删了写,反复几次,对自己的描述很不 ...

最新文章

  1. delphi webbrowser 对象不支持_【Python 秘籍】排序不支持原生比较的对象
  2. Android Camera 预览拉伸
  3. Object.keys 及表单清空
  4. 别跟我说测试的坏话...
  5. mycat 编辑schema.xml
  6. java虚拟机之内存分配
  7. oracle biee 11g客户端连接OCI 10g/11g数据源时报错
  8. web app开发利器 - iscroll4 解决方案
  9. WPF中的相关属性含义
  10. 输入输出知识点和问题超全总结(持续更新中)
  11. 金融项目app业务及测试策略
  12. 当年,我为何关停了亲手创建的“北京圣思园”
  13. 美丽杭州,魅力杭州:弘阳地产水城新时代
  14. 【笔记】程序性能优化28个策略原则
  15. 像元二分模型计算植被覆盖度
  16. 华为云访问密钥AK\SK获取
  17. 传输层的重要协议——TCP
  18. 安卓棉花糖动态权限适配
  19. 固态硬盘量产复活记(慧荣SM2256K+H27QFG8PEM5R)
  20. js生日计算年龄_js 根据出生日期计算年龄

热门文章

  1. 深入理解UE4宏定义—— GENERATED_BODY
  2. Android时间轴(Timeline)效果的实现
  3. python for循环读取excel表格
  4. 关于Busybox镜像
  5. Android AlertDialog对话框不能阻塞进程
  6. Win10 Windows Defender 删不掉的1个威胁
  7. phpstudy(apache)shtml语法配置支持include包含步骤
  8. 直播预约有奖| 高级咨询顾问徐雁斐:效能度量如何助力高效精细的外包管理
  9. 计算机屏幕截图怎么操作,电脑屏幕截图怎么弄?
  10. 香橙派Orange Pi Zero2开发板使用USB摄像头的方法(安卓镜像)