spring之Validator

article/2025/10/6 20:09:17

初步认识

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的内容暂时先写到这里,以后有内容需要补充再记录。


http://chatgpt.dhexx.cn/article/Exo1vmnx.shtml

相关文章

Hibernate-Validator的学习

Hibernate-Validator的学习 此教程基于黑马程序员Java品达通用权限项目&#xff0c;哔哩哔哩链接&#xff1a;https://www.bilibili.com/video/BV1tw411f79E?p49 1.hibernate-validator介绍 早期的网站&#xff0c;用户输入一个邮箱地址&#xff0c;需要将邮箱地址发送到服…

Hibernate Validator源码解析

一、引言 问题&#xff1a;在代码编写的过程中&#xff0c;数据值的校验在JavaEE三层架构&#xff08;展示层、业务层、数据访问层&#xff09;均有涉及&#xff0c;各层的校验需求又是不尽相同的&#xff0c;因此往往会伴随着代码冗余&#xff0c;重复的校验逻辑出现在三层代…

Hibernate Validator简介

亲爱的小伙伴们我来填坑啦&#xff0c;java中优雅的参数校验方法中的校验的实现原理。 1.前言 验证数据是发生在所有应用程序层&#xff08;从表示层到持久层&#xff09;的常见任务。通常在每一层中实现相同的验证逻辑&#xff0c;这既耗时又容易出错。为了避免重复这些验证&…

bootstrapValidator验证最大值最小值范围限制

录入该值的最大值与最小值 bootstrapValidator进行效验&#xff0c;使最小值不可大于最大值&#xff0c;最大值不可小于最小值 刚开始的验证还是没事的&#xff0c;符合正常的验证规则 再把不符合规则的最大值改变&#xff0c;现在最小值已经比最大值小了&#xff0c;但是最大…

class-validator中文教程

官方文档&#xff1a; https://www.npmjs.com/package/class-validator class-validator可以说是一个简化验证的依赖库 &#xff08;采用注释的方式进行校验&#xff09; 但是缺少中文文档和过程&#xff0c;以自己的理解和对官网文档的阅读进行整理输出。 它的好兄弟class-t…

Hibernate Validator 总结大全

背景 代码开发过程中&#xff0c;参数的有效性校验是一项很繁琐的工作&#xff0c; 如果参数简单&#xff0c;就那么几个参数&#xff0c;直接通过ifelse可以搞定&#xff0c;如果参数太多&#xff0c;比如一个大对象有100多个字段作为入参&#xff0c;你如何校验呢&#xff1…

java使用validator进行校验

不管是html页面表单提交的对象数据还是和第三方公司进行接口对接&#xff0c;都需要对接收到的数据进行校验&#xff08;非空、长度、格式等等&#xff09;。如果使用if一个个进行校验&#xff08;字段非常多&#xff09;&#xff0c;这是让人崩溃的过程。幸好jdk或hibernate都…

java validator_Spring中校验器(Validator)的深入讲解

前言 Spring框架的 validator 组件,是个辅助组件,在进行数据的完整性和有效性非常有用,通过定义一个某个验证器,即可在其它需要的地方,使用即可,非常通用。 应用在执行业务逻辑之前,必须通过校验保证接受到的输入数据是合法正确的,但很多时候同样的校验出现了多次,在不…

springboot使用hibernate validator校验

目录 一、参数校验二、hibernate validator校验demo三、hibernate的校验模式 1、普通模式&#xff08;默认是这个模式&#xff09;2、快速失败返回模式四、hibernate的两种校验 1、请求参数校验2、GET参数校验(RequestParam参数校验)3、model校验4、对象级联校验5、分组校验五…

Validator 使用总结

介绍 首先说下大家常用的hibernate-validator&#xff0c;它是对JSR-303/JSR-349标准的实现&#xff0c;然后spring为了给开发者提供便捷集成了hibernate-validator&#xff0c;默认在springmvc模块。 依赖 本文所介绍皆在springboot应用的基础上&#xff0c;首先加上web模块…

浅谈 Android Tombstone(墓碑日志)分析步骤

