diff --git a/.editorconfig b/.editorconfig index 2087dd7..9b84b10 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,3 +10,6 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = false insert_final_newline = true + +[*.xml] +indent_size = 2 diff --git a/pom.xml b/pom.xml index 76f910f..0f75c33 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,8 @@ + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 xyz.zhouxy.plusone @@ -20,33 +21,38 @@ - xyz.zhouxy.plusone - plusone-commons - 0.1.0-SNAPSHOT - - - org.apache.commons - commons-lang3 - ${commons-lang3.version} + com.google.guava + guava + 32.0.1-jre + org.junit.jupiter junit-jupiter-api 5.9.2 test + + org.apache.commons + commons-lang3 + 3.14.0 + test + + + org.apache.commons + commons-collections4 + 4.4 + test + - - maven-clean-plugin 3.1.0 - maven-resources-plugin 3.0.2 @@ -71,7 +77,6 @@ maven-deploy-plugin 2.8.2 - maven-site-plugin 3.7.1 diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/ConcurrentHashMapUtil.java b/src/main/java/xyz/zhouxy/plusone/commons/util/ConcurrentHashMapUtil.java new file mode 100644 index 0000000..39d681c --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/ConcurrentHashMapUtil.java @@ -0,0 +1,43 @@ +package xyz.zhouxy.plusone.commons.util; + +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +/** + * ConcurrentHashMapUtil + * + *

+ * Java 8 的 {@link ConcurrentHashMap#computeIfAbsent(Object, Function)} 方法有 bug, + * 可使用这个工具类的 {@link computeIfAbsentForJava8} 进行替换。 + * + *

+ * NOTE: 方法来自Dubbo,见:issues#2349 + * + * @author ZhouXY + * @see ConcurrentHashMap + */ +public class ConcurrentHashMapUtil { + + public static V computeIfAbsentForJava8(ConcurrentHashMap map, final K key, + final Function mappingFunction) { + Objects.requireNonNull(key); + Objects.requireNonNull(mappingFunction); + V v = map.get(key); + if (null == v) { + v = mappingFunction.apply(key); + if (null == v) { + return null; + } + final V res = map.putIfAbsent(key, v); + if (null != res) { + return res; + } + } + return v; + } + + private ConcurrentHashMapUtil() { + throw new IllegalStateException("Utility class"); + } +} diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/Predicates.java b/src/main/java/xyz/zhouxy/plusone/commons/util/Predicates.java new file mode 100644 index 0000000..5dba12c --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/Predicates.java @@ -0,0 +1,43 @@ +package xyz.zhouxy.plusone.commons.util; + +import java.util.function.Predicate; + +/** + * Predicates + * + *

+ * {@link Predicate} 相关操作。 + *

+ * + * @author ZhouXY + * @see Predicate + */ +public class Predicates { + + /** + * 将 lambda 表达式或者方法引用包装为对应类型的 {@link Predicate} 对象。 + * 如将 {@code Objects::nonNull} 明确地指定为 {@code Predicate<String>}, + * 使之可以链式调用 {@link Predicate#and(Predicate)}、{@link Predicate#or(Predicate)} + * 等方法,连接其它 {@code Predicate} 对象。 + * + *
+     * Predicate<String> predicate = Predicates.<String>of(Objects::nonNull)
+     *         .and(StringUtils::isNotEmpty);
+     * 
+ * + * @param 目标类型 + * @param predicate 原 {@link Predicate} 实例 + * @return 包装的 {@link Predicate} 实例 + */ + public static Predicate of(Predicate predicate) { + return predicate::test; + } + + public static Predicate not(Predicate predicate) { + return t -> !predicate.test(t); + } + + private Predicates() { + throw new IllegalStateException("Utility class"); + } +} diff --git a/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java b/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java new file mode 100644 index 0000000..bcca2b0 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/commons/util/RegexUtil.java @@ -0,0 +1,378 @@ +package xyz.zhouxy.plusone.commons.util; + +import java.util.Arrays; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import com.google.common.base.Preconditions; + +/** + * 封装一些常用的正则操作,并可以缓存 {@link Pattern} 实例以复用(最多缓存大概 256 个)。 + * + * @author ZhouXY + * + */ +public final class RegexUtil { + + private static final int DEFAULT_CACHE_INITIAL_CAPACITY = 64; + private static final int MAX_CACHE_SIZE = 256; + private static final ConcurrentHashMap PATTERN_CACHE = new ConcurrentHashMap<>( + DEFAULT_CACHE_INITIAL_CAPACITY); + + /** + * 获取 {@link Pattern} 实例。 + * + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return {@link Pattern} 实例 + */ + public static Pattern getPattern(final String pattern, final boolean cachePattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return cachePattern ? getAndCachePatternInternal(pattern) : getPatternInternal(pattern); + } + + /** + * 获取 {@link Pattern} 实例,不缓存。 + * + * @param pattern 正则表达式 + * @return {@link Pattern} 实例 + */ + public static Pattern getPattern(final String pattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return getPatternInternal(pattern); + } + + /** + * 将各个正则表达式转为 {@link Pattern} 实例。 + * + * @param patterns 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return {@link Pattern} 实例数组 + */ + public static Pattern[] getPatterns(final String[] patterns, final boolean cachePattern) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return cachePattern + ? getAndCachePatternsInternal(patterns) + : getPatternsInternal(patterns); + } + + /** + * 将各个正则表达式转为 {@link Pattern} 实例,不缓存。 + * + * @param patterns 正则表达式 + * @return {@link Pattern} 实例数组 + */ + public static Pattern[] getPatterns(final String[] patterns) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return getPatternsInternal(patterns); + } + + /** + * 手动缓存 Pattern 实例。 + * + * @param pattern 要缓存的 {@link Pattern} 实例 + * @return 缓存的 Pattern 实例。如果缓存已满,则返回 {@code null}。 + */ + public static Pattern cachePattern(final Pattern pattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + if (PATTERN_CACHE.size() >= MAX_CACHE_SIZE) { + return null; + } + final String patternStr = pattern.pattern(); + final Pattern pre = PATTERN_CACHE.putIfAbsent(patternStr, pattern); + return pre != null ? pre : pattern; + } + + /** + * 判断 {@code input} 是否匹配 {@code pattern}。 + * + * @param input 输入 + * @param pattern 正则 + * @return 判断结果 + */ + public static boolean matches(@Nullable final CharSequence input, final Pattern pattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return matchesInternal(input, pattern); + } + + /** + * 判断 {@code input} 是否匹配 {@code patterns} 中的一个。 + * + * @param input 输入 + * @param patterns 正则 + * @return 判断结果 + */ + public static boolean matchesOne(@Nullable final CharSequence input, final Pattern[] patterns) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return matchesOneInternal(input, patterns); + } + + /** + * 判断 {@code input} 是否匹配全部正则。 + * + * @param input 输入 + * @param patterns 正则 + * @return 判断结果 + */ + public static boolean matchesAll(@Nullable final CharSequence input, final Pattern[] patterns) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + return matchesAllInternal(input, patterns); + } + + /** + * 判断 {@code input} 是否匹配 {@code pattern}。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 判断结果 + */ + public static boolean matches(@Nullable final CharSequence input, final String pattern, + final boolean cachePattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + Pattern p = cachePattern + ? getAndCachePatternInternal(pattern) + : getPatternInternal(pattern); + return matchesInternal(input, p); + } + + /** + * 判断 {@code input} 是否匹配 {@code pattern}。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @return 判断结果 + */ + public static boolean matches(@Nullable final CharSequence input, final String pattern) { + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return matchesInternal(input, getPatternInternal(pattern)); + } + + /** + * 判断 {@code input} 是否匹配 {@code patterns} 中的一个。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 判断结果 + */ + public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns, + final boolean cachePattern) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = cachePattern + ? getAndCachePatternsInternal(patterns) + : getPatternsInternal(patterns); + return matchesOneInternal(input, patternSet); + } + + /** + * 判断 {@code input} 是否匹配 {@code patterns} 中的一个。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @return 判断结果 + */ + public static boolean matchesOne(@Nullable final CharSequence input, final String[] patterns) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = getPatternsInternal(patterns); + return matchesOneInternal(input, patternSet); + } + + /** + * 判断 {@code input} 是否匹配全部正则。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 判断结果 + */ + public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns, + final boolean cachePattern) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = cachePattern + ? getAndCachePatternsInternal(patterns) + : getPatternsInternal(patterns); + return matchesAllInternal(input, patternSet); + } + + /** + * 判断 {@code input} 是否匹配全部正则。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param patterns 正则表达式 + * @return 判断结果 + */ + public static boolean matchesAll(@Nullable final CharSequence input, final String[] patterns) { + Preconditions.checkNotNull(patterns, "Patterns can not be null."); + Preconditions.checkArgument(allNotNull(patterns), "The pattern can not be null."); + final Pattern[] patternSet = getPatternsInternal(patterns); + return matchesAllInternal(input, patternSet); + } + + /** + * 生成 Matcher。 + * + * @param input 输入 + * @param pattern 正则 + * @return 结果 + */ + public static Matcher getMatcher(final CharSequence input, final Pattern pattern) { + Preconditions.checkNotNull(input, "The input can not be null."); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return pattern.matcher(input); + } + + /** + * 生成 Matcher。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return 结果 + */ + public static Matcher getMatcher(final CharSequence input, final String pattern, boolean cachePattern) { + Preconditions.checkNotNull(input, "The input can not be null."); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + final Pattern p = cachePattern + ? getAndCachePatternInternal(pattern) + : getPatternInternal(pattern); + return p.matcher(input); + } + + /** + * 生成 Matcher。不缓存 {@link Pattern} 实例。 + * + * @param input 输入 + * @param pattern 正则表达式 + * @return 结果 + */ + public static Matcher getMatcher(final CharSequence input, final String pattern) { + Preconditions.checkNotNull(input, "The input can not be null."); + Preconditions.checkNotNull(pattern, "The pattern can not be null."); + return getPatternInternal(pattern).matcher(input); + } + + // ========== internal methods ========== + + /** + * 获取 {@link Pattern} 实例。 + * + * @param pattern 正则表达式 + * @param cachePattern 是否缓存 {@link Pattern} 实例 + * @return {@link Pattern} 实例 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern getAndCachePatternInternal(@Nonnull final String pattern) { + if (PATTERN_CACHE.size() < MAX_CACHE_SIZE) { + return ConcurrentHashMapUtil.computeIfAbsentForJava8(PATTERN_CACHE, pattern, Pattern::compile); + } + Pattern result = PATTERN_CACHE.get(pattern); + if (result != null) { + return result; + } + return Pattern.compile(pattern); + } + + /** + * 获取 {@link Pattern} 实例,不缓存。 + * + * @param pattern 正则表达式 + * @return {@link Pattern} 实例 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern getPatternInternal(@Nonnull final String pattern) { + Pattern result = PATTERN_CACHE.get(pattern); + if (result == null) { + result = Pattern.compile(pattern); + } + return result; + } + + /** + * 将各个正则表达式转为 {@link Pattern} 实例。 + * + * @param patterns 正则表达式 + * @return {@link Pattern} 实例数组 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern[] getAndCachePatternsInternal(@Nonnull final String[] patterns) { + return Arrays.stream(patterns) + .map(RegexUtil::getAndCachePatternInternal) + .toArray(Pattern[]::new); + } + + /** + * 将各个正则表达式转为 {@link Pattern} 实例。 + * + * @param patterns 正则表达式 + * @return {@link Pattern} 实例数组 + */ + @SuppressWarnings("null") + @Nonnull + private static Pattern[] getPatternsInternal(@Nonnull final String[] patterns) { + return Arrays.stream(patterns) + .map(RegexUtil::getPatternInternal) + .toArray(Pattern[]::new); + } + + /** + * 判断 {@code input} 是否匹配 {@code pattern}。 + * + * @param input 输入 + * @param pattern 正则 + * @return 判断结果 + */ + private static boolean matchesInternal(@Nullable final CharSequence input, @Nonnull final Pattern pattern) { + return input != null && pattern.matcher(input).matches(); + } + + @SuppressWarnings("null") + private static boolean matchesOneInternal(@Nullable final CharSequence input, @Nonnull final Pattern[] patterns) { + if (input == null) { + return false; + } + for (Pattern pattern : patterns) { + if (matchesInternal(input, pattern)) { + return true; + } + } + return false; + } + + @SuppressWarnings("null") + private static boolean matchesAllInternal(final CharSequence input, final Pattern[] patterns) { + if (input == null) { + return false; + } + for (Pattern pattern : patterns) { + if (!matchesInternal(input, pattern)) { + return false; + } + } + return true; + } + + private static boolean allNotNull(T[] array) { + return Arrays.stream(array).allMatch(Objects::nonNull); + } + + private RegexUtil() { + // 不允许实例化 + throw new IllegalStateException("Utility class"); + } +} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java index aaa009e..e0bcae4 100644 --- a/src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java +++ b/src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java @@ -3,17 +3,24 @@ package xyz.zhouxy.plusone.validator; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; +import java.util.regex.Pattern; + +import com.google.common.base.Strings; + +import xyz.zhouxy.plusone.commons.util.Predicates; +import xyz.zhouxy.plusone.commons.util.RegexUtil; public class BaseValidator { private final List> rules = new ArrayList<>(); private final List> propertyValidators = new ArrayList<>(); protected void withRule(final Predicate rule, final String errorMessage) { - withRule(rule, () -> InvalidInputException.of(errorMessage)); + withRule(rule, () -> new InvalidInputException(errorMessage)); } protected void withRule(Predicate rule, Supplier exceptionBuilder) { @@ -77,4 +84,473 @@ public class BaseValidator { valueValidator.validate(obj); } } + + abstract static class PropertyValidator { + Function getter; + Validator validator = new Validator<>(); + + PropertyValidator(Function getter) { + this.getter = getter; + } + + void withRule(Predicate condition, + Function exceptionCreator) { + withRule(value -> { + if (!condition.test(value)) { + throw exceptionCreator.apply(value); + } + }); + } + + private void withRule(Consumer rule) { + this.validator.addRule(rule); + } + + // ==================== + // ====== Object ====== + // ==================== + + // ====== notNull ===== + + public THIS notNull() { + return notNull("Value could not be null."); + } + + public THIS notNull(String errMsg) { + return notNull(convertExceptionCreator(errMsg)); + } + + public THIS notNull(Supplier exceptionCreator) { + return notNull(convertExceptionCreator(exceptionCreator)); + } + + public THIS notNull(Function exceptionCreator) { + withRule(Objects::nonNull, exceptionCreator); + return thisObject(); + } + + // ====== isNull ===== + + public THIS isNull(String errMsg) { + return isNull(convertExceptionCreator(errMsg)); + } + + public THIS isNull(Supplier exceptionCreator) { + return isNull(convertExceptionCreator(exceptionCreator)); + } + + public THIS isNull(Function exceptionCreator) { + withRule(Objects::isNull, exceptionCreator); + return thisObject(); + } + + // ===== equals ===== + + public THIS equalsThat(Object that) { + return equalsThat(that, value -> new InvalidInputException("(%s) 必须与 (%s) 相等", value, that)); + } + + public THIS equalsThat(Object that, String errMsg) { + return equalsThat(that, convertExceptionCreator(errMsg)); + } + + public THIS equalsThat( + Object that, Supplier exceptionCreator) { + return equalsThat(that, convertExceptionCreator(exceptionCreator)); + } + + public THIS equalsThat( + Object that, Function exceptionCreator) { + withRule(value -> Objects.equals(value, that), exceptionCreator); + return thisObject(); + } + + // ===== isTrue ===== + + public THIS isTrue(Predicate condition) { + return isTrue(condition, "无效的用户输入"); + } + + public THIS isTrue(Predicate condition, String errMsg) { + return isTrue(condition, convertExceptionCreator(errMsg)); + } + + public THIS isTrue( + Predicate condition, + Supplier exceptionCreator) { + return isTrue(condition, convertExceptionCreator(exceptionCreator)); + } + + public THIS isTrue( + Predicate condition, + Function exceptionCreator) { + withRule(condition, exceptionCreator); + return thisObject(); + } + + // ===== isTrue ===== + + public THIS isTrue(Collection> conditions) { + return isTrue(conditions, "无效的用户输入"); + } + + public THIS isTrue(Collection> conditions, String errMsg) { + return isTrue(conditions, convertExceptionCreator(errMsg)); + } + + public THIS isTrue( + Collection> conditions, + Supplier exceptionCreator) { + return isTrue(conditions, convertExceptionCreator(exceptionCreator)); + } + + public THIS isTrue( + Collection> conditions, + Function exceptionCreator) { + for (Predicate condition : conditions) { + withRule(condition, exceptionCreator); + } + return thisObject(); + } + + // ======================================================================== + + @SuppressWarnings("unchecked") + void validate(DTO obj) { + PROPERTY value = (PROPERTY) this.getter.apply(obj); + this.validator.validate(value); + } + + static Function convertExceptionCreator(String errMsg) { + return value -> new InvalidInputException(errMsg); + } + + static Function convertExceptionCreator( + Supplier exceptionSupplier) { + return value -> exceptionSupplier.get(); + } + + protected abstract THIS thisObject(); + } + + public static class BoolValidator extends PropertyValidator> { + + BoolValidator(Function getter) { + super(getter); + } + + // ====== isTrue ====== + + public BoolValidator isTrue() { + return isTrue("The value must be true."); + } + + public BoolValidator isTrue(String errMsg) { + return isTrue(convertExceptionCreator(errMsg)); + } + + public BoolValidator isTrue(Supplier exceptionCreator) { + return isTrue(convertExceptionCreator(exceptionCreator)); + } + + public BoolValidator isTrue( + Function exceptionCreator) { + super.withRule(Boolean.TRUE::equals, exceptionCreator); + return this; + } + + // ====== isFalse ====== + + public BoolValidator isFalse() { + return isFalse("The value must be false."); + } + + public BoolValidator isFalse(String errMsg) { + return isFalse(convertExceptionCreator(errMsg)); + } + + public BoolValidator isFalse(Supplier exceptionCreator) { + return isFalse(convertExceptionCreator(exceptionCreator)); + } + + public BoolValidator isFalse( + Function exceptionCreator) { + super.withRule(Boolean.FALSE::equals, exceptionCreator); + return this; + } + + @Override + protected BoolValidator thisObject() { + return this; + } + } + + public static class DoubleValidator extends PropertyValidator> { + + DoubleValidator(Function getter) { + super(getter); + } + + public DoubleValidator between(double min, double max) { + return between(min, max, String.format("数值不在 %s 和 %s 之间", String.valueOf(min), String.valueOf(max))); + } + + public DoubleValidator between(double min, double max, String errMsg) { + return between(min, max, convertExceptionCreator(errMsg)); + } + + public DoubleValidator between(double min, double max, + Supplier exceptionCreator) { + return between(min, max, convertExceptionCreator(exceptionCreator)); + } + + public DoubleValidator between(double min, double max, + Function exceptionCreator) { + super.withRule(value -> (value >= min && value < max), exceptionCreator); + return this; + } + + @Override + protected DoubleValidator thisObject() { + return this; + } + } + + public static class IntValidator extends PropertyValidator> { + + IntValidator(Function getter) { + super(getter); + } + + public IntValidator between(int min, int max) { + return between(min, max, String.format("数值不在 %d 和 %d 之间", min, max)); + } + + public IntValidator between(int min, int max, String errMsg) { + return between(min, max, convertExceptionCreator(errMsg)); + } + + public IntValidator between(int min, int max, + Supplier exceptionCreator) { + return between(min, max, convertExceptionCreator(exceptionCreator)); + } + + public IntValidator between(int min, int max, + Function exceptionCreator) { + super.withRule(value -> (value >= min && value < max), exceptionCreator); + return this; + } + + @Override + protected IntValidator thisObject() { + return this; + } + } + + public static class StringValidator extends PropertyValidator> { + + StringValidator(Function getter) { + super(getter); + } + + // ==================== + // ====== String ====== + // ==================== + + // ===== matches ===== + + public StringValidator matches(Pattern regex, String errMsg) { + return matches(regex, convertExceptionCreator(errMsg)); + } + + public StringValidator matches( + Pattern regex, + Supplier exceptionCreator) { + return matches(regex, convertExceptionCreator(exceptionCreator)); + } + + public StringValidator matches( + Pattern regex, + Function exceptionCreator) { + super.withRule(input -> RegexUtil.matches(input, regex), exceptionCreator); + return this; + } + + // ===== matchesOne ===== + + public StringValidator matchesOne(Pattern[] regexs, String errMsg) { + return matchesOne(regexs, convertExceptionCreator(errMsg)); + } + + public StringValidator matchesOne( + Pattern[] regexs, + Supplier exceptionCreator) { + return matchesOne(regexs, convertExceptionCreator(exceptionCreator)); + } + + public StringValidator matchesOne( + Pattern[] regexs, + Function exceptionCreator) { + super.withRule(input -> RegexUtil.matchesOne(input, regexs), exceptionCreator); + return this; + } + + public StringValidator matchesOne(List regexs, String errMsg) { + return matchesOne(regexs, convertExceptionCreator(errMsg)); + } + + public StringValidator matchesOne( + List regexs, + Supplier exceptionCreator) { + return matchesOne(regexs, convertExceptionCreator(exceptionCreator)); + } + + public StringValidator matchesOne( + List regexs, + Function exceptionCreator) { + super.withRule(input -> RegexUtil.matchesOne(input, regexs.toArray(new Pattern[regexs.size()])), + exceptionCreator); + return this; + } + + // ===== matchesAll ===== + + public StringValidator matchesAll(Pattern[] regexs, String errMsg) { + return matchesAll(regexs, convertExceptionCreator(errMsg)); + } + + public StringValidator matchesAll( + Pattern[] regexs, + Supplier exceptionCreator) { + return matchesAll(regexs, convertExceptionCreator(exceptionCreator)); + } + + public StringValidator matchesAll( + Pattern[] regexs, + Function exceptionCreator) { + super.withRule(input -> RegexUtil.matchesAll(input, regexs), exceptionCreator); + return this; + } + + public StringValidator matchesAll(Collection regexs, String errMsg) { + return matchesAll(regexs, convertExceptionCreator(errMsg)); + } + + public StringValidator matchesAll( + Collection regexs, + Supplier exceptionCreator) { + return matchesAll(regexs, convertExceptionCreator(exceptionCreator)); + } + + public StringValidator matchesAll( + Collection regexs, + Function exceptionCreator) { + super.withRule(input -> RegexUtil.matchesAll(input, regexs.toArray(new Pattern[regexs.size()])), + exceptionCreator); + return this; + } + + // ====== notEmpty ===== + + public StringValidator notEmpty() { + return notEmpty("The string argument must not be empty."); + } + + public StringValidator notEmpty(String errMsg) { + return notEmpty(convertExceptionCreator(errMsg)); + } + + public StringValidator notEmpty(Supplier exceptionCreator) { + return notEmpty(convertExceptionCreator(exceptionCreator)); + } + + public StringValidator notEmpty( + Function exceptionCreator) { + super.withRule(Predicates.not(Strings::isNullOrEmpty), exceptionCreator); + return this; + } + + // ====== isEmpty ===== + + public StringValidator isEmpty() { + return notEmpty("The string argument must be empty."); + } + + public StringValidator isEmpty(String errMsg) { + return isEmpty(convertExceptionCreator(errMsg)); + } + + public StringValidator isEmpty(Supplier exceptionCreator) { + return isEmpty(convertExceptionCreator(exceptionCreator)); + } + + public StringValidator isEmpty( + Function exceptionCreator) { + super.withRule(Strings::isNullOrEmpty, exceptionCreator); + return this; + } + + @Override + protected StringValidator thisObject() { + return this; + } + } + + public static class ObjectValidator extends PropertyValidator> { + + ObjectValidator(Function getter) { + super(getter); + } + + @Override + protected ObjectValidator thisObject() { + return this; + } + } + + public static class CollectionValidator + extends PropertyValidator, CollectionValidator> { + + CollectionValidator(Function> getter) { + super(getter); + } + + // ====== notEmpty ===== + + public CollectionValidator notEmpty(String errMsg) { + return notEmpty(convertExceptionCreator(errMsg)); + } + + public CollectionValidator notEmpty(Supplier exceptionCreator) { + return notEmpty(convertExceptionCreator(exceptionCreator)); + } + + public CollectionValidator notEmpty( + Function, E> exceptionCreator) { + super.withRule(value -> value != null && !value.isEmpty(), exceptionCreator); + return this; + } + + // ====== isEmpty ===== + + public CollectionValidator isEmpty(String errMsg) { + return isEmpty(convertExceptionCreator(errMsg)); + } + + public CollectionValidator isEmpty(Supplier exceptionCreator) { + return isEmpty(convertExceptionCreator(exceptionCreator)); + } + + public CollectionValidator isEmpty( + Function, E> exceptionCreator) { + super.withRule(value -> value == null || value.isEmpty(), exceptionCreator); + return this; + } + + @Override + protected CollectionValidator thisObject() { + return this; + } + } + } diff --git a/src/main/java/xyz/zhouxy/plusone/validator/BoolValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/BoolValidator.java deleted file mode 100644 index 6d00130..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/BoolValidator.java +++ /dev/null @@ -1,58 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -import java.util.function.Function; -import java.util.function.Supplier; - -import org.apache.commons.lang3.BooleanUtils; - -public class BoolValidator extends PropertyValidator> { - - BoolValidator(Function getter) { - super(getter); - } - - // ====== isTrue ====== - - public BoolValidator isTrue() { - return isTrue("The value must be true."); - } - - public BoolValidator isTrue(String errMsg) { - return isTrue(convertExceptionCreator(errMsg)); - } - - public BoolValidator isTrue(Supplier exceptionCreator) { - return isTrue(convertExceptionCreator(exceptionCreator)); - } - - public BoolValidator isTrue( - Function exceptionCreator) { - withRule(BooleanUtils::isTrue, exceptionCreator); - return this; - } - - // ====== isFalse ====== - - public BoolValidator isFalse() { - return isFalse("The value must be false."); - } - - public BoolValidator isFalse(String errMsg) { - return isFalse(convertExceptionCreator(errMsg)); - } - - public BoolValidator isFalse(Supplier exceptionCreator) { - return isFalse(convertExceptionCreator(exceptionCreator)); - } - - public BoolValidator isFalse( - Function exceptionCreator) { - withRule(BooleanUtils::isFalse, exceptionCreator); - return this; - } - - @Override - protected BoolValidator thisObject() { - return this; - } -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/CollectionValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/CollectionValidator.java deleted file mode 100644 index cb434a1..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/CollectionValidator.java +++ /dev/null @@ -1,49 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -import java.util.Collection; -import java.util.function.Function; -import java.util.function.Supplier; - -public class CollectionValidator extends PropertyValidator, CollectionValidator> { - - CollectionValidator(Function> getter) { - super(getter); - } - - // ====== notEmpty ===== - - public CollectionValidator notEmpty(String errMsg) { - return notEmpty(convertExceptionCreator(errMsg)); - } - - public CollectionValidator notEmpty(Supplier exceptionCreator) { - return notEmpty(convertExceptionCreator(exceptionCreator)); - } - - public CollectionValidator notEmpty( - Function, E> exceptionCreator) { - withRule(value -> value != null && !value.isEmpty(), exceptionCreator); - return this; - } - - // ====== isEmpty ===== - - public CollectionValidator isEmpty(String errMsg) { - return isEmpty(convertExceptionCreator(errMsg)); - } - - public CollectionValidator isEmpty(Supplier exceptionCreator) { - return isEmpty(convertExceptionCreator(exceptionCreator)); - } - - public CollectionValidator isEmpty( - Function, E> exceptionCreator) { - withRule(value -> value == null || value.isEmpty(), exceptionCreator); - return this; - } - - @Override - protected CollectionValidator thisObject() { - return this; - } -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/DoubleValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/DoubleValidator.java deleted file mode 100644 index 5e02774..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/DoubleValidator.java +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -import java.util.function.Function; -import java.util.function.Supplier; - -public class DoubleValidator extends PropertyValidator> { - - DoubleValidator(Function getter) { - super(getter); - } - - public DoubleValidator between(double min, double max) { - return between(min, max, String.format("数值不在 %s 和 %s 之间", String.valueOf(min), String.valueOf(max))); - } - - public DoubleValidator between(double min, double max, String errMsg) { - return between(min, max, convertExceptionCreator(errMsg)); - } - - public DoubleValidator between(double min, double max, - Supplier exceptionCreator) { - return between(min, max, convertExceptionCreator(exceptionCreator)); - } - - public DoubleValidator between(double min, double max, - Function exceptionCreator) { - withRule(value -> (value >= min && value < max), exceptionCreator); - return this; - } - - @Override - protected DoubleValidator thisObject() { - return this; - } -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/IValidateRequired.java b/src/main/java/xyz/zhouxy/plusone/validator/IValidateRequired.java deleted file mode 100644 index 82e98ae..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/IValidateRequired.java +++ /dev/null @@ -1,13 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -/** - * 自带校验方法,校验不通过时直接抛异常。 - * - * @author ZhouXY - * - * @see ValidateUtil - * @see BaseValidator - */ -public interface IValidateRequired { - void validate(); -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/IntValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/IntValidator.java deleted file mode 100644 index 3327d39..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/IntValidator.java +++ /dev/null @@ -1,35 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -import java.util.function.Function; -import java.util.function.Supplier; - -public class IntValidator extends PropertyValidator> { - - IntValidator(Function getter) { - super(getter); - } - - public IntValidator between(int min, int max) { - return between(min, max, String.format("数值不在 %d 和 %d 之间", min, max)); - } - - public IntValidator between(int min, int max, String errMsg) { - return between(min, max, convertExceptionCreator(errMsg)); - } - - public IntValidator between(int min, int max, - Supplier exceptionCreator) { - return between(min, max, convertExceptionCreator(exceptionCreator)); - } - - public IntValidator between(int min, int max, - Function exceptionCreator) { - withRule(value -> (value >= min && value < max), exceptionCreator); - return this; - } - - @Override - protected IntValidator thisObject() { - return this; - } -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java b/src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java index 1bc1c30..25b0822 100644 --- a/src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java +++ b/src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java @@ -1,39 +1,31 @@ package xyz.zhouxy.plusone.validator; -import xyz.zhouxy.plusone.commons.exception.BaseRuntimeException; - /** - * 4040000 - 用户请求参数错误 + * 用户请求参数错误 * - * @author ZhouXY + * @author ZhouXY */ -public class InvalidInputException extends BaseRuntimeException { +public class InvalidInputException extends RuntimeException { private static final long serialVersionUID = 7956661913360059670L; - public static final String ERROR_CODE = "4040000"; - - protected InvalidInputException(String code, String msg) { - super(code, msg); + public InvalidInputException() { + super("用户请求参数错误"); } - protected InvalidInputException(String code, Throwable cause) { - super(code, cause); + public InvalidInputException(String msg) { + super(msg); } - protected InvalidInputException(String code, String msg, Throwable cause) { - super(code, msg, cause); + public InvalidInputException(String msgFormat, Object... args) { + super(String.format(msgFormat, args)); } - public static InvalidInputException of(String msg) { - return new InvalidInputException(ERROR_CODE, msg); + public InvalidInputException(Throwable cause) { + super(cause); } - public static InvalidInputException of(Throwable cause) { - return new InvalidInputException(ERROR_CODE, cause); - } - - public static InvalidInputException of(String msg, Throwable cause) { - return new InvalidInputException(ERROR_CODE, msg, cause); + public InvalidInputException(String msg, Throwable cause) { + super(msg, cause); } } diff --git a/src/main/java/xyz/zhouxy/plusone/validator/MapValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/MapValidator.java index 855010d..3fef02a 100644 --- a/src/main/java/xyz/zhouxy/plusone/validator/MapValidator.java +++ b/src/main/java/xyz/zhouxy/plusone/validator/MapValidator.java @@ -10,15 +10,24 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; -public class MapValidator { +import xyz.zhouxy.plusone.validator.BaseValidator.*; + +public abstract class MapValidator { private final List>> rules = new ArrayList<>(); private final List, ?, ?>> propertyValidators = new ArrayList<>(); - protected void withRule(final Predicate> rule, final String errorMessage) { - withRule(rule, () -> InvalidInputException.of(errorMessage)); + private final String[] propertyNames; + + protected MapValidator(List propertyNames) { + this.propertyNames = propertyNames.toArray(new String[0]); } - protected void withRule(Predicate> rule, Supplier exceptionBuilder) { + protected void withRule(final Predicate> rule, final String errorMessage) { + withRule(rule, () -> new InvalidInputException(errorMessage)); + } + + protected void withRule(Predicate> rule, + Supplier exceptionBuilder) { withRule(rule, value -> exceptionBuilder.get()); } @@ -68,11 +77,16 @@ public class MapValidator { @SuppressWarnings("unchecked") protected final CollectionValidator, E> ruleForCollection(String key) { - CollectionValidator, E> validValueHolder = new CollectionValidator<>(m -> (Collection) m.get(key)); + CollectionValidator, E> validValueHolder = new CollectionValidator<>( + m -> (Collection) m.get(key)); propertyValidators.add(validValueHolder); return validValueHolder; } + public Map validate(Map obj) { + return this.validate(obj, this.propertyNames); + } + public Map validate(Map obj, String... keys) { for (Consumer> rule : this.rules) { rule.accept(obj); diff --git a/src/main/java/xyz/zhouxy/plusone/validator/ObjectValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/ObjectValidator.java deleted file mode 100644 index 6f2de5f..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/ObjectValidator.java +++ /dev/null @@ -1,15 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -import java.util.function.Function; - -public class ObjectValidator extends PropertyValidator> { - - ObjectValidator(Function getter) { - super(getter); - } - - @Override - protected ObjectValidator thisObject() { - return this; - } -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/PropertyValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/PropertyValidator.java deleted file mode 100644 index fc08f0f..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/PropertyValidator.java +++ /dev/null @@ -1,156 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -import java.util.Collection; -import java.util.Objects; -import java.util.function.Consumer; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; - -abstract class PropertyValidator { - Function getter; - Validator validator = new Validator<>(); - - PropertyValidator(Function getter) { - this.getter = getter; - } - - void withRule(Predicate condition, - Function exceptionCreator) { - withRule(value -> { - if (!condition.test(value)) { - throw exceptionCreator.apply(value); - } - }); - } - - private void withRule(Consumer rule) { - this.validator.addRule(rule); - } - - // ==================== - // ====== Object ====== - // ==================== - - // ====== notNull ===== - - public THIS notNull() { - return notNull("Value could not be null."); - } - - public THIS notNull(String errMsg) { - return notNull(convertExceptionCreator(errMsg)); - } - - public THIS notNull(Supplier exceptionCreator) { - return notNull(convertExceptionCreator(exceptionCreator)); - } - - public THIS notNull(Function exceptionCreator) { - withRule(Objects::nonNull, exceptionCreator); - return thisObject(); - } - - // ====== isNull ===== - - public THIS isNull(String errMsg) { - return isNull(convertExceptionCreator(errMsg)); - } - - public THIS isNull(Supplier exceptionCreator) { - return isNull(convertExceptionCreator(exceptionCreator)); - } - - public THIS isNull(Function exceptionCreator) { - withRule(Objects::isNull, exceptionCreator); - return thisObject(); - } - - // ===== equals ===== - - public THIS equalsThat(Object that) { - return equalsThat(that, value -> InvalidInputException.of(String.format("(%s) 必须与 (%s) 相等", value, that))); - } - - public THIS equalsThat(Object that, String errMsg) { - return equalsThat(that, convertExceptionCreator(errMsg)); - } - - public THIS equalsThat( - Object that, Supplier exceptionCreator) { - return equalsThat(that, convertExceptionCreator(exceptionCreator)); - } - - public THIS equalsThat( - Object that, Function exceptionCreator) { - withRule(value -> Objects.equals(value, that), exceptionCreator); - return thisObject(); - } - - // ===== isTrue ===== - - public THIS isTrue(Predicate condition) { - return isTrue(condition, "无效的用户输入"); - } - - public THIS isTrue(Predicate condition, String errMsg) { - return isTrue(condition, convertExceptionCreator(errMsg)); - } - - public THIS isTrue( - Predicate condition, - Supplier exceptionCreator) { - return isTrue(condition, convertExceptionCreator(exceptionCreator)); - } - - public THIS isTrue( - Predicate condition, - Function exceptionCreator) { - withRule(condition, exceptionCreator); - return thisObject(); - } - - // ===== isTrue ===== - - public THIS isTrue(Collection> conditions) { - return isTrue(conditions, "无效的用户输入"); - } - - public THIS isTrue(Collection> conditions, String errMsg) { - return isTrue(conditions, convertExceptionCreator(errMsg)); - } - - public THIS isTrue( - Collection> conditions, - Supplier exceptionCreator) { - return isTrue(conditions, convertExceptionCreator(exceptionCreator)); - } - - public THIS isTrue( - Collection> conditions, - Function exceptionCreator) { - for (Predicate condition : conditions) { - withRule(condition, exceptionCreator); - } - return thisObject(); - } - - // ======================================================================== - - @SuppressWarnings("unchecked") - void validate(DTO obj) { - PROPERTY value = (PROPERTY) this.getter.apply(obj); - this.validator.validate(value); - } - - static Function convertExceptionCreator(String errMsg) { - return value -> InvalidInputException.of(errMsg); - } - - static Function convertExceptionCreator( - Supplier exceptionSupplier) { - return value -> exceptionSupplier.get(); - } - - protected abstract THIS thisObject(); -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/StringValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/StringValidator.java deleted file mode 100644 index 79863d1..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/StringValidator.java +++ /dev/null @@ -1,189 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -import java.util.Collection; -import java.util.List; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.regex.Pattern; - -import org.apache.commons.lang3.StringUtils; - -import xyz.zhouxy.plusone.commons.constant.PatternConsts; -import xyz.zhouxy.plusone.commons.util.RegexUtil; - -public class StringValidator extends PropertyValidator> { - - StringValidator(Function getter) { - super(getter); - } - - // ==================== - // ====== String ====== - // ==================== - - // ===== matches ===== - - public StringValidator matches(Pattern regex, String errMsg) { - return matches(regex, convertExceptionCreator(errMsg)); - } - - public StringValidator matches( - Pattern regex, - Supplier exceptionCreator) { - return matches(regex, convertExceptionCreator(exceptionCreator)); - } - - public StringValidator matches( - Pattern regex, - Function exceptionCreator) { - withRule(input -> RegexUtil.matches(input, regex), exceptionCreator); - return this; - } - - // ===== matchesOne ===== - - public StringValidator matchesOne(Pattern[] regexs, String errMsg) { - return matchesOne(regexs, convertExceptionCreator(errMsg)); - } - - public StringValidator matchesOne( - Pattern[] regexs, - Supplier exceptionCreator) { - return matchesOne(regexs, convertExceptionCreator(exceptionCreator)); - } - - public StringValidator matchesOne( - Pattern[] regexs, - Function exceptionCreator) { - withRule(input -> RegexUtil.matchesOne(input, regexs), exceptionCreator); - return this; - } - - public StringValidator matchesOne(List regexs, String errMsg) { - return matchesOne(regexs, convertExceptionCreator(errMsg)); - } - - public StringValidator matchesOne( - List regexs, - Supplier exceptionCreator) { - return matchesOne(regexs, convertExceptionCreator(exceptionCreator)); - } - - public StringValidator matchesOne( - List regexs, - Function exceptionCreator) { - withRule(input -> RegexUtil.matchesOne(input, regexs.toArray(new Pattern[regexs.size()])), exceptionCreator); - return this; - } - - // ===== matchesAll ===== - - public StringValidator matchesAll(Pattern[] regexs, String errMsg) { - return matchesAll(regexs, convertExceptionCreator(errMsg)); - } - - public StringValidator matchesAll( - Pattern[] regexs, - Supplier exceptionCreator) { - return matchesAll(regexs, convertExceptionCreator(exceptionCreator)); - } - - public StringValidator matchesAll( - Pattern[] regexs, - Function exceptionCreator) { - withRule(input -> RegexUtil.matchesAll(input, regexs), exceptionCreator); - return this; - } - - public StringValidator matchesAll(Collection regexs, String errMsg) { - return matchesAll(regexs, convertExceptionCreator(errMsg)); - } - - public StringValidator matchesAll( - Collection regexs, - Supplier exceptionCreator) { - return matchesAll(regexs, convertExceptionCreator(exceptionCreator)); - } - - public StringValidator matchesAll( - Collection regexs, - Function exceptionCreator) { - withRule(input -> RegexUtil.matchesAll(input, regexs.toArray(new Pattern[regexs.size()])), exceptionCreator); - return this; - } - - // ===== notBlank ===== - - public StringValidator notBlank() { - return notBlank("This String argument must have text; it must not be null, empty, or blank"); - } - - public StringValidator notBlank(String errMsg) { - return notBlank(convertExceptionCreator(errMsg)); - } - - public StringValidator notBlank(Supplier exceptionCreator) { - return notBlank(convertExceptionCreator(exceptionCreator)); - } - - public StringValidator notBlank( - Function exceptionCreator) { - withRule(StringUtils::isNotBlank, exceptionCreator); - return this; - } - - // ===== email ===== - - public StringValidator email() { - return email("The value is not an email address."); - } - - public StringValidator email(String errMsg) { - return email(convertExceptionCreator(errMsg)); - } - - public StringValidator email(Supplier exceptionCreator) { - return email(convertExceptionCreator(exceptionCreator)); - } - - public StringValidator email(Function exceptionCreator) { - return matches(PatternConsts.EMAIL, exceptionCreator); - } - - // ====== notEmpty ===== - - public StringValidator notEmpty(String errMsg) { - return notEmpty(convertExceptionCreator(errMsg)); - } - - public StringValidator notEmpty(Supplier exceptionCreator) { - return notEmpty(convertExceptionCreator(exceptionCreator)); - } - - public StringValidator notEmpty( - Function exceptionCreator) { - withRule(StringUtils::isNotEmpty, exceptionCreator); - return this; - } - - // ====== isEmpty ===== - - public StringValidator isEmpty(String errMsg) { - return isEmpty(convertExceptionCreator(errMsg)); - } - - public StringValidator isEmpty(Supplier exceptionCreator) { - return isEmpty(convertExceptionCreator(exceptionCreator)); - } - - public StringValidator isEmpty( - Function exceptionCreator) { - withRule(StringUtils::isEmpty, exceptionCreator); - return this; - } - - @Override - protected StringValidator thisObject() { - return this; - } -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/ValidateUtil.java b/src/main/java/xyz/zhouxy/plusone/validator/ValidateUtil.java deleted file mode 100644 index 1a8438d..0000000 --- a/src/main/java/xyz/zhouxy/plusone/validator/ValidateUtil.java +++ /dev/null @@ -1,29 +0,0 @@ -package xyz.zhouxy.plusone.validator; - -/** - * 校验工具类 - *

