spring开发web项目,都会需要对入参的长度,格式等进行校验,如果将这些都写在代码中,那么代码就会很不美观.validate框架能很好的解决这些和业务无关的校验.
1. 准备.
需要使用valid的框架,需要在项目中引入依赖
// valid 校验框架 implementation group: 'javax.validation', name: 'validation-api', version: '2.0.1.Final' implementation group: 'org.hibernate', name: 'hibernate-validator', version: '7.0.1.Final'
首先需要解释下为什么需要这2个依赖.
javax.validation的依赖中包含了平常发开中经常使用的注解校验.
@Null 限制只能为null @NotNull 限制必须不为null @AssertFalse 限制必须为false @AssertTrue 限制必须为true @DecimalMax(value) 限制必须为一个不大于指定值的数字 @DecimalMin(value) 限制必须为一个不小于指定值的数字 @Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction @Future 限制必须是一个将来的日期 @Max(value) 限制必须为一个不大于指定值的数字 @Min(value) 限制必须为一个不小于指定值的数字 @Past 限制必须是一个过去的日期 @Pattern(value) 限制必须符合指定的正则表达式 @Size(max,min) 限制字符长度必须在min到max之间 @Past 验证注解的元素值(日期类型)比当前时间早 @NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0) @NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格 @Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式
这些注释相关的校验却是写在validator中的
也就是说javax中的validation定义了相关的校验注解和 ConstraintValidator 接口, hibernate则通过实现这个接口来对每一个注解进行校验
了解了相关的工作原理,我们就能很好的模仿它进行相应的开发,比如枚举类的校验.
1. 第一步,先定义需要校验的注解
package com.xdj.robot.annotation; import com.xdj.robot.valid.EnumValidator; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = EnumValidator.class) // 这里必须写上自己编写的validator 不然会抛出找不到校验器的错误 @Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE}) public @interface EnumValid { String message() default ""; // 作用参考@Validated和@Valid的区别 Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; /** * 目标枚举类 */ Class<? extends Enum> value(); /** * 是否忽略空值 */ boolean ignoreEmpty() default true; }
2.编写自己的校验器
package com.xdj.robot.valid; import com.xdj.robot.annotation.EnumValid; import com.xdj.robot.enums.SexEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; @Slf4j @Component public class EnumValidator implements ConstraintValidator<EnumValid, Enum> { private EnumValid annotation; @Override public void initialize(EnumValid constraintAnnotation) { annotation = constraintAnnotation; } @Override public boolean isValid(Enum t, ConstraintValidatorContext constraintValidatorContext) { boolean result = false; Class<?> cls = annotation.value(); boolean ignoreEmpty = annotation.ignoreEmpty(); if (!ignoreEmpty || (cls.isEnum() && t != null)) { Object[] objects = cls.getEnumConstants(); for (Object obj : objects) { // 使用此注解的枚举类需要重写toString方法,改为需要验证的值 if (obj.toString().equals(String.valueOf(t))) { result = true; break; } } }else result = true; return result; } }
3.定义枚举类型和需要校验的实体
package com.xdj.robot.enums; public enum SexEnum { FEMALE, MALE; } package com.xdj.robot.dto; import com.xdj.robot.annotation.EnumValid; import com.xdj.robot.enums.SexEnum; import lombok.Data; import javax.validation.constraints.NotEmpty; import java.math.BigDecimal; @Data public class ValidTableDTO { @NotEmpty(message = "名称不能为空") private String nme; @EnumValid(value = SexEnum.class, message = "性别必须为FEMALE, MALE ") private SexEnum MALE; private BigDecimal money; private String phone; }
4.最后进行校验 验证
{ "code": 9999, "message": "性别必须为FEMALE, MALE ", "data": null }