This commit is contained in:
ran.shang
2025-06-11 09:42:13 +08:00
commit 7e38b8d971
1935 changed files with 132836 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
package com.newyetai.common.validation;
/**
* 校验
*
* @author on 2019-11-05
*/
public interface Check {
}

View File

@@ -0,0 +1,10 @@
package com.newyetai.common.validation;
/**
* 新增校验
*
* @author on 2019-11-05
*/
public interface Create {
}

View File

@@ -0,0 +1,10 @@
package com.newyetai.common.validation;
/**
* 删除校验
*
* @author on 2019-11-05
*/
public interface Delete {
}

View File

@@ -0,0 +1,7 @@
package com.newyetai.common.validation;
/**
* @author on 2019-11-05
*/
public interface Send {
}

View File

@@ -0,0 +1,10 @@
package com.newyetai.common.validation;
/**
* 更新校验
*
* @author on 2019-11-05
*/
public interface Update {
}

View File

@@ -0,0 +1,52 @@
package com.newyetai.common.validation.annotation;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
@Target({TYPE, ANNOTATION_TYPE,FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {BigDecimalRangeValidator.class})
public @interface BigDecimalRange {
String message() default "";
/**
* 提示信息前缀
* @return 错误提示
*/
String messagePrefix() default "金额数值";
/**
* 最小值 (包含)
* @return 最小值
*/
String minValue() default "";
/**
* 最大值 (包含)
* @return 最大值
*/
String maxValue() default "";
/**
* 校验长度
*
* @return int 长度 -1:不校验
*/
int length() default -1;
/**
* 校验小数点位数
* @return int 小数点位数校验 -1:不校验
*/
int scala() default -1;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,124 @@
package com.newyetai.common.validation.annotation;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.springframework.validation.annotation.Validated;
import javax.validation.*;
import java.math.BigDecimal;
import java.util.Objects;
import java.util.Set;
/**
* 金额数字范围验证器
*
* @author Carlye
* @date 2021/03/16
*/
public class BigDecimalRangeValidator implements ConstraintValidator<BigDecimalRange, BigDecimal> {
private BigDecimal minValue;
private BigDecimal maxValue;
private int scala;
private int length;
private String messagePrefix;
@Override
public void initialize(BigDecimalRange constraintAnnotation) {
try {
minValue = new BigDecimal(constraintAnnotation.minValue());
} catch (Exception e) {
//doNothing
minValue = null;
}
try {
maxValue = new BigDecimal(constraintAnnotation.maxValue());
} catch (Exception e) {
//doNothing
maxValue = null;
}
scala = constraintAnnotation.scala();
length = constraintAnnotation.length();
messagePrefix = constraintAnnotation.messagePrefix();
}
@Override
public boolean isValid(BigDecimal checkValue,
ConstraintValidatorContext context) {
String messageSuffix = "超出范围";
boolean checkResult = true;
if (Objects.isNull(checkValue)) {
messageSuffix = "不能为空";
checkResult = false;
} else if (scala >= 0) { //需要对位数进行校验
//原值输出BigDecimal
String checkValueStr = checkValue.toPlainString();
if (StringUtils.substringAfter(checkValueStr, ".").length() != scala) {
messageSuffix = "需要保留" + scala + "位小数";
checkResult = false;
}
} else if (length >= 0) {
//原值输出BigDecimal
String checkValueStr = checkValue.toPlainString();
if (checkValueStr.length() > length) {
messageSuffix = "超过最大位数限制(" + length + ")";
checkResult = false;
}
} else if (Objects.nonNull(minValue) && minValue.compareTo(checkValue) > 0) {
messageSuffix = String.join("", "最小值为", minValue.stripTrailingZeros().toPlainString());
checkResult = false;
} else if (Objects.nonNull(maxValue) && maxValue.compareTo(checkValue) < 0) {
messageSuffix = String.join("", "最大值为", maxValue.stripTrailingZeros().toPlainString());
checkResult = false;
}
if (!checkResult) {
//改变默认提示信息
if (ConstraintValidatorContextImpl.class.isAssignableFrom(context.getClass())) {
//禁用默认提示信息
context.disableDefaultConstraintViolation();
//设置提示语(在message前面加上key)
context.buildConstraintViolationWithTemplate(String.join("", messagePrefix, messageSuffix)).addConstraintViolation();
}
}
return checkResult;
}
public static void main(String[] args) {
BigDecimal bigDecimal = BigDecimal.valueOf(0.90988);
System.out.println(bigDecimal.toPlainString());
System.out.println(StringUtils.substringAfter(bigDecimal.toPlainString(), "."));
}
@Data
private static class ValidTest {
@BigDecimalRange(messagePrefix = "火红的萨", maxValue = "0.999", minValue = "0.001")
private BigDecimal checkV;
@Validated
public static void test(@Valid ValidTest validTest) {
System.out.println(validTest);
}
public static void main(String[] args) {
BigDecimal bigDecimal = BigDecimal.valueOf(0.0001);
System.out.println(String.valueOf(bigDecimal));
Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
ValidTest validTest = new ValidTest();
validTest.setCheckV(BigDecimal.valueOf(-1));
Set<ConstraintViolation<ValidTest>> validate = validator.validate(validTest);
StringBuilder validateError = new StringBuilder();
for (ConstraintViolation<ValidTest> constraintViolation : validate) {
validateError.append(constraintViolation.getMessage()).append(";");
}
System.out.println(validateError);
}
}
}

View File

@@ -0,0 +1,50 @@
package com.newyetai.common.validation.annotation;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import com.newyetai.common.validation.constants.ValidProviderEnum;
/**
* 表达式校验器注解
* @author sr on 2021-05-25
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ExpressionValidator.class})
public @interface Expression {
String message() default "{javax.validation.constraints.Expression.message}";
/**
* springEl表达式,内置参数value(待校验值),返回值类型boolean
* @return
* @author sr on 2021-05-25
*/
String expressionStr() default "";
/**
* {@link ValidProviderEnum}
* @return
* @author sr on 2021-07-07
*/
ValidProviderEnum type() default ValidProviderEnum.NONE;
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,42 @@
package com.newyetai.common.validation.annotation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import com.newyetai.common.validation.constants.ValidProviderEnum;
public class ExpressionValidator implements ConstraintValidator<Expression, Object>{
//SPEL解析
private static ExpressionParser parser = new SpelExpressionParser();
private org.springframework.expression.Expression spelExpression ;
private ValidProviderEnum validProviderEnum;
@Override
public void initialize(Expression expression) {
String expressionStr = expression.expressionStr();
if (StringUtils.isNotBlank(expressionStr)) {
spelExpression = parser.parseExpression(expressionStr);
}
validProviderEnum = expression.type();
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (spelExpression != null) {
StandardEvaluationContext spelContext = new StandardEvaluationContext();
spelContext.setVariable("value", value);
return spelExpression.getValue(spelContext, Boolean.class);
}
return validProviderEnum.getFunction().apply(value);
}
}

View File

@@ -0,0 +1,52 @@
package com.newyetai.common.validation.annotation;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Pattern.Flag;
/**
* 身份证号
*
* @author on 2019-11-05
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {IdCardValidator.class})
@Inherited
public @interface IdCard {
/**
* @return the error message template
*/
String message() default "身份证号码格式错误";
/**
* @return the groups the constraint belongs to
*/
Class<?>[] groups() default {};
/**
* @return array of {@code Flag}s considered when resolving the regular expression
*/
Flag[] flags() default {};
/**
* @return the payload associated to the constraint
*/
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,29 @@
package com.newyetai.common.validation.annotation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.lang3.StringUtils;
import com.newyetai.common.validation.util.ValidateUtils;
/**
* 身份证号校验器
*
* @author on 2019-11-05
*/
public class IdCardValidator implements ConstraintValidator<IdCard, String> {
@Override
public void initialize(IdCard constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (StringUtils.isBlank(value)) {
return true;
}
return ValidateUtils.isIdCard(value);
}
}

View File

@@ -0,0 +1,59 @@
package com.newyetai.common.validation.annotation;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Pattern.Flag;
/**
* 电话号码
*
* @author on 2019-11-05
*/
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {PhoneValidator.class})
@Inherited
// @Pattern(regexp=ValidateUtil.mobileReg, message = MaterialConstant.PHONE_FORMAT_ERROR)
public @interface Phone {
/**
* @return the error message template
*/
// @AliasFor(annotation = Pattern.class, attribute = "message")
String message() default "电话号码格式错误";
/**
* @return the groups the constraint belongs to
*/
// @AliasFor(annotation = Pattern.class, attribute = "groups")
Class<?>[] groups() default {};
/**
* @return array of {@code Flag}s considered when resolving the regular expression
*/
// @AliasFor(annotation = Pattern.class, attribute = "flags")
Flag[] flags() default {};
/**
* @return the payload associated to the constraint
*/
// @AliasFor(annotation = Pattern.class, attribute = "payload")
Class<? extends Payload>[] payload() default {};
}

View File

@@ -0,0 +1,28 @@
package com.newyetai.common.validation.annotation;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.apache.commons.lang3.StringUtils;
import com.newyetai.common.validation.util.ValidateUtils;
/**
* 电话号码校验器
*
* @author on 2019-11-05
*/
public class PhoneValidator implements ConstraintValidator<Phone, String> {
@Override
public void initialize(Phone constraintAnnotation) {}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (StringUtils.isBlank(value)) {
return true;
}
return ValidateUtils.isPhone(value) || ValidateUtils.isFixedTelephone(value);
}
}

