From 86714d7722e24e0247d0ebf92f0e815134c9be97 Mon Sep 17 00:00:00 2001 From: wangyu <727842003@qq.com> Date: Wed, 29 Sep 2021 11:34:12 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E5=94=AF=E4=B8=80?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/annotations/UniqueField.java | 44 +++++++++++++ .../validators/UniqueFieldValidator.java | 61 +++++++++++++++++++ .../beans/enums/ValidationCandidate.java | 10 ++- 3 files changed, 112 insertions(+), 3 deletions(-) create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/validation/annotations/UniqueField.java create mode 100644 flyfish-common/src/main/java/com/flyfish/framework/validation/validators/UniqueFieldValidator.java diff --git a/flyfish-common/src/main/java/com/flyfish/framework/validation/annotations/UniqueField.java b/flyfish-common/src/main/java/com/flyfish/framework/validation/annotations/UniqueField.java new file mode 100644 index 0000000..9f77e6f --- /dev/null +++ b/flyfish-common/src/main/java/com/flyfish/framework/validation/annotations/UniqueField.java @@ -0,0 +1,44 @@ +package com.flyfish.framework.validation.annotations; + + +import com.flyfish.framework.validation.validators.IdCardValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import com.flyfish.framework.validation.annotations.UniqueField.List; +import com.flyfish.framework.validation.validators.UniqueFieldValidator; + +import static java.lang.annotation.ElementType.*; +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER}) +@Retention(RUNTIME) +@Documented +@Constraint(validatedBy = {UniqueFieldValidator.class}) +@Repeatable(List.class) +public @interface UniqueField { + + String message() default "集合中的关键字段不唯一!"; + + // 唯一字段 + String value(); + + //分组 + Class[] groups() default {}; + + //负载 + Class[] payload() default {}; + + //指定多个时使用 + @Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE}) + @Retention(RUNTIME) + @Documented + @interface List { + UniqueField[] value(); + } +} diff --git a/flyfish-common/src/main/java/com/flyfish/framework/validation/validators/UniqueFieldValidator.java b/flyfish-common/src/main/java/com/flyfish/framework/validation/validators/UniqueFieldValidator.java new file mode 100644 index 0000000..bf6d89d --- /dev/null +++ b/flyfish-common/src/main/java/com/flyfish/framework/validation/validators/UniqueFieldValidator.java @@ -0,0 +1,61 @@ +package com.flyfish.framework.validation.validators; + + +import com.flyfish.framework.validation.annotations.UniqueField; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.ClassUtils; +import org.springframework.beans.BeanUtils; + +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.List; +import java.util.Map; + +public class UniqueFieldValidator implements ConstraintValidator> { + + private String field; + + @Override + public void initialize(UniqueField uniqueField) { + this.field = uniqueField.value(); + } + + /** + * Implements the validation logic. + * The state of {@code value} must not be altered. + *

+ * This method can be accessed concurrently, thread-safety must be ensured + * by the implementation. + * + * @param value object to validate + * @param context context in which the constraint is evaluated + * @return {@code false} if {@code value} does not pass the constraint + */ + @Override + public boolean isValid(List value, ConstraintValidatorContext context) { + int size = CollectionUtils.size(value); + if (size < 2) { + return true; + } + long count = value.stream().map(item -> { + if (item instanceof String || ClassUtils.isPrimitiveOrWrapper(item.getClass())) { + return item; + } + if (item instanceof Map) { + return ((Map) item).get(field); + } + try { + PropertyDescriptor descriptor = BeanUtils.getPropertyDescriptor(item.getClass(), field); + if (null != descriptor) { + return descriptor.getReadMethod().invoke(item); + } + return null; + } catch (IllegalAccessException | InvocationTargetException ignored) { + return null; + } + }).distinct().count(); + return count == size; + } +} 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 index 9333254..7879220 100644 --- 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 @@ -4,6 +4,7 @@ import com.flyfish.framework.beans.meta.BeanPropertyType; import com.flyfish.framework.beans.meta.BeanValidation; import com.flyfish.framework.validation.annotations.IdCard; import com.flyfish.framework.validation.annotations.Phone; +import com.flyfish.framework.validation.annotations.UniqueField; import com.flyfish.framework.validation.enums.PhoneType; import lombok.Getter; import org.hibernate.validator.constraints.Currency; @@ -67,10 +68,13 @@ public enum ValidationCandidate { // 货币 CURRENCY((annotation, validation) -> validation.setValidator("currency"), Currency.class), // 手机号 - PHONE(((annotation, validation) -> validation.setValidator("phone").prop("type", - annotation.getEnum("type", PhoneType.class).name().toLowerCase())), Phone.class), + PHONE((annotation, validation) -> validation.setValidator("phone").prop("type", + annotation.getEnum("type", PhoneType.class).name().toLowerCase()), Phone.class), // 身份证号 - ID_CARD(((annotation, validation) -> validation.setValidator("idCard")), IdCard.class); + ID_CARD((annotation, validation) -> validation.setValidator("idCard"), IdCard.class), + // 唯一字段 + UNIQUE_FIELD((annotation, validation) -> validation.setValidator("uniqueField") + .prop("field", annotation.getString("value")), UniqueField.class); private final BiConsumer, BeanValidation> mapper;