diff --git a/src/main/java/xyz/zhouxy/plusone/validator/MapValidator.java b/src/main/java/xyz/zhouxy/plusone/validator/MapValidator.java new file mode 100644 index 0000000..cfc4437 --- /dev/null +++ b/src/main/java/xyz/zhouxy/plusone/validator/MapValidator.java @@ -0,0 +1,87 @@ +package xyz.zhouxy.plusone.validator; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public 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)); + } + + protected void withRule(Predicate> rule, Supplier exceptionBuilder) { + withRule(rule, value -> exceptionBuilder.get()); + } + + protected void withRule(Predicate> condition, + Function, E> exceptionBuilder) { + withRule(value -> { + if (!condition.test(value)) { + throw exceptionBuilder.apply(value); + } + }); + } + + protected void withRule(Consumer> rule) { + this.rules.add(rule); + } + + protected final ObjectValidator, R> ruleFor(String key) { + ObjectValidator, R> validValueHolder = new ObjectValidator<>(map -> (R) map.get(key)); + propertyValidators.add(validValueHolder); + return validValueHolder; + } + + protected final IntValidator> ruleForInt(String key) { + IntValidator> validValueHolder = new IntValidator<>(map -> map.get(key)); + propertyValidators.add(validValueHolder); + return validValueHolder; + } + + protected final DoubleValidator> ruleForDouble(String key) { + DoubleValidator> validValueHolder = new DoubleValidator<>(map -> map.get(key)); + propertyValidators.add(validValueHolder); + return validValueHolder; + } + + protected final BoolValidator> ruleForBool(String key) { + BoolValidator> validValueHolder = new BoolValidator<>(map -> map.get(key)); + propertyValidators.add(validValueHolder); + return validValueHolder; + } + + protected final StringValidator> ruleForString(String key) { + StringValidator> validValueHolder = new StringValidator<>(map -> map.get(key)); + propertyValidators.add(validValueHolder); + return validValueHolder; + } + + protected final CollectionValidator, E> ruleForCollection(String key) { + CollectionValidator, E> validValueHolder = new CollectionValidator<>(m -> (Collection) m.get(key)); + propertyValidators.add(validValueHolder); + return validValueHolder; + } + + public Map validate(Map obj, String... keys) { + for (Consumer> rule : this.rules) { + rule.accept(obj); + } + for (PropertyValidator, ?, ?> valueValidator : this.propertyValidators) { + valueValidator.validate(obj); + } + final Map result = new HashMap<>(keys.length); + for (String key : keys) { + result.put(key, obj.get(key)); + } + return result; + } +} diff --git a/src/test/java/xyz/zhouxy/plusone/map/MapValidatorTests.java b/src/test/java/xyz/zhouxy/plusone/map/MapValidatorTests.java new file mode 100644 index 0000000..4336f3f --- /dev/null +++ b/src/test/java/xyz/zhouxy/plusone/map/MapValidatorTests.java @@ -0,0 +1,50 @@ +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 org.junit.jupiter.api.Test; + +import xyz.zhouxy.plusone.commons.constant.PatternConsts; +import xyz.zhouxy.plusone.validator.MapValidator; + +class MapValidatorTests { + + @Test + void testMapValidator() { + Map params = new HashMap<>(); + params.put("username", "ZhouXY"); + params.put("admin", true); + params.put("password", "99Code108"); + params.put("password2", "99Code108"); + params.put("test", "88gggg"); + params.put("roles", Arrays.asList("admin", "ZhongShanAdmin")); + + params = RegisterParamsValidator.INSTANCE + .validate(params, "roles", "username", "admin", "password"); + System.out.println(params); + } +} + +class RegisterParamsValidator extends MapValidator { + RegisterParamsValidator() { + this.>ruleFor("roles") + .notNull(() -> new NullPointerException("roles")); + this.ruleForString("username") + .matches(PatternConsts.USERNAME, "用户名不符合条件!"); + this.ruleForBool("admin") + .notNull("admin could not be null.") + .isTrue("admin must be true."); + this.ruleForString("password") + .notBlank("密码不能为空!") + .matches(PatternConsts.PASSWORD, "密码格式错误!"); + this.ruleForCollection("roles") + .notEmpty("角色列表不能为空!"); + this.withRule(m -> Objects.equals(m.get("password"), m.get("password2")), + "两次输入的密码不一样!"); + } + static final RegisterParamsValidator INSTANCE = new RegisterParamsValidator(); +} diff --git a/src/test/java/xyz/zhouxy/plusone/validator2/test/ValidatorTests.java b/src/test/java/xyz/zhouxy/plusone/validator2/test/ValidatorTests.java index 372052d..1f13f38 100644 --- a/src/test/java/xyz/zhouxy/plusone/validator2/test/ValidatorTests.java +++ b/src/test/java/xyz/zhouxy/plusone/validator2/test/ValidatorTests.java @@ -2,9 +2,7 @@ package xyz.zhouxy.plusone.validator2.test; import static xyz.zhouxy.plusone.commons.constant.PatternConsts.*; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; @@ -61,6 +59,47 @@ class ValidatorTests { 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); + } } /**