View File

@@ -0,0 +1,23 @@
package com.newyetai.common.validation.annotation;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
* @author on 2019-11-05
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
@Inherited
public @interface TableColumn {
String name();
int sort();
}

View File

@@ -0,0 +1,46 @@
package com.newyetai.common.validation.constants;
import java.util.Map;
import java.util.function.Function;
import com.google.common.collect.Maps;
import com.newyetai.common.validation.util.ValidateUtils;
public enum ValidProviderEnum {
NONE("none", (v) -> false),
CARD_NO("cardNo", (v) -> ValidateUtils.isIdCard((String) v)),
PHONE("phone", (v) -> ValidateUtils.isPhone((String) v)),
USERNAME("username", (v) -> ValidateUtils.matchUsername((String) v)),
PASSWORD("password", (v) -> ValidateUtils.matchPassword((String) v)),
REAL_NAME("realName", (v) -> ValidateUtils.checkRealName((String) v)),
;
private static Map<String, ValidProviderEnum> validMap ;
private String type;
private Function<Object, Boolean> function;
ValidProviderEnum(String type, Function<Object, Boolean> function) {
this.type = type;
this.function = function;
}
static {
ValidProviderEnum[] enums = ValidProviderEnum.values();
validMap = Maps.newHashMapWithExpectedSize(enums.length);
for (ValidProviderEnum providerEnum : enums) {
validMap.put(providerEnum.getType(), providerEnum);
}
}
public String getType() {
return this.type;
}
public Function<Object, Boolean> getFunction() {
return this.function;
}
}

