1. 重构代码;2. 支持对 POJO 的校验

ZhouXY108 2024-03-15 09:09:38 +08:00
parent e4f18d5d89
commit a703fcadc1
6 changed files with 115 additions and 150 deletions

View File

@ -0,0 +1,51 @@
package xyz.zhouxy.plusone.validator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
public abstract class BasePropertyValidator<TObj, TProperty, TValidator extends BasePropertyValidator<TObj, TProperty, TValidator>> {
private final Function<TObj, ? extends TProperty> getter;
protected BasePropertyValidator(Function<TObj, ? extends TProperty> getter) {
this.getter = getter;
}
private final List<Consumer<TProperty>> consumers = new LinkedList<>();
public final TValidator withRules(Predicate<? super TProperty> rule) {
return withRules(rule, v -> new IllegalArgumentException());
}
public final TValidator withRules(
Predicate<? super TProperty> rule, String errorMsg) {
return withRules(rule, v -> new IllegalArgumentException(errorMsg));
}
public final <E extends RuntimeException> TValidator withRules(
Predicate<? super TProperty> rule, Supplier<E> e) {
return withRules(rule, v -> e.get());
}
public final <E extends RuntimeException> TValidator withRules(
Predicate<? super TProperty> rule, Function<TProperty, E> e) {
this.consumers.add(v -> {
if (!rule.test(v)) {
throw e.apply(v);
}
});
return thisObject();
}
public final <T extends TObj> void validate(T dto) {
for (Consumer<TProperty> consumer : consumers) {
consumer.accept(getter.apply(dto));
}
}
protected abstract TValidator thisObject();
}

View File

@ -0,0 +1,20 @@
package xyz.zhouxy.plusone.validator;
import java.util.Map;
public class EntryValidator<K, V>
extends BasePropertyValidator<Map<K, ? super V>, V, EntryValidator<K, V>> {
public EntryValidator(K key) {
super(m -> {
@SuppressWarnings("unchecked")
V v = (V) m.get(key);
return v;
});
}
@Override
protected EntryValidator<K, V> thisObject() {
return this;
}
}

View File

@ -51,12 +51,12 @@ public abstract class MapValidator<K, V> {
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
protected final <VV extends V> PropertyValidator<K, VV> checkProperty(K key, Class<VV> clazz) { protected final <VV extends V> EntryValidator<K, VV> checkProperty(K key, Class<VV> clazz) {
return checkProperty(key); return checkProperty(key);
} }
protected final <VV extends V> PropertyValidator<K, VV> checkProperty(K key) { protected final <VV extends V> EntryValidator<K, VV> checkProperty(K key) {
PropertyValidator<K, VV> validator = new PropertyValidator<>(key); EntryValidator<K, VV> validator = new EntryValidator<>(key);
this.consumers.add(validator::validate); this.consumers.add(validator::validate);
return validator; return validator;
} }
@ -81,45 +81,3 @@ public abstract class MapValidator<K, V> {
}); });
} }
} }
class PropertyValidator<K, V> {
private final K key;
public PropertyValidator(K key) {
this.key = key;
}
private final List<Consumer<V>> consumers = new LinkedList<>();
public final PropertyValidator<K, V> withRules(Predicate<? super V> rule) {
return withRules(rule, v -> new IllegalArgumentException(key.toString()));
}
public final PropertyValidator<K, V> withRules(Predicate<? super V> rule, String errorMsg) {
return withRules(rule, v -> new IllegalArgumentException(errorMsg));
}
public final <E extends RuntimeException> PropertyValidator<K, V> withRules(Predicate<? super V> rule,
Supplier<E> e) {
return withRules(rule, v -> e.get());
}
public final <E extends RuntimeException> PropertyValidator<K, V> withRules(Predicate<? super V> rule,
Function<V, E> e) {
this.consumers.add(v -> {
if (!rule.test(v)) {
throw e.apply(v);
}
});
return this;
}
public final void validate(Map<K, ? super V> map) {
for (Consumer<V> consumer : consumers) {
@SuppressWarnings("unchecked")
V v = (V) map.get(this.key);
consumer.accept(v);
}
}
}

View File

@ -1,90 +0,0 @@
package xyz.zhouxy.plusone.validator;
import java.util.Collection;
import java.util.function.Predicate;
import java.util.regex.Pattern;
public class PredicateTools {
private PredicateTools() {
throw new IllegalStateException("Utility class");
}
public static <T> Predicate<T> asPredicate(Predicate<T> predicate) {
return predicate;
}
public static <T> boolean notNull(T obj) {
return obj != null;
}
public static <T> Predicate<T> notNull() {
return PredicateTools::notNull;
}
public static int length(CharSequence cs) {
return cs == null ? 0 : cs.length();
}
public static boolean isNotBlank(CharSequence cs) {
return !isBlank(cs);
}
public static Predicate<CharSequence> isNotBlank() {
return PredicateTools::isNotBlank;
}
public static boolean isBlank(CharSequence cs) {
final int strLen = length(cs);
if (strLen == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (!Character.isWhitespace(cs.charAt(i))) {
return false;
}
}
return true;
}
public static Predicate<CharSequence> isBlank() {
return PredicateTools::isBlank;
}
public static Predicate<CharSequence> matches(Pattern pattern) {
return str -> pattern.matcher(str).matches();
}
public static Predicate<CharSequence> matchesAll(Pattern... patterns) {
return str -> {
for (Pattern pattern : patterns) {
if (!pattern.matcher(str).matches()) {
return false;
}
}
return true;
};
}
public static Predicate<CharSequence> matchesOne(Pattern... patterns) {
return str -> {
for (Pattern pattern : patterns) {
if (pattern.matcher(str).matches()) {
return true;
}
}
return false;
};
}
public static <T> Predicate<Collection<T>> forAllItems(Predicate<T> predicate) {
return c -> {
for (T t : c) {
if (!predicate.test(t)) {
return false;
}
}
return true;
};
}
}

