SpringBoot Validation参数校验 详解自定义注解规则和分组校验 (2)

在编写Update分组接口时,如果继承了Default,下面两个写法就是等效的:
@Validated({Update.class}),@Validated({Update.class,Default.class})
如果Update不继承Default,@Validated({Update.class})就只会校验属于Update.class分组的参数字段

递归校验

如果 UserVO 类中增加一个 OrderVO 类的属性,而 OrderVO 中的属性也需要校验,就用到递归校验了,只要在相应属性上增加@Valid注解即可实现(对于集合同样适用)

public class OrderVO { @NotNull private Long id; @NotBlank(message = "itemName 不能为空") private String itemName; // 省略其他代码... } public class UserVO { @NotBlank(message = "name 不能为空",groups = Update.class) private String name; //需要递归校验的OrderVO @Valid private OrderVO orderVO; // 省略其他代码... } 自定义校验

validation 为我们提供了这么多特性,几乎可以满足日常开发中绝大多数参数校验场景了。但是,一个好的框架一定是方便扩展的。有了扩展能力,就能应对更多复杂的业务场景,毕竟在开发过程中,唯一不变的就是变化本身。 Validation允许用户自定义校验

实现很简单,分两步:

自定义校验注解

package cn.soboys.core.validator; import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; /** * @author kenx * @version 1.0 * @date 2021/1/21 20:49 * 日期验证 约束注解类 */ @Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = {IsDateTimeValidator.class}) // 标明由哪个类执行校验逻辑 public @interface IsDateTime { // 校验出错时默认返回的消息 String message() default "日期格式错误"; //分组校验 Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; //下面是我自己定义属性 boolean required() default true; String dateFormat() default "yyyy-MM-dd"; }

注意:message用于显示错误信息这个字段是必须的,groups和payload也是必须的
@Constraint(validatedBy = { HandsomeBoyValidator.class})用来指定处理这个注解逻辑的类

编写校验者类

package cn.soboys.core.validator; import cn.hutool.core.util.StrUtil; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; /** * @author kenx * @version 1.0 * @date 2021/1/21 20:51 * 日期验证器 */ public class IsDateTimeValidator implements ConstraintValidator<IsDateTime, String> { private boolean required = false; private String dateFormat = "yyyy-MM-dd"; /** * 用于初始化注解上的值到这个validator * @param constraintAnnotation */ @Override public void initialize(IsDateTime constraintAnnotation) { required = constraintAnnotation.required(); dateFormat = constraintAnnotation.dateFormat(); } /** * 具体的校验逻辑 * @param value * @param context * @return */ public boolean isValid(String value, ConstraintValidatorContext context) { if (required) { return ValidatorUtil.isDateTime(value, dateFormat); } else { if (StrUtil.isBlank(value)) { return true; } else { return ValidatorUtil.isDateTime(value, dateFormat); } } } }

注意这里验证逻辑我抽出来单独写了一个工具类,ValidatorUtil

package cn.soboys.core.validator; import cn.hutool.core.date.DateUtil; import cn.hutool.core.text.StrFormatter; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; import java.lang.reflect.Method; import java.math.BigDecimal; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * @author kenx * @version 1.0 * @date 2021/1/21 20:51 * 验证表达式 */ public class ValidatorUtil { private static final Pattern mobile_pattern = Pattern.compile("1\\d{10}"); private static final Pattern money_pattern = Pattern.compile("^[0-9]+\\.?[0-9]{0,2}$"); /** * 验证手机号 * * @param src * @return */ public static boolean isMobile(String src) { if (StrUtil.isBlank(src)) { return false; } Matcher m = mobile_pattern.matcher(src); return m.matches(); } /** * 验证枚举值是否合法 ,所有枚举需要继承此方法重写 * * @param beanClass 枚举类 * @param status 对应code * @return * @throws Exception */ public static boolean isEnum(Class<?> beanClass, String status) throws Exception { if (StrUtil.isBlank(status)) { return false; } //转换枚举类 Class<Enum> clazz = (Class<Enum>) beanClass; /** * 其实枚举是语法糖 * 是封装好的多个Enum类的实列 * 获取所有枚举实例 */ Enum[] enumConstants = clazz.getEnumConstants(); //根据方法名获取方法 Method getCode = clazz.getMethod("getCode"); Method getDesc = clazz.getMethod("getDesc"); for (Enum enums : enumConstants) { //得到枚举实例名 String instance = enums.name(); //执行枚举方法获得枚举实例对应的值 String code = getCode.invoke(enums).toString(); if (code.equals(status)) { return true; } String desc = getDesc.invoke(enums).toString(); System.out.println(StrFormatter.format("实列{}---code:{}desc{}", instance, code, desc)); } return false; } /** * 验证金额0.00 * * @param money * @return */ public static boolean isMoney(BigDecimal money) { if (StrUtil.isEmptyIfStr(money)) { return false; } if (!NumberUtil.isNumber(String.valueOf(money.doubleValue()))) { return false; } if (money.doubleValue() == 0) { return false; } Matcher m = money_pattern.matcher(String.valueOf(money.doubleValue())); return m.matches(); } /** * 验证 日期 * * @param date * @param dateFormat * @return */ public static boolean isDateTime(String date, String dateFormat) { if (StrUtil.isBlank(date)) { return false; } try { DateUtil.parse(date, dateFormat); return true; } catch (Exception e) { return false; } } }

我自定义了补充了很多验证器,包括日期验证,枚举验证,手机号验证,金额验证

SpringBoot Validation参数校验 详解自定义注解规则和分组校验

自定义校验注解使用起来和内置注解无异,在需要的字段上添加相应注解即可

校验流程解析

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwzxz.html