View File

@@ -0,0 +1,249 @@
package com.newyetai.common.validation.util;
import com.newyetai.common.constant.CommonConstants;
import com.newyetai.common.exception.util.Assert;
import org.apache.commons.lang3.StringUtils;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.Set;
import java.util.regex.Pattern;
/**
* @author on 2019-11-05
*/
public class ValidateUtils {
/**
* 用户安全码校验正则
*/
public static final String SECURITY_CODE_PATTERN = "^[A-Za-z\\d!@#$%^&*]{6,32}$";
public static Pattern numberPattern = Pattern.compile("^[-\\+]?[\\d]*$");
public static Pattern mobilePattern = Pattern.compile("^[1][0-9]{10}$");
public static Pattern fixedTelephone = Pattern.compile("^[0]\\d{2,3}\\d{7,8}");
public static final Pattern USERNAME_PATTERN = Pattern.compile("^[a-zA-Z0-9]{4,32}$");
public static final Pattern PASSWORD_PATTERN = Pattern.compile("[A-Za-z\\d!@#$%^&*]{6,32}$");
/**
* 正则 邮箱
*/
private static Pattern EMAIL_REG = Pattern.compile("^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$");
/**
* 昵称校验
*/
private static Pattern NICK_NAME_REG = Pattern.compile("^[\\u4e00-\\u9fffa-zA-Z0-9]{2,32}$");
/** 姓名 **/
private static final Pattern REAL_NAME_REG = Pattern.compile(
"^(([a-zA-Z+\\.?\\·?a-zA-Z+]{2,30}$)|([\\u4e00-\\u9fff+\\·?\\u4e00-\\u9fff+]{2,30}$))");
public static Validator validator = Validation.buildDefaultValidatorFactory()
.getValidator();
/**
* 身份证号权重因子、对应验证码
*/
// 前十七位加权因子
public static final int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
// 这是除以11后,可能产生的11位余数对应的验证码
public static final String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
// 定义判别用户身份证号的正则表达式(15位或者18位,最后一位可以为字母)
// 假设18位身份证号码:41000119910101123X 410001 19910101 123X
// ^开头
// [1-9] 第一位1-9中的一个 4
// \\d{5} 五位数字 10001(前六位省市县地区)
// (18|19|20) 19(现阶段可能取值范围18xx-20xx年)
// \\d{2} 91(年份)
// ((0[1-9])|(10|11|12)) 01(月份)
// (([0-2][1-9])|10|20|30|31)01(日期)
// \\d{3} 三位数字 123(第十七位奇数代表男,偶数代表女)
// [0-9Xx] 0123456789Xx其中的一个 X(第十八位为校验值)
// $结尾
// 假设15位身份证号码:410001910101123 410001 910101 123
// ^开头
// [1-9] 第一位1-9中的一个 4
// \\d{5} 五位数字 10001(前六位省市县地区)
// \\d{2} 91(年份)
// ((0[1-9])|(10|11|12)) 01(月份)
// (([0-2][1-9])|10|20|30|31)01(日期)
// \\d{3} 三位数字 123(第十五位奇数代表男,偶数代表女),15位身份证不含X
// $结尾
private static Pattern idCardPattern = Pattern.compile(
"(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|"
+ "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)");
/**
* 手机号码校验
*
* @param mobile
* @return
*/
public static boolean isPhone(String mobile) {
if (StringUtils.isBlank(mobile)) {
return false;
}
return mobilePattern.matcher(mobile).matches();
}
/**
* 固定电话校验
*
* @param phone
* @return
*/
public static boolean isFixedTelephone(String phone) {
if (StringUtils.isBlank(phone)) {
return false;
}
phone = phone.replace("-", "");
return fixedTelephone.matcher(phone).matches();
}
/**
* 身份证校验
*
* @param idCard
* @return
*/
public static boolean isIdCard(String idCard) {
if (StringUtils.isBlank(idCard)) {
return false;
}
boolean matches = idCardPattern.matcher(idCard).matches();
// 判断第18位校验值
if (matches) {
if (idCard.length() == 18) {
try {
char[] charArray = idCard.toCharArray();
int sum = 0;
for (int i = 0; i < idCardWi.length; i++) {
int current = Integer.parseInt(String.valueOf(charArray[i]));
int count = current * idCardWi[i];
sum += count;
}
char idCardLast = charArray[17];
int idCardMod = sum % 11;
if (idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase())) {
return true;
} else {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
return matches;
}
/**
* 校验对象,校验未通过返回异常信息
* @param object
* @param groups
* @return null 校验通过;否则 返回异常信息
* @author sr on 2021-05-25
*/
public static String validate(Object object, Class<?>... groups) {
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (constraintViolations.isEmpty()) {
return null;
}
StringBuilder errMsg = new StringBuilder();
constraintViolations.forEach(constraintViolation -> errMsg
.append(constraintViolation.getMessage()).append(CommonConstants.COMMA));
return errMsg.toString();
}
/**
* 校验对象,校验未通过抛BusinessException
* @param object
* @param groups
* @author sr on 2021-05-25
*/
public static void validateBiz(Object object, Class<?>... groups) {
String errMsg = validate(object, groups);
Assert.isNull(errMsg, errMsg);
}
/**
* 校验对象,校验未通过抛BusinessException
* @param object
* @param errMsg 自定义异常信息
* @param groups
* @author sr on 2021-06-10
*/
public static void validateBiz(Object object, String errMsg, Class<?>... groups) {
String originErrMsg = validate(object, groups);
Assert.isNull(originErrMsg, errMsg);
}
/**
* 账号是否合规
* @param userName
* @return
* @author sr on 2021-07-07
*/
public static boolean matchUsername(String userName) {
if (StringUtils.isBlank(userName)) {
return false;
}
return USERNAME_PATTERN.matcher(userName).matches();
}
/**
* 密码是否合规
* @param password
* @return
* @author sr on 2021-07-07
*/
public static boolean matchPassword(String password) {
if (StringUtils.isBlank(password)) {
return false;
}
return PASSWORD_PATTERN.matcher(password).matches();
}
/**
* 邮箱是否合规
* @param email
* @return
* @author sr on 2021-07-07
*/
public static boolean checkEmail(String email) {
if (StringUtils.isBlank(email)) {
return false;
}
return EMAIL_REG.matcher(email).matches();
}
public static boolean checkNickName(String nickname) {
if (StringUtils.isBlank(nickname)) {
return false;
}
return NICK_NAME_REG.matcher(nickname).matches();
}
/**
* 检查中文姓名
*
* @param realname 中文名
* @return boolean
*/
public static boolean checkRealName(String realname) {
if (StringUtils.isBlank(realname)) {
return false;
}
return REAL_NAME_REG.matcher(realname).matches();
}
}