From 6facacb4b1899356e05926db5babfe7f77f7555c Mon Sep 17 00:00:00 2001
From: ZhouXY108
Date: Sat, 10 Dec 2022 23:16:04 +0800
Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=A0=A1=E9=AA=8C=E5=99=A8?=
=?UTF-8?q?=E3=80=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 5 +
.../zhouxy/plusone/constant/RegexConsts.java | 27 ++
.../xyz/zhouxy/plusone/util/RegexUtil.java | 36 ++
.../plusone/validator/BaseValidator.java | 86 ++++
.../validator/InvalidInputException.java | 53 +++
.../plusone/validator/ValidateUtil.java | 23 ++
.../zhouxy/plusone/validator/Validator.java | 42 ++
.../validator/validator2/BaseValidator2.java | 22 +
.../validator/validator2/ValueValidator.java | 379 ++++++++++++++++++
9 files changed, 673 insertions(+)
create mode 100644 src/main/java/xyz/zhouxy/plusone/constant/RegexConsts.java
create mode 100644 src/main/java/xyz/zhouxy/plusone/util/RegexUtil.java
create mode 100644 src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java
create mode 100644 src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java
create mode 100644 src/main/java/xyz/zhouxy/plusone/validator/ValidateUtil.java
create mode 100644 src/main/java/xyz/zhouxy/plusone/validator/Validator.java
create mode 100644 src/main/java/xyz/zhouxy/plusone/validator/validator2/BaseValidator2.java
create mode 100644 src/main/java/xyz/zhouxy/plusone/validator/validator2/ValueValidator.java
diff --git a/pom.xml b/pom.xml
index 5c25ec3..4f88683 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,5 +26,10 @@
jackson-annotations
2.13.4
+
+ cn.hutool
+ hutool-core
+ 5.8.9
+
\ No newline at end of file
diff --git a/src/main/java/xyz/zhouxy/plusone/constant/RegexConsts.java b/src/main/java/xyz/zhouxy/plusone/constant/RegexConsts.java
new file mode 100644
index 0000000..a34c436
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/constant/RegexConsts.java
@@ -0,0 +1,27 @@
+package xyz.zhouxy.plusone.constant;
+
+/**
+ * 正则表达式常量
+ *
+ * @author ZhouXY
+ */
+public final class RegexConsts {
+
+ public static final String DATE = "^\\d{4}-\\d{2}-\\d{2}";
+
+ public static final String PASSWORD = "^(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])[\\w\\\\!#$%&'*\\+\\-/=?^`{|}~@\\(\\)\\[\\]\",\\.;':><]{8,32}$";
+
+ public static final String CAPTCHA = "^[0-9A-Za-z]{4,6}$";
+
+ public static final String 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})$";
+
+ public static final String 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}$";
+
+ public static final String USERNAME = "^[\\da-zA-Z_.@\\\\]{4,36}$";
+
+ public static final String NICKNAME = "^[\\da-zA-Z_.@\\\\]{4,36}$";
+
+ private RegexConsts() {
+ throw new IllegalStateException("Utility class");
+ }
+}
diff --git a/src/main/java/xyz/zhouxy/plusone/util/RegexUtil.java b/src/main/java/xyz/zhouxy/plusone/util/RegexUtil.java
new file mode 100644
index 0000000..023160c
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/util/RegexUtil.java
@@ -0,0 +1,36 @@
+package xyz.zhouxy.plusone.util;
+
+import java.util.regex.Pattern;
+
+public class RegexUtil {
+
+ private RegexUtil() {
+ throw new IllegalStateException("Utility class");
+ }
+
+ public static boolean matches(CharSequence input, String regex) {
+ return Pattern.matches(regex, input);
+ }
+
+ public static boolean matchesOr(CharSequence input, String... regexs) {
+ boolean isMatched;
+ for (String regex : regexs) {
+ isMatched = Pattern.matches(regex, input);
+ if (isMatched) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean matchesAnd(CharSequence input, String... regexs) {
+ boolean isMatched;
+ for (String regex : regexs) {
+ isMatched = Pattern.matches(regex, input);
+ if (!isMatched) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java
new file mode 100644
index 0000000..08f13d0
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/validator/BaseValidator.java
@@ -0,0 +1,86 @@
+package xyz.zhouxy.plusone.validator;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * 校验器
+ *
+ *
+ * 可以使用以下方式初始化一个校验器:
+ *
+ *
+ *
+ * BaseValidator<Integer> validator = new BaseValidator<>() {
+ * {
+ * withRule(value -> Objects.nonNull(value), "value 不能为空");
+ * withRule(value -> (value >= 0 && value <= 500), "value 应在 [0, 500] 内");
+ * }
+ * };
+ *
+ *
+ *
+ * 也可以通过继承本类,定义一个校验器(可使用单例模式)。
+ *
+ *
+ *
+ * 然后通过校验器的 {@link #validate} 方法,或
+ * {@link ValidateUtil#validate(Object, Validator)} 对指定对象进行校验。
+ *
+ *
+ *
+ * ValidateUtil.validate(255, validator);
+ *
+ *
+ *
+ * validator.validate(666);
+ *
+ *
+ *
+ * @author ZhouXY
+ * @see IValidateRequired
+ * @see ValidateUtil
+ * @see Validator
+ */
+public abstract class BaseValidator {
+
+ private final List> rules = new ArrayList<>();
+
+ protected BaseValidator() {
+ }
+
+ protected final void withRule(Predicate rule, String errorMessage) {
+ withRule(rule, () -> new InvalidInputException(errorMessage));
+ }
+
+ protected final void withRule(Predicate rule, Supplier exceptionCreator) {
+ withRule(rule, value -> exceptionCreator.get());
+ }
+
+ protected final void withRule(Predicate rule, Function exceptionCreator) {
+ this.rules.add(new RuleInfo<>(rule, exceptionCreator));
+ }
+
+ public void validate(T obj) {
+ this.rules.forEach(ruleInfo -> ruleInfo.validate(obj));
+ }
+
+ protected static class RuleInfo {
+ private final Predicate rule;
+ private final Function exceptionCreator;
+
+ private RuleInfo(Predicate rule, Function exceptionCreator) {
+ this.rule = rule;
+ this.exceptionCreator = exceptionCreator;
+ }
+
+ private void validate(T obj) {
+ if (!rule.test(obj)) {
+ throw exceptionCreator.apply(obj);
+ }
+ }
+ }
+}
diff --git a/src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java b/src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java
new file mode 100644
index 0000000..5a23431
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/validator/InvalidInputException.java
@@ -0,0 +1,53 @@
+package xyz.zhouxy.plusone.validator;
+
+import xyz.zhouxy.plusone.exception.PlusoneException;
+
+/**
+ * 4040200 - 无效的用户输入
+ *
+ * @author ZhouXY
+ */
+public class InvalidInputException extends PlusoneException {
+
+ private static final long serialVersionUID = 7956661913360059670L;
+
+ public static final int ERROR_CODE = 4040200;
+
+ private InvalidInputException(int code, String msg) {
+ super(code, msg);
+ }
+
+ private InvalidInputException(int code, Throwable cause) {
+ super(code, cause);
+ }
+
+ private InvalidInputException(int code, String msg, Throwable cause) {
+ super(code, msg, cause);
+ }
+
+ public InvalidInputException(String msg) {
+ this(ERROR_CODE, msg);
+ }
+
+ public InvalidInputException(Throwable cause) {
+ this(ERROR_CODE, cause);
+ }
+
+ public InvalidInputException(String msg, Throwable cause) {
+ this(ERROR_CODE, msg, cause);
+ }
+
+ /**
+ * 不支持的 Principal 类型出现时抛出的异常
+ */
+ public static InvalidInputException unsupportedPrincipalTypeException() {
+ return unsupportedPrincipalTypeException("不支持的 PrincipalType");
+ }
+
+ /**
+ * 不支持的 Principal 类型出现时抛出的异常
+ */
+ public static InvalidInputException unsupportedPrincipalTypeException(String message) {
+ return new InvalidInputException(4040201, message);
+ }
+}
diff --git a/src/main/java/xyz/zhouxy/plusone/validator/ValidateUtil.java b/src/main/java/xyz/zhouxy/plusone/validator/ValidateUtil.java
new file mode 100644
index 0000000..438b197
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/validator/ValidateUtil.java
@@ -0,0 +1,23 @@
+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(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
new file mode 100644
index 0000000..b56ff50
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/validator/Validator.java
@@ -0,0 +1,42 @@
+package xyz.zhouxy.plusone.validator;
+
+import java.util.function.Predicate;
+
+/**
+ * 校验器
+ *
+ *
+ * 可以使用以下方式初始化一个校验器:
+ *
+ *
+ *
+ * var validator = new Validator<Integer>()
+ * .addRule(value -> Objects.nonNull(value), "value 不能为空")
+ * .addRule(value -> (value >= 0 && value <= 500), "value 应在 [0, 500] 内");
+ *
+ *
+ *
+ * 然后通过校验器的 {@link #validate} 方法,或
+ * {@link ValidateUtil#validate(Object, Validator)} 对指定对象进行校验。
+ *
+ *
+ *
+ * validator.validate(666);
+ *
+ *
+ *
+ * ValidateUtil.validate(255, validator);
+ *
+ *
+ *
+ * @author ZhouXY
+ * @see IValidateRequired
+ * @see ValidateUtil
+ * @see BaseValidator
+ */
+public final class Validator extends BaseValidator {
+ public final Validator addRule(final Predicate rule, final String errorMessage) {
+ withRule(rule, errorMessage);
+ return this;
+ }
+}
diff --git a/src/main/java/xyz/zhouxy/plusone/validator/validator2/BaseValidator2.java b/src/main/java/xyz/zhouxy/plusone/validator/validator2/BaseValidator2.java
new file mode 100644
index 0000000..257af16
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/validator/validator2/BaseValidator2.java
@@ -0,0 +1,22 @@
+package xyz.zhouxy.plusone.validator.validator2;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+public abstract class BaseValidator2 {
+
+ private List> valueValidators = new ArrayList<>();
+
+ protected final ValueValidator ruleFor(Function getter) {
+ ValueValidator validValueHolder = new ValueValidator<>(getter);
+ valueValidators.add(validValueHolder);
+ return validValueHolder;
+ }
+
+ public void validate(T obj) {
+ for (ValueValidator valueValidator : this.valueValidators) {
+ valueValidator.validateProperty(obj);
+ }
+ }
+}
diff --git a/src/main/java/xyz/zhouxy/plusone/validator/validator2/ValueValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/validator2/ValueValidator.java
new file mode 100644
index 0000000..e80b136
--- /dev/null
+++ b/src/main/java/xyz/zhouxy/plusone/validator/validator2/ValueValidator.java
@@ -0,0 +1,379 @@
+package xyz.zhouxy.plusone.validator.validator2;
+
+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 cn.hutool.core.util.StrUtil;
+import xyz.zhouxy.plusone.constant.RegexConsts;
+import xyz.zhouxy.plusone.util.RegexUtil;
+import xyz.zhouxy.plusone.validator.InvalidInputException;
+
+public class ValueValidator {
+ Function getter;
+ List> rules = new ArrayList<>();
+
+ public ValueValidator(Function getter) {
+ this.getter = getter;
+ }
+
+ private void withRule(Predicate condition,
+ Function exceptionCreator) {
+ withRule(value -> {
+ if (!condition.test(value)) {
+ throw exceptionCreator.apply(value);
+ }
+ });
+ }
+
+ private void withRule(Consumer rule) {
+ this.rules.add(rule);
+ }
+
+ // ====================
+ // ====== Object ======
+ // ====================
+
+ // ====== notNull =====
+
+ public ValueValidator notNull() {
+ return notNull("Value could not be null.");
+ }
+
+ public ValueValidator notNull(String errMsg) {
+ return notNull(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator notNull(Supplier exceptionCreator) {
+ return notNull(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator notNull(Function exceptionCreator) {
+ withRule(Objects::nonNull, exceptionCreator);
+ return this;
+ }
+
+ // ====== isNull =====
+
+ public ValueValidator isNull(String errMsg) {
+ return isNull(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator isNull(Supplier exceptionCreator) {
+ return isNull(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator isNull(Function exceptionCreator) {
+ withRule(Objects::isNull, exceptionCreator);
+ return this;
+ }
+
+ // ===== equals =====
+
+ public ValueValidator equalsThat(Object that) {
+ return equalsThat(that, value -> new InvalidInputException(String.format("(%s) 必须与 (%s) 相等", value, that)));
+ }
+
+ public ValueValidator equalsThat(Object that, String errMsg) {
+ return equalsThat(that, convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator equalsThat(
+ Object that, Supplier exceptionCreator) {
+ return equalsThat(that, convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator equalsThat(
+ Object that, Function exceptionCreator) {
+ withRule(value -> Objects.equals(value, that), exceptionCreator);
+ return this;
+ }
+
+ // ===== state =====
+
+ public ValueValidator state(Predicate condition) {
+ return state(condition, "无效的用户输入");
+ }
+
+ public ValueValidator state(Predicate condition, String errMsg) {
+ return state(condition, convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator state(
+ Predicate condition,
+ Supplier exceptionCreator) {
+ return state(condition, convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator state(
+ Predicate condition,
+ Function exceptionCreator) {
+ withRule(condition, exceptionCreator);
+ return this;
+ }
+
+ // =================
+ // ====== int ======
+ // =================
+
+ public ValueValidator between(int min, int max) {
+ return between(min, max, String.format("数值不在 %s 和 %s 之间", String.valueOf(min), String.valueOf(max)));
+ }
+
+ public ValueValidator between(int min, int max, String errMsg) {
+ return between(min, max, convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator between(int min, int max,
+ Supplier exceptionCreator) {
+ return between(min, max, convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator between(int min, int max,
+ Function exceptionCreator) {
+ withRule(value -> ((int) value >= min && (int) value < max), exceptionCreator);
+ return this;
+ }
+
+ // ====================
+ // ====== double ======
+ // ====================
+
+ public ValueValidator between(double min, double max) {
+ return between(min, max, String.format("数值不在 %s 和 %s 之间", String.valueOf(min), String.valueOf(max)));
+ }
+
+ public ValueValidator between(double min, double max, String errMsg) {
+ return between(min, max, convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator between(double min, double max,
+ Supplier exceptionCreator) {
+ return between(min, max, convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator between(double min, double max,
+ Function exceptionCreator) {
+ withRule(value -> ((double) value >= min && (double) value < max), exceptionCreator);
+ return this;
+ }
+
+ // ================================
+ // ====== Collection, String ======
+ // ================================
+
+ // ====== notEmpty =====
+
+ public ValueValidator notEmpty(String errMsg) {
+ return notEmpty(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator notEmpty(Supplier exceptionCreator) {
+ return notEmpty(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator notEmpty(Function exceptionCreator) {
+ withRule(value -> {
+ if (value == null) {
+ return false;
+ }
+ if (value instanceof Collection) {
+ return !((Collection>) value).isEmpty();
+ }
+ if (value instanceof String) {
+ return !((String) value).isEmpty();
+ }
+ return false;
+ }, exceptionCreator);
+ return this;
+ }
+
+ // ====== isEmpty =====
+
+ public ValueValidator isEmpty(String errMsg) {
+ return isEmpty(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator isEmpty(Supplier exceptionCreator) {
+ return isEmpty(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator isEmpty(Function exceptionCreator) {
+ withRule(value -> {
+ if (value == null) {
+ return false;
+ }
+ if (value instanceof Collection) {
+ return ((Collection>) value).isEmpty();
+ }
+ if (value instanceof String) {
+ return ((String) value).isEmpty();
+ }
+ return false;
+ }, exceptionCreator);
+ return this;
+ }
+
+ // =====================
+ // ====== boolean ======
+ // =====================
+
+ // ====== isTrue ======
+
+ public ValueValidator isTrue() {
+ return isTrue("The value must be true.");
+ }
+
+ public ValueValidator isTrue(String errMsg) {
+ return isTrue(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator isTrue(Supplier exceptionCreator) {
+ return isTrue(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator isTrue(Function exceptionCreator) {
+ withRule(Boolean.TRUE::equals, exceptionCreator);
+ return this;
+ }
+
+ // ====== isFalse ======
+
+ public ValueValidator isFalse() {
+ return isFalse("The value must be false.");
+ }
+
+ public ValueValidator isFalse(String errMsg) {
+ return isFalse(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator isFalse(Supplier exceptionCreator) {
+ return isFalse(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator isFalse(Function exceptionCreator) {
+ withRule(Boolean.FALSE::equals, exceptionCreator);
+ return this;
+ }
+
+ // ====================
+ // ====== String ======
+ // ====================
+
+ // ===== matches =====
+
+ public ValueValidator matches(String regex, String errMsg) {
+ return matches(regex, convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator matches(
+ String regex,
+ Supplier exceptionCreator) {
+ return matches(regex, convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator matches(
+ String regex,
+ Function exceptionCreator) {
+ withRule(input -> RegexUtil.matches((String) input, regex), exceptionCreator);
+ return this;
+ }
+
+ // ===== matchesOr =====
+
+ public ValueValidator matchesOr(String[] regexs, String errMsg) {
+ return matchesOr(regexs, convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator matchesOr(
+ String[] regexs,
+ Supplier exceptionCreator) {
+ return matchesOr(regexs, convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator matchesOr(
+ String[] regexs,
+ Function exceptionCreator) {
+ withRule(input -> RegexUtil.matchesOr((String) input, regexs), exceptionCreator);
+ return this;
+ }
+
+ // ===== matchesAnd =====
+
+ public ValueValidator matchesAnd(String[] regexs, String errMsg) {
+ return matchesAnd(regexs, convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator matchesAnd(
+ String[] regexs,
+ Supplier exceptionCreator) {
+ return matchesAnd(regexs, convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator matchesAnd(
+ String[] regexs,
+ Function exceptionCreator) {
+ withRule(input -> RegexUtil.matchesAnd((String) input, regexs), exceptionCreator);
+ return this;
+ }
+
+ // ===== notBlank =====
+
+ public ValueValidator notBlank() {
+ return notBlank("This String argument must have text; it must not be null, empty, or blank");
+ }
+
+ public ValueValidator notBlank(String errMsg) {
+ return notBlank(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator notBlank(Supplier exceptionCreator) {
+ return notBlank(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator notBlank(Function exceptionCreator) {
+ withRule(input -> StrUtil.isNotBlank((String) input), exceptionCreator);
+ return this;
+ }
+
+ // ===== email =====
+
+ public ValueValidator email() {
+ return email("The value is not an email address.");
+ }
+
+ public ValueValidator email(String errMsg) {
+ return email(convertExceptionCreator(errMsg));
+ }
+
+ public ValueValidator email(Supplier exceptionCreator) {
+ return email(convertExceptionCreator(exceptionCreator));
+ }
+
+ public ValueValidator email(Function exceptionCreator) {
+ return matches(RegexConsts.EMAIL, exceptionCreator);
+ }
+
+ // ========================================================================
+
+ void validateProperty(DTO obj) {
+ PROPERTY value = this.getter.apply(obj);
+ for (Consumer rule : this.rules) {
+ rule.accept(value);
+ }
+ }
+
+ private static Function convertExceptionCreator(String errMsg) {
+ return convertExceptionCreator(errMsg);
+ }
+
+ private static Function convertExceptionCreator(
+ Supplier exceptionSupplier) {
+ return value -> exceptionSupplier.get();
+ }
+}