feat: 实现校验支持

This commit is contained in:
wangyu 2021-09-23 10:41:53 +08:00
parent 45b0d7abb5
commit 56863ad880
4 changed files with 104 additions and 38 deletions

View File

@ -1,32 +1,99 @@
package com.flyfish.framework.beans.enums;
import com.flyfish.framework.beans.meta.BeanProperty;
import com.flyfish.framework.beans.meta.BeanValidation;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.hibernate.validator.constraints.Currency;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.*;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
/**
* 校验候选元
* 提供工厂方法进行构建
*
* @author wangyu
*/
@AllArgsConstructor
@Getter
public enum ValidationCandidate {
REQUIRED((annotation, property) -> new BeanValidation().setRequired(true).setMessage(annotation.getString("message")),
Arrays.asList(NotBlank.class, NotEmpty.class, NotNull.class));
// 必填
REQUIRED((annotation, validation) -> validation.setRequired(true), NotBlank.class, NotEmpty.class, NotNull.class),
// 正则表达式
PATTERN((annotation, validation) -> validation.setPattern(annotation.getString("regexp")), Pattern.class),
// 必须为null
NULL((annotation, validation) -> validation.setValidator("null"), Null.class),
// 长度验证
LEN((annotation, validation) -> {
int min = annotation.getInt("min");
int max = annotation.getInt("max");
if (min == max) {
validation.setLen(max);
} else {
validation.setMin(min).setMax(max);
}
}, Length.class, Size.class, Range.class),
// 最小长度
MIN((annotation, validation) -> validation.setMax(annotation.getInt("value")), Min.class),
// 最大长度
MAX((annotation, validation) -> validation.setMin(annotation.getInt("value")), Max.class),
// 电子邮件
EMAIL((annotation, validation) -> validation.setType("email"), Email.class),
// URL地址
URL_ADDRESS((annotation, validation) -> validation.setType("url"), URL.class),
// 数字
DIGITS((annotation, validation) -> validation.setType("number").setValidator("digits")
.prop("integer", annotation.getInt("integer")).prop("fraction", annotation.getInt("fraction")),
Digits.class),
// 日期
DATE((annotation, validation) -> validation.setValidator("date").prop("type", annotation.getType().getSimpleName()),
Future.class, FutureOrPresent.class, Past.class, PastOrPresent.class),
// 负数正数
NATURE((annotation, validation) -> validation.setType("number").setValidator("nature")
.prop("type", annotation.getType().getSimpleName()),
Negative.class, NegativeOrZero.class, Positive.class, PositiveOrZero.class),
// 货币
CURRENCY((annotation, validation) -> validation.setValidator("currency"), Currency.class);
private final BiFunction<MergedAnnotation<?>, BeanProperty, BeanValidation> mapper;
private final BiConsumer<MergedAnnotation<?>, BeanValidation> mapper;
private final List<Class<? extends Annotation>> annotations;
@SafeVarargs
ValidationCandidate(BiConsumer<MergedAnnotation<?>, BeanValidation> mapper,
Class<? extends Annotation>... annotations) {
this.mapper = mapper;
this.annotations = Arrays.asList(annotations);
}
/**
* 通过合并注解集合匹配
*
* @param annotations 注解集合
* @return 结果
*/
public static List<BeanValidation> produce(MergedAnnotations annotations) {
return Arrays.stream(values()).flatMap(candidate -> candidate.annotations.stream().map(annotations::get)
.filter(MergedAnnotation::isPresent).map(candidate::produce)
).collect(Collectors.toList());
}
/**
* 生产校验规则
*
* @return 结果
*/
public BeanValidation produce(MergedAnnotation<?> annotation) {
BeanValidation validation = new BeanValidation().setMessage(annotation.getString("message"));
mapper.accept(annotation, validation);
return validation;
}
}

View File

@ -3,6 +3,7 @@ package com.flyfish.framework.beans.meta;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.flyfish.framework.annotations.Properties;
import com.flyfish.framework.annotations.*;
import com.flyfish.framework.beans.enums.ValidationCandidate;
import com.flyfish.framework.domain.base.Qo;
import com.flyfish.framework.domain.base.Vo;
import com.flyfish.framework.utils.ReflectionUtils;
@ -17,7 +18,6 @@ import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.TypeUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.MergedAnnotation;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.data.mongodb.core.mapping.Document;
@ -128,7 +128,7 @@ public class BeanProperty {
}
}
// 优雅的处理校验
parseValidation(property, annotations);
property.setValidation(ValidationCandidate.produce(annotations));
} else if (strict) {
property.setReadonly(true);
return property;
@ -328,15 +328,6 @@ public class BeanProperty {
return Optional.empty();
}
/**
* 解析验证机制
* @param property 属性
* @param annotations 注解们
*/
private static void parseValidation(BeanProperty property, MergedAnnotations annotations) {
}
/**
* 设置当前对象的键值属性
*

View File

@ -1,17 +1,8 @@
package com.flyfish.framework.beans.meta;
import org.hibernate.validator.constraints.Currency;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.Range;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;
/**
* 枚举常用的bean属性
*
* @author wangyu
*/
public interface BeanProps {
@ -26,11 +17,4 @@ public interface BeanProps {
String LAYOUT_HALF = "half";
String LAYOUT_TABLE = "table";
List<Class<? extends Annotation>> VALIDATION_TYPES = Arrays.asList(
NotBlank.class, NotEmpty.class, NotNull.class, Null.class, Email.class, Digits.class, Future.class,
FutureOrPresent.class, Past.class, PastOrPresent.class, Pattern.class, Max.class, Min.class,
Negative.class, NegativeOrZero.class, Positive.class, PositiveOrZero.class, Size.class,
Length.class, Range.class, URL.class, Currency.class
);
}

View File

@ -3,9 +3,13 @@ package com.flyfish.framework.beans.meta;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.HashMap;
import java.util.Map;
/**
* 智能验证实体
* 封装了通用验证框架和前端校验框架的适配支持严格统一验证
*
* @author wangyu
*/
@Data
@ -15,6 +19,9 @@ public class BeanValidation {
// 是否必需
private Boolean required;
// 类型
private String type;
// 验证文案
private String message;
@ -23,4 +30,21 @@ public class BeanValidation {
// 验证长度
private int len;
// 验证最小长度
private int min;
// 验证最大长度
private int max;
// 内建的验证器
private String validator;
// 额外的选项
private Map<String, Object> properties = new HashMap<>();
public BeanValidation prop(String key, Object value) {
properties.put(key, value);
return this;
}
}