View File

@ -0,0 +1,17 @@
package xyz.zhouxy.plusone.validator;
import java.util.function.Function;
public class PropertyValidator<TObj, TProperty>
extends BasePropertyValidator<TObj, TProperty, PropertyValidator<TObj, TProperty>> {
protected PropertyValidator(Function<TObj, ? extends TProperty> getter) {
super(getter);
}
@Override
protected PropertyValidator<TObj, TProperty> thisObject() {
return this;
}
}

View File

@ -1,4 +1,4 @@
package xyz.zhouxy.plusone.validator; package xyz.zhouxy.plusone.validator.map;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@ -7,11 +7,16 @@ import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
import xyz.zhouxy.plusone.commons.constant.PatternConsts; import xyz.zhouxy.plusone.commons.constant.PatternConsts;
import xyz.zhouxy.plusone.commons.function.PredicateTools;
import xyz.zhouxy.plusone.commons.util.RegexUtil;
import xyz.zhouxy.plusone.validator.MapValidator;
class MapValidatorTests { class MapValidatorTests {
@ -26,34 +31,38 @@ class MapValidatorTests {
private static final MapValidator<String, Object> validator = new MapValidator<String, Object>( private static final MapValidator<String, Object> validator = new MapValidator<String, Object>(
new String[] { USERNAME, ACCOUNT, PASSWORD, AGE, BOOLEAN, ROLE_LIST }) { new String[] { USERNAME, ACCOUNT, PASSWORD, AGE, BOOLEAN, ROLE_LIST }) {
{ {
checkProperty(USERNAME, String.class) checkProperty(USERNAME, String.class).withRules(
.withRules(StringUtils::isNotEmpty) PredicateTools.from(StringUtils::isNotBlank)
.withRules(PredicateTools.matches(PatternConsts.USERNAME), .and(username -> RegexUtil.matches(username, PatternConsts.USERNAME)),
username -> new IllegalArgumentException(String.format("用户名【%s】不符合规范", username))); username -> new IllegalArgumentException(String.format("用户名【%s】不符合规范", username)));
checkProperty(ACCOUNT, String.class) checkProperty(ACCOUNT, String.class).withRules(
.withRules(StringUtils::isNotEmpty) PredicateTools.from(StringUtils::isNotBlank)
.withRules(PredicateTools.matchesOne(PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE), .and(account -> RegexUtil.matchesOne(account,
new Pattern[] { PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE })),
"请输入正确的邮箱地址或手机号"); "请输入正确的邮箱地址或手机号");
checkProperty(PASSWORD, String.class) checkProperty(PASSWORD, String.class)
.withRules(StringUtils::isNotEmpty) .withRules(StringUtils::isNotEmpty, "密码不能为空")
.withRules(PredicateTools.matches(PatternConsts.PASSWORD), "密码不符合规范"); .withRules(pwd -> RegexUtil.matches(pwd, PatternConsts.PASSWORD), "密码不符合规范");
// 校验到多个属性,只能针对 map 本身进行校验
withRule(m -> Objects.equals(m.get(PASSWORD), m.get(PASSWORD2)), withRule(m -> Objects.equals(m.get(PASSWORD), m.get(PASSWORD2)),
"两次输入的密码不一样!"); "两次输入的密码不一样!");
checkProperty(AGE, Integer.class) // 通过泛型方式调用方法,指定数据类型
this.<Integer>checkProperty(AGE)
.withRules(Objects::nonNull) .withRules(Objects::nonNull)
.withRules(age -> (18 <= age && 60 >= age)); .withRules(age -> (18 <= age && 60 >= age));
checkProperty(BOOLEAN, Boolean.class) checkProperty(BOOLEAN, Boolean.class)
.withRules(PredicateTools.notNull(), "Boolean property could not be null.") .withRules(Objects::nonNull, "Boolean property could not be null.")
.withRules(b -> b, "Boolean property must be true."); .withRules(b -> b, "Boolean property must be true.");
this.<Collection<String>>checkProperty(ROLE_LIST) this.<Collection<String>>checkProperty(ROLE_LIST)
.withRules(c -> c != null && !c.isEmpty(), "角色列表不能为空!") .withRules(CollectionTools::isNotEmpty, "角色列表不能为空!")
.withRules(PredicateTools.forAllItems(Objects::nonNull), () -> new NullPointerException(ROLE_LIST)); .withRules(l -> l.stream().allMatch(StringUtils::isNotBlank),
() -> new IllegalArgumentException(ROLE_LIST));
} }
}; };