最近项目产品刚刚出货&#xff0c;客户退机、死机事件频发。日常解决bug中&#xff0c;少不了和墓碑日志打交道&#xff0c;截止今天之前&#xff0c;见到墓碑日志都是一脸懵逼&#xff0c;不知道怎么分析。最近又有了两个日志&#xff0c;硬着头皮看吧。之所以称之为浅谈&…

Android tombstone文件是如何生成的

本节内容我们聚焦到androidQ上&#xff0c;分析android中一个用于debug的功能&#xff0c;那就是tombstone&#xff0c;俗称“墓碑”。现实生活中墓碑一般是给死人准备的&#xff0c;而在android系统中“墓碑”则是给进程准备的。 为何Android要设计出这样一个东西呢&#xff…

【Android NDK 开发】NDK C/C++ 代码崩溃调试 - Tombstone 报错信息日志文件分析 ( 获取 tombstone_0X 崩溃日志信息 )

文章目录 一、崩溃信息描述二、手机命令行操作三、电脑命令行操作四、Tombstone 内容 Tombstone 报错信息日志文件被保存在了 /data/tombstones/ 目录下 , 先 ROOT 再说 , 没有 ROOT 权限无法访问该目录中的信息 ; 使用 Pixel 2 手机进行调试 , 其它 ROOT 后的手机也可以使用 …

Android tombstone 分析案例

Android tombstone 分析案例 tombstone文件内容1. 体系结构2. 发生Crash线程3. 原因4. 寄存器状态4.1 处理器工作模式下的寄存器4.2 未分组寄存器r0 – r74.3 分组寄存器r8 – r144.4 程序计数器pc(r15)4.5 程序状态寄存器4.6 ARM参数规则 5. 回溯栈6. 程序栈7. 寄存器地址附近…

RocksDB Tombstone 详解

目录 为什么会有墓碑&#xff1f; 使用场景 原理 描述 分段 查询 优化点 总结 为什么会有墓碑&#xff1f; 我们知道 TP 数据库一般选择 KV 引擎作为存储引擎&#xff0c;数据库的元数据和数据通过一定的编码规则变成 KV 对存储在存储引擎中&#xff0c;比如 CockroachD…

Tombstone 文件分析

Tombstone 文件分析 /* * 下面信息是dropbox负责添加的 **/ isPrevious: true Build: Rock/odin/odin:7.1.1/NMF26F/1500868195:user/dev-keys Hardware: msm8953 Revision: 0 Bootloader: unknown Radio: unknown Kernel: Linux version 3.18.31-perf-g34cb3d1 (smartcmhardc…

android Tombstone 流程

一 总述 下面是一份dump 的log&#xff1a; 810 876 I system_server: libdebuggerd_client: started dumping process 678 740 740 I /system/bin/tombstoned: registered intercept for pid 678 and type kDebuggerdNativeBacktrace 678 678 I libc : Requested du…

android tombstone log分析

今天和大家一起聊聊android 中出现的 Tombstone问题&#xff0c;近期在定制pad 上分析设备概率性重启&#xff0c;导出bugreport日志后&#xff0c;除了看到anr log外&#xff0c;同级目录下还看到了tombstones 并且对比以往日志&#xff0c;发现都生产了大量tombstone...,于是…

深入学习tombstone和signal

三驾马车&#xff08;CPU&#xff0c;内存和存储设备&#xff09;中&#xff0c;跑得最慢的就是存储设备了 电脑上&#xff0c;从HDD 到SSD&#xff0c;从SATA SSD到PCIe SSD&#xff0c;硬盘是越来越快&#xff1b; 手机上&#xff0c;从SD卡&#xff0c;到eMMC卡&#xff0…

tombstone

1.什么是tombstone 当一个动态库&#xff08;native 程序&#xff09;开始执行时&#xff0c;系统会注册一些连接到 debuggerd 的 signal handlers&#xff0c;当系统 crash 的时候&#xff0c;会保存一个 tombstone 文件到/data/tombstones目录下&#xff08;Logcat中也会有相…