- * 对 {@link IValidateRequired} 的实现类对象进行校验 - *

- * - * @author ZhouXY - * - * @see BaseValidator - * @see Validator - * @see IValidateRequired - */ -public class ValidateUtil { - private ValidateUtil() { - throw new IllegalStateException("Utility class"); - } - - public static void validate(Object obj) { - if (obj instanceof IValidateRequired) { - ((IValidateRequired) obj).validate(); - } - } - - public static void validate(T obj, BaseValidator validator) { - validator.validate(obj); - } -} diff --git a/src/main/java/xyz/zhouxy/plusone/validator/Validator.java b/src/main/java/xyz/zhouxy/plusone/validator/Validator.java index f5a730a..405570d 100644 --- a/src/main/java/xyz/zhouxy/plusone/validator/Validator.java +++ b/src/main/java/xyz/zhouxy/plusone/validator/Validator.java @@ -32,7 +32,7 @@ import java.util.function.Supplier; * *

* - * @author ZhouXY + * @author ZhouXY * @see IValidateRequired * @see ValidateUtil * @see BaseValidator diff --git a/src/test/java/xyz/zhouxy/plusone/constant/Patterns.java b/src/test/java/xyz/zhouxy/plusone/constant/Patterns.java new file mode 100644 index 0000000..ef679b1 --- /dev/null +++ b/src/test/java/xyz/zhouxy/plusone/constant/Patterns.java @@ -0,0 +1,37 @@ +package xyz.zhouxy.plusone.constant; + +import java.util.regex.Pattern; + +public enum Patterns { + DATE("^\\d{4}-\\d{2}-\\d{2}"), + + PASSWORD("^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[\\w\\\\!#$%&'*\\+\\-/=?^`{|}~@\\(\\)\\[\\]\",\\.;':><]{8,32}$"), + + CAPTCHA("^[0-9A-Za-z]{4,6}$"), + + EMAIL("^\\w+([-+.]\\w+)*@[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})*(\\.(?![0-9]+$)[a-zA-Z0-9][-0-9A-Za-z]{0,62})$"), + + MOBILE_PHONE("^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\\d{8}$"), + + USERNAME("^[\\da-zA-Z_.@\\\\]{4,36}$"), + + NICKNAME("^[\\da-zA-Z_.@\\\\]{4,36}$"), + + ; + + private final String regex; + private final Pattern pattern; + + Patterns(String regex) { + this.regex = regex; + this.pattern = Pattern.compile(regex); + } + + public String getRegex() { + return regex; + } + + public Pattern getPattern() { + return pattern; + } +} diff --git a/src/test/java/xyz/zhouxy/plusone/map/MapValidatorTests.java b/src/test/java/xyz/zhouxy/plusone/map/MapValidatorTests.java index 4336f3f..0f90d14 100644 --- a/src/test/java/xyz/zhouxy/plusone/map/MapValidatorTests.java +++ b/src/test/java/xyz/zhouxy/plusone/map/MapValidatorTests.java @@ -2,13 +2,13 @@ package xyz.zhouxy.plusone.map; import java.util.Arrays; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.regex.Pattern; import org.junit.jupiter.api.Test; -import xyz.zhouxy.plusone.commons.constant.PatternConsts; +import xyz.zhouxy.plusone.constant.Patterns; import xyz.zhouxy.plusone.validator.MapValidator; class MapValidatorTests { @@ -17,34 +17,52 @@ class MapValidatorTests { void testMapValidator() { Map params = new HashMap<>(); params.put("username", "ZhouXY"); - params.put("admin", true); + params.put("account", "zhouxy@code108.cn"); params.put("password", "99Code108"); params.put("password2", "99Code108"); - params.put("test", "88gggg"); - params.put("roles", Arrays.asList("admin", "ZhongShanAdmin")); + params.put("age", 25); + params.put("boolean", true); + params.put("roleList", Arrays.asList("admin", "")); - params = RegisterParamsValidator.INSTANCE - .validate(params, "roles", "username", "admin", "password"); - System.out.println(params); + Map validedParams = TestValidator.INSTANCE + .validate(params); + System.out.println(validedParams); } } -class RegisterParamsValidator extends MapValidator { - RegisterParamsValidator() { - this.>ruleFor("roles") - .notNull(() -> new NullPointerException("roles")); - this.ruleForString("username") - .matches(PatternConsts.USERNAME, "用户名不符合条件!"); - this.ruleForBool("admin") +class TestValidator extends MapValidator { + private static final String USERNAME = "username"; + private static final String ACCOUNT = "account"; + private static final String PASSWORD = "password"; + private static final String PASSWORD2 = "password2"; + private static final String AGE = "age"; + private static final String BOOLEAN = "boolean"; + private static final String ROLE_LIST = "roleList"; + + TestValidator() { + super(Arrays.asList(USERNAME, ACCOUNT, PASSWORD, AGE, BOOLEAN, ROLE_LIST)); + this.ruleForString(USERNAME) + .notEmpty() + .matches(Patterns.USERNAME.getPattern(), + username -> new IllegalArgumentException(String.format("用户名【%s】不符合规范", username))); + this.ruleForString(ACCOUNT) + .notEmpty() + .matchesOne(new Pattern[] { Patterns.EMAIL.getPattern(), Patterns.MOBILE_PHONE.getPattern() }, "请输入正确的邮箱地址或手机号"); + this.ruleForString(PASSWORD) + .notEmpty("密码不能为空") + .matches(Patterns.PASSWORD.getPattern(), "密码不符合规范"); + this.withRule(m -> Objects.equals(m.get(PASSWORD), m.get(PASSWORD2)), + "两次输入的密码不一样!"); + this.ruleForInt(AGE) + .notNull() + .isTrue(age -> (18 <= age && 60 >= age)); + this.ruleForBool(BOOLEAN) .notNull("admin could not be null.") .isTrue("admin must be true."); - this.ruleForString("password") - .notBlank("密码不能为空!") - .matches(PatternConsts.PASSWORD, "密码格式错误!"); - this.ruleForCollection("roles") + this.ruleForCollection(ROLE_LIST) + .notNull(() -> new NullPointerException(ROLE_LIST)) .notEmpty("角色列表不能为空!"); - this.withRule(m -> Objects.equals(m.get("password"), m.get("password2")), - "两次输入的密码不一样!"); } - static final RegisterParamsValidator INSTANCE = new RegisterParamsValidator(); + + static final TestValidator INSTANCE = new TestValidator(); } diff --git a/src/test/java/xyz/zhouxy/plusone/validator2/test/ValidatorTests.java b/src/test/java/xyz/zhouxy/plusone/pojo/ValidatorTests.java similarity index 61% rename from src/test/java/xyz/zhouxy/plusone/validator2/test/ValidatorTests.java rename to src/test/java/xyz/zhouxy/plusone/pojo/ValidatorTests.java index 1f13f38..92eadfc 100644 --- a/src/test/java/xyz/zhouxy/plusone/validator2/test/ValidatorTests.java +++ b/src/test/java/xyz/zhouxy/plusone/pojo/ValidatorTests.java @@ -1,8 +1,10 @@ -package xyz.zhouxy.plusone.validator2.test; +package xyz.zhouxy.plusone.pojo; -import static xyz.zhouxy.plusone.commons.constant.PatternConsts.*; +import static xyz.zhouxy.plusone.constant.Patterns.*; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; @@ -10,8 +12,7 @@ import org.junit.jupiter.api.Test; import com.google.common.base.Preconditions; -import xyz.zhouxy.plusone.commons.function.Predicates; -import xyz.zhouxy.plusone.commons.util.MoreCollections; +import xyz.zhouxy.plusone.commons.util.Predicates; import xyz.zhouxy.plusone.commons.util.RegexUtil; import xyz.zhouxy.plusone.validator.Validator; @@ -30,76 +31,37 @@ class ValidatorTests { return Objects.nonNull(username) && StringUtils.isNotEmpty(username) && StringUtils.isNotBlank(username) - && RegexUtil.matches(username, USERNAME); + && RegexUtil.matches(username, USERNAME.getPattern()); }, command -> new IllegalArgumentException(String.format("用户名【%s】不符合规范", command.getUsername()))) // 传入 predicate 和 error message .addRule(command -> Predicates .of(Objects::nonNull) - .and(account -> RegexUtil.matchesOne(account, new Pattern[] { EMAIL, MOBILE_PHONE })) + .and(account -> RegexUtil.matchesOne(account, new Pattern[] { EMAIL.getPattern(), MOBILE_PHONE.getPattern() })) .test(command.getAccount()), "请输入邮箱地址或手机号") // 传入 rule .addRule(command -> { String code = command.getCode(); Preconditions.checkArgument(Objects.nonNull(code), "验证码不能为空"); - Preconditions.checkArgument(RegexUtil.matches(code, CAPTCHA), "验证码不符合规范"); + Preconditions.checkArgument(RegexUtil.matches(code, CAPTCHA.getPattern()), "验证码不符合规范"); }) // 传入 rule .addRule(command -> { String password = command.getPassword(); Preconditions.checkArgument(StringUtils.isNotEmpty(password), "密码不能为空"); - Preconditions.checkArgument(RegexUtil.matches(password, PASSWORD), "密码不符合规范"); + Preconditions.checkArgument(RegexUtil.matches(password, PASSWORD.getPattern()), "密码不符合规范"); }) // 传入 predicate 和 Supplier - .addRule(command -> MoreCollections.isNotEmpty(command.getRoles()), - () -> new RuntimeException("角色列表不能为空")) + .addRule(command -> { + List roles = command.getRoles(); + return roles != null && !roles.isEmpty(); + }, () -> new RuntimeException("角色列表不能为空")) // 传入 predicate 和 error message .addRule(command -> Objects.equals(command.getPassword(), command.getPassword2()), "两次输入的密码不一致"); registerCommandValidator.validate(registerCommand); System.out.println(registerCommand); } - @Test - void testValidateMap() { - Map params = new HashMap<>(); - params.put("username", "zhouxy"); - params.put("account", "zhouxy@code108.cn"); - params.put("password", "89wy7G78gu7ggahB2"); - params.put("age", 25); - params.put("roles", Arrays.asList("", "admin")); - - Validator> registerCommandValidator = new Validator>() - // 传入 predicate 和 Function - .addRule(command -> { - String username = (String) command.get("username"); - return Objects.nonNull(username) - && StringUtils.isNotEmpty(username) - && StringUtils.isNotBlank(username) - && RegexUtil.matches(username, USERNAME); - }, command -> new IllegalArgumentException(String.format("用户名【%s】不符合规范", command.get("username")))) - // 传入 predicate 和 error message - .addRule(command -> Predicates - .of(Objects::nonNull) - .and(account -> RegexUtil.matchesOne(account, new Pattern[] { EMAIL, MOBILE_PHONE })) - .test((String) command.get("account")), - "请输入邮箱地址或手机号") - // 传入 rule - .addRule(command -> { - String password = (String) command.get("password"); - Preconditions.checkArgument(StringUtils.isNotEmpty(password), "密码不能为空"); - Preconditions.checkArgument(RegexUtil.matches(password, PASSWORD), "密码不符合规范"); - }) - // 传入 predicate 和 Supplier - .addRule(command -> MoreCollections.isNotEmpty((List) command.get("roles")), - () -> new RuntimeException("角色列表不能为空")) - .addRule(command -> { - Integer age = (Integer) command.get("age"); - Preconditions.checkNotNull(age); - Preconditions.checkArgument(18 < age && 60 >= age); - }); - registerCommandValidator.validate(params); - System.out.println(params); - } } /** diff --git a/src/test/java/xyz/zhouxy/plusone/validator/test/BaseValidatorTest.java b/src/test/java/xyz/zhouxy/plusone/validator/test/BaseValidatorTest.java deleted file mode 100644 index d6e2927..0000000 --- a/src/test/java/xyz/zhouxy/plusone/validator/test/BaseValidatorTest.java +++ /dev/null @@ -1,137 +0,0 @@ -package xyz.zhouxy.plusone.validator.test; - -import java.util.Arrays; -import java.util.List; -import java.util.Objects; - -import org.apache.commons.lang3.StringUtils; -import org.junit.jupiter.api.Test; - -import xyz.zhouxy.plusone.commons.constant.PatternConsts; -import xyz.zhouxy.plusone.commons.function.Predicates; -import xyz.zhouxy.plusone.commons.util.RegexUtil; -import xyz.zhouxy.plusone.validator.BaseValidator; -import xyz.zhouxy.plusone.validator.ValidateUtil; - -class BaseValidatorTest { - @Test - void testValidate() { - RegisterCommand registerCommand = new RegisterCommand("zhouxy108", "luquanlion@outlook.com", "22336", "A1b2C3d4", - "A1b2C3d4", - Arrays.asList(new String[] { "admin", "editor" })); - RegisterCommandValidator.INSTANCE.validate(registerCommand); - ValidateUtil.validate(registerCommand, RegisterCommandValidator.INSTANCE); - System.out.println(registerCommand); - } -} - -class RegisterCommandValidator extends BaseValidator { - - static final RegisterCommandValidator INSTANCE = new RegisterCommandValidator(); - - private RegisterCommandValidator() { - ruleForString(RegisterCommand::getUsername) - .isTrue(Predicates.of(Objects::nonNull) - .and(StringUtils::isNotEmpty) - .and(StringUtils::isNotBlank) - .and(username -> RegexUtil.matches(username, PatternConsts.USERNAME)), - username -> new IllegalArgumentException(String.format("用户名【%s】不符合规范", username))); - ruleForString(RegisterCommand::getAccount) - .notNull("请输入邮箱地址或手机号") - .matchesOne(Arrays.asList(PatternConsts.EMAIL, PatternConsts.MOBILE_PHONE), "请输入邮箱地址或手机号"); - ruleForString(RegisterCommand::getCode) - .notNull("验证码不能为空") - .matches(PatternConsts.CAPTCHA, "验证码不符合规范"); - ruleForString(RegisterCommand::getPassword) - .notEmpty("密码不能为空") - .matches(PatternConsts.PASSWORD, "密码不符合规范"); - ruleForCollection(RegisterCommand::getRoles) - .notEmpty(() -> new RuntimeException("角色列表不能为空")); - - withRule(registerCommand -> Objects.equals(registerCommand.getPassword(), registerCommand.getPassword2()), - "两次输入的密码不一致"); - } -} - -/** - * RegisterCommand - */ -class RegisterCommand { - - private String username; - private String account; - private String code; - private String password; - private String password2; - private List roles; - - public RegisterCommand() { - } - - public RegisterCommand(String username, String account, String code, String password, String password2, - List roles) { - this.username = username; - this.account = account; - this.code = code; - this.password = password; - this.password2 = password2; - this.roles = roles; - } - - public String getUsername() { - return username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getAccount() { - return account; - } - - public void setAccount(String account) { - this.account = account; - } - - public String getCode() { - return code; - } - - public void setCode(String code) { - this.code = code; - } - - public String getPassword() { - return password; - } - - public void setPassword(String password) { - this.password = password; - } - - public String getPassword2() { - return password2; - } - - public void setPassword2(String password2) { - this.password2 = password2; - } - - public List getRoles() { - return roles; - } - - public void setRoles(List roles) { - this.roles = roles; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("RegisterCommand [username=").append(username).append(", account=").append(account) - .append(", code=").append(code).append(", password=").append(password).append(", password2=") - .append(password2).append(", roles=").append(roles).append("]"); - return builder.toString(); - } -}