From 45b0d7abb5d6b4a3d2ae6ab3c9d7a6f5f0c175ef Mon Sep 17 00:00:00 2001 From: wangyu <727842003@qq.com> Date: Thu, 23 Sep 2021 09:06:01 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=8F=90=E4=BA=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=A1=86=E6=9E=B6=E4=BB=A3=E7=A0=81=EF=BC=8C=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E9=83=A8=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../beans/enums/ValidationCandidate.java | 32 +++++++++ .../framework/beans/meta/BeanProperty.java | 71 +++++++++++++------ .../framework/beans/meta/BeanProps.java | 17 +++++ .../framework/beans/meta/BeanValidation.java | 26 +++++++ 4 files changed, 124 insertions(+), 22 deletions(-) create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/beans/enums/ValidationCandidate.java create mode 100644 flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanValidation.java diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/enums/ValidationCandidate.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/enums/ValidationCandidate.java new file mode 100644 index 0000000..626c73b --- /dev/null +++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/enums/ValidationCandidate.java @@ -0,0 +1,32 @@ +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.springframework.core.annotation.MergedAnnotation; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.lang.annotation.Annotation; +import java.util.Arrays; +import java.util.List; +import java.util.function.BiFunction; + +/** + * 校验候选元 + * + * @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)); + + private final BiFunction, BeanProperty, BeanValidation> mapper; + + private final List> annotations; +} diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProperty.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProperty.java index 2a95611..26f9cee 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProperty.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProperty.java @@ -18,6 +18,8 @@ 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; import java.beans.PropertyDescriptor; @@ -60,6 +62,9 @@ public class BeanProperty { // 类型为object时,拥有子表单 private List children; + // bean验证 + private List validation; + // 排序变量,用于排序 private transient int order; @@ -89,10 +94,13 @@ public class BeanProperty { boolean strict = Qo.class.isAssignableFrom(beanClass) || Vo.class.isAssignableFrom(beanClass); // 尝试获取field Field field = FieldUtils.getField(beanClass, descriptor.getName(), true); + MergedAnnotations annotations = null == field ? MergedAnnotations.from() : MergedAnnotations.from(field); // 存在field,可以干一些坏事 if (null != field) { - Property props = AnnotationUtils.findAnnotation(field, Property.class); - if (null != props) { + // 开始解析关键注解 + if (annotations.isPresent(Property.class)) { + Property props = annotations.get(Property.class).synthesize(); + // 只有存在馆建注解,才会进行初始化 String parentName = Optional.ofNullable(beanClass.getAnnotation(RestBean.class)) .map(RestBean::name).orElse(""); property.setTitle(props.inherited() ? parentName + props.title() : props.title()); @@ -100,24 +108,27 @@ public class BeanProperty { property.setReadonly(props.readonly()); property.setGroup(props.group()); // 优雅地设置排序 - Order order = AnnotationUtils.findAnnotation(field, Order.class); - if (null != order) { - property.setOrder(order.value()); + MergedAnnotation order = annotations.get(Order.class); + if (order.isPresent()) { + property.setOrder(order.synthesize().value()); } else { property.setOrder(props.order()); } // 优雅的设置额外的属性 - FormItem item = AnnotationUtils.findAnnotation(field, FormItem.class); - if (null != item) { + MergedAnnotation item = annotations.get(FormItem.class); + if (item.isPresent()) { + FormItem formItem = item.synthesize(); // 设置额外属性 - property.extra.put("component", item.component()); - property.layout = item.layout(); - if (ArrayUtils.isNotEmpty(item.props())) { - for (FormItem.Prop prop : item.props()) { + property.extra.put("component", formItem.component()); + property.layout = formItem.layout(); + if (ArrayUtils.isNotEmpty(formItem.props())) { + for (FormItem.Prop prop : formItem.props()) { property.prop(prop.key(), prop.value()); } } } + // 优雅的处理校验 + parseValidation(property, annotations); } else if (strict) { property.setReadonly(true); return property; @@ -132,18 +143,18 @@ public class BeanProperty { // 如果字段使用DictValue注解,尝试使用字典值仓库 if (null != field) { // 添加了字典枚举,自动添加code,从字典表取得 - if (field.isAnnotationPresent(DictValue.class)) { - DictValue dictValue = field.getAnnotation(DictValue.class); + if (annotations.isPresent(DictValue.class)) { + DictValue dictValue = annotations.get(DictValue.class).synthesize(); property.prop("code", dictValue.value()); - } else if (field.isAnnotationPresent(EnumValue.class)) { + } else if (annotations.isPresent(EnumValue.class)) { // 添加了枚举注解,自动注入类型,给前端使用 property.setType(BeanPropertyType.ENUM); - EnumValue enumValue = field.getAnnotation(EnumValue.class); + EnumValue enumValue = annotations.get(EnumValue.class).synthesize(); String name = StringFormats.camel2Line(ClassUtils.getShortClassName(enumValue.value())); property.prop("code", name); - } else if (field.isAnnotationPresent(DBRefValue.class)) { + } else if (annotations.isPresent(DBRefValue.class)) { // 添加了数据库引用注解,自动注入类型给前端使用 - DBRefValue dbRefValue = field.getAnnotation(DBRefValue.class); + DBRefValue dbRefValue = annotations.get(DBRefValue.class).synthesize(); Optional optional = processDbRef(dbRefValue.value()); if (optional.isPresent()) { property.setType(BeanPropertyType.DB_REF); @@ -160,10 +171,10 @@ public class BeanProperty { ReflectionUtils.getGenericType(field) .filter(property::isAttachment) .ifPresent(item -> property.prop("attachment", true)); - if (field.isAnnotationPresent(SubBean.class)) { + if (annotations.isPresent(SubBean.class)) { // 尝试获取泛型参数,存在时,赋值子表单 parseSubClass(field).ifPresent(subClazz -> property.setChildren(from(subClazz))); - } else if (field.isAnnotationPresent(DateRange.class)) { + } else if (annotations.isPresent(DateRange.class)) { property.setType(BeanPropertyType.DATE); property .prop("type", "range") @@ -173,7 +184,7 @@ public class BeanProperty { break; case OBJECT: // 有子bean注解才处理 - if (null != field && field.isAnnotationPresent(SubBean.class)) { + if (null != field && annotations.isPresent(SubBean.class)) { property.setChildren(from(clazz)); } break; @@ -198,8 +209,8 @@ public class BeanProperty { case DATE: // 为日期,自动放入类型和长度 if (null != field) { - if (field.isAnnotationPresent(JsonFormat.class)) { - String pattern = field.getAnnotation(JsonFormat.class).pattern(); + if (annotations.isPresent(JsonFormat.class)) { + String pattern = annotations.get(JsonFormat.class).synthesize().pattern(); // yyyy-MM-dd HH:mm:ss if (StringUtils.isNotBlank(pattern)) { if (pattern.length() == 7) { @@ -317,6 +328,22 @@ public class BeanProperty { return Optional.empty(); } + /** + * 解析验证机制 + * @param property 属性 + * @param annotations 注解们 + */ + private static void parseValidation(BeanProperty property, MergedAnnotations annotations) { + + } + + /** + * 设置当前对象的键值属性 + * + * @param key 键 + * @param value 值 + * @return 结果 + */ public BeanProperty prop(String key, Object value) { if (null == props) { props = new HashMap<>(); diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProps.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProps.java index 82c860c..f26dd46 100644 --- a/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProps.java +++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanProps.java @@ -1,5 +1,15 @@ 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 @@ -16,4 +26,11 @@ public interface BeanProps { String LAYOUT_HALF = "half"; String LAYOUT_TABLE = "table"; + + List> 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 + ); } diff --git a/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanValidation.java b/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanValidation.java new file mode 100644 index 0000000..f6d5000 --- /dev/null +++ b/flyfish-web/src/main/java/com/flyfish/framework/beans/meta/BeanValidation.java @@ -0,0 +1,26 @@ +package com.flyfish.framework.beans.meta; + +import lombok.Data; +import lombok.experimental.Accessors; + +/** + * 智能验证实体 + * 封装了通用验证框架和前端校验框架的适配,支持严格统一验证 + * @author wangyu + */ +@Data +@Accessors(chain = true) +public class BeanValidation { + + // 是否必需 + private Boolean required; + + // 验证文案 + private String message; + + // 验证正则 + private String pattern; + + // 验证长度 + private int len; +}