mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-08 07:01:37 +08:00
feat(validation): 新增校验模块并引入 SpEL Validator 用于复杂校验场景
This commit is contained in:
37
continew-starter-validation/pom.xml
Normal file
37
continew-starter-validation/pom.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>continew-starter-validation</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>ContiNew Starter 验证模块</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>top.continew</groupId>
|
||||
<artifactId>continew-starter-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring Boot 校验模块(Hibernate Validator) -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpEL Validator(基于 SpEL 的 jakarta.validation-api 扩展增强包) -->
|
||||
<dependency>
|
||||
<groupId>cn.sticki</groupId>
|
||||
<artifactId>spel-validator-javax</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.validation.autoconfigure;
|
||||
|
||||
import jakarta.annotation.PostConstruct;
|
||||
import jakarta.validation.Validator;
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* JSR 303 校验器自动配置
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@AutoConfiguration
|
||||
public class ValidatorAutoConfiguration {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ValidatorAutoConfiguration.class);
|
||||
|
||||
/**
|
||||
* Validator 失败立即返回模式配置
|
||||
*
|
||||
* <p>
|
||||
* 默认情况下会校验完所有字段,然后才抛出异常。
|
||||
* </p>
|
||||
*/
|
||||
@Bean
|
||||
public Validator validator(MessageSource messageSource) {
|
||||
try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
|
||||
// 国际化
|
||||
factoryBean.setValidationMessageSource(messageSource);
|
||||
factoryBean.setProviderClass(HibernateValidator.class);
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("hibernate.validator.fail_fast", "true");
|
||||
factoryBean.setValidationProperties(properties);
|
||||
factoryBean.afterPropertiesSet();
|
||||
return factoryBean.getValidator();
|
||||
}
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Validator' completed initialization.");
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.validation.constraints;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
/**
|
||||
* 枚举校验注解
|
||||
*
|
||||
* <p>
|
||||
* {@code @EnumValue(value = XxxEnum.class, message = "参数值无效")} <br />
|
||||
* {@code @EnumValue(enumValues = {"F", "M"} ,message = "性别只允许为F或M")}
|
||||
* </p>
|
||||
*
|
||||
* @author Jasmine
|
||||
* @author Charles7c
|
||||
* @since 2.7.3
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = EnumValueValidator.class)
|
||||
public @interface EnumValue {
|
||||
|
||||
/**
|
||||
* 枚举类
|
||||
*
|
||||
* @return 枚举类
|
||||
*/
|
||||
Class<? extends Enum> value() default Enum.class;
|
||||
|
||||
/**
|
||||
* 枚举值
|
||||
*
|
||||
* @return 枚举值
|
||||
*/
|
||||
String[] enumValues() default {};
|
||||
|
||||
/**
|
||||
* 获取枚举值的方法名
|
||||
*
|
||||
* @return 获取枚举值的方法名
|
||||
*/
|
||||
String method() default "";
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*
|
||||
* @return 提示消息
|
||||
*/
|
||||
String message() default "参数值无效";
|
||||
|
||||
/**
|
||||
* 分组
|
||||
*
|
||||
* @return 分组
|
||||
*/
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
/**
|
||||
* 负载
|
||||
*
|
||||
* @return 负载
|
||||
*/
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.validation.constraints;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 枚举校验器
|
||||
*
|
||||
* @author Charles7c
|
||||
* @author Jasmine
|
||||
* @since 2.7.3
|
||||
*/
|
||||
public class EnumValueValidator implements ConstraintValidator<EnumValue, Object> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EnumValueValidator.class);
|
||||
private Class<? extends Enum> enumClass;
|
||||
private String[] enumValues;
|
||||
private String enumMethod;
|
||||
|
||||
@Override
|
||||
public void initialize(EnumValue enumValue) {
|
||||
this.enumClass = enumValue.value();
|
||||
this.enumValues = enumValue.enumValues();
|
||||
this.enumMethod = enumValue.method();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(Object value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
// 优先校验 enumValues
|
||||
if (enumValues.length > 0) {
|
||||
return Arrays.asList(enumValues).contains(Convert.toStr(value));
|
||||
}
|
||||
Enum[] enumConstants = enumClass.getEnumConstants();
|
||||
if (enumConstants.length == 0) {
|
||||
return false;
|
||||
}
|
||||
if (CharSequenceUtil.isBlank(enumMethod)) {
|
||||
return findEnumValue(enumConstants, Enum::toString, Convert.toStr(value));
|
||||
}
|
||||
try {
|
||||
// 枚举类指定了方法名,则调用指定方法获取枚举值
|
||||
Method method = enumClass.getMethod(enumMethod);
|
||||
for (Enum enumConstant : enumConstants) {
|
||||
if (Convert.toStr(method.invoke(enumConstant)).equals(Convert.toStr(value))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("An error occurred while validating the enum value, please check the @EnumValue parameter configuration.", e);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历枚举类,判断是否包含指定值
|
||||
*
|
||||
* @param enumConstants 枚举类数组
|
||||
* @param function 获取枚举值的函数
|
||||
* @param value 待校验的值
|
||||
* @return 是否包含指定值
|
||||
*/
|
||||
private boolean findEnumValue(Enum[] enumConstants, Function<Enum, Object> function, Object value) {
|
||||
for (Enum enumConstant : enumConstants) {
|
||||
if (function.apply(enumConstant).equals(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.validation.constraints;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
/**
|
||||
* JSON 格式字符串校验注解
|
||||
*
|
||||
* <p>
|
||||
* 校验字符串是否为 JSON 格式字符串
|
||||
* {@code @JsonString(message = "必须为有效的 JSON 格式")} <br />
|
||||
* </p>
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.12.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = JsonStringValidator.class)
|
||||
public @interface JsonString {
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*
|
||||
* @return 提示消息
|
||||
*/
|
||||
String message() default "必须为有效的 JSON 格式";
|
||||
|
||||
/**
|
||||
* 分组
|
||||
*
|
||||
* @return 分组
|
||||
*/
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
/**
|
||||
* 负载
|
||||
*
|
||||
* @return 负载
|
||||
*/
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.validation.constraints;
|
||||
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* JSON 格式字符串校验器
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.12.0
|
||||
*/
|
||||
public class JsonStringValidator implements ConstraintValidator<JsonString, String> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
return JSONUtil.isTypeJSON(value);
|
||||
}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.validation.constraints;
|
||||
|
||||
import jakarta.validation.Constraint;
|
||||
import jakarta.validation.Payload;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
/**
|
||||
* 手机号校验注解
|
||||
*
|
||||
* <p>
|
||||
* 校验中国大陆手机号码
|
||||
* {@code @Mobile(message = "手机号格式不正确")} <br />
|
||||
* </p>
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.10.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Constraint(validatedBy = MobileValidator.class)
|
||||
public @interface Mobile {
|
||||
|
||||
/**
|
||||
* 提示消息
|
||||
*
|
||||
* @return 提示消息
|
||||
*/
|
||||
String message() default "手机号格式不正确";
|
||||
|
||||
/**
|
||||
* 分组
|
||||
*
|
||||
* @return 分组
|
||||
*/
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
/**
|
||||
* 负载
|
||||
*
|
||||
* @return 负载
|
||||
*/
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.validation.constraints;
|
||||
|
||||
import cn.hutool.core.util.PhoneUtil;
|
||||
import jakarta.validation.ConstraintValidator;
|
||||
import jakarta.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* 手机号校验器
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 2.10.0
|
||||
*/
|
||||
public class MobileValidator implements ConstraintValidator<Mobile, String> {
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (value == null) {
|
||||
return true;
|
||||
}
|
||||
return PhoneUtil.isMobile(value);
|
||||
}
|
||||
}
|
@@ -0,0 +1 @@
|
||||
top.continew.starter.validation.autoconfigure.ValidatorAutoConfiguration
|
Reference in New Issue
Block a user