All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.zcj.util.validator.ValidatorBuilder Maven / Gradle / Ivy

package com.zcj.util.validator;

import com.zcj.util.UtilClass;
import com.zcj.util.UtilDate;
import com.zcj.util.UtilRegex;
import com.zcj.util.UtilString;
import com.zcj.util.validator.annotation.Validator;
import com.zcj.util.validator.constant.StrFormat;
import com.zcj.util.validator.dto.ValidatorResult;
import com.zcj.web.spring.SpringBeanUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

/**
 * 实体中属性的格式验证工具
 *
 * @author [email protected]
 * @since 2019/10/14
 */
public class ValidatorBuilder {

    private static final Logger logger = LoggerFactory.getLogger(ValidatorBuilder.class);

    private static final String CN_NAME_ANNOTATION_CLASS = "com.zcj.util.coder.annotation.CnName";
    private static final String API_MODEL_PROPERTY = "io.swagger.annotations.ApiModelProperty";

    private final T object;
    private final boolean includeAllField;
    private final boolean includeEmptyTagField;
    private final Set includeTagsField;
    private final boolean oneErrorBreak;

    private ValidatorBuilder(Builder builder) {
        object = builder.object;
        includeAllField = builder.includeAllField;
        includeEmptyTagField = builder.includeEmptyTagField;
        includeTagsField = builder.includeTagsField;
        oneErrorBreak = builder.oneErrorBreak;
    }

    public ValidatorResult valid() {
        ValidatorResult result = new ValidatorResult();
        List fields = UtilClass.getAllFields(object.getClass());
        for (Field field : fields) {
            Validator[] validators = field.getAnnotationsByType(Validator.class);
            if (validators != null && validators.length > 0) {
                validOneField(field, validators, result);
                if (oneErrorBreak && result.isFails()) {
                    break;
                }
            }
        }
        return result;
    }

    public static class Builder {
        private T object = null;
        private boolean includeAllField = false;
        private boolean includeEmptyTagField = false;
        private Set includeTagsField = new HashSet<>();
        private boolean oneErrorBreak = false;

        public Builder(T object) {
            this.object = object;
        }

        /**
         * 如果有一个属性验证不通过,马上返回
         *
         * @return com.zcj.util.validator.ValidatorUtil.Builder
         */
        public Builder oneErrorBreak() {
            this.oneErrorBreak = true;
            return this;
        }

        /**
         * 验证所有加了注解的字段
         *
         * @return com.zcj.util.validator.ValidatorUtil.Builder
         */
        public Builder includeAllField() {
            this.includeAllField = true;
            return this;
        }

        /**
         * 验证未设置 tags 的字段
         *
         * @return com.zcj.util.validator.ValidatorUtil.Builder
         */
        public Builder includeEmptyTagField() {
            this.includeEmptyTagField = true;
            return this;
        }

        // 验证指定 tags 的字段
        public Builder includeTagsField(String... tags) {
            if (tags != null && tags.length > 0) {
                for (String tag : tags) {
                    if (UtilString.isNotBlank(tag)) {
                        this.includeTagsField.add(tag);
                    }
                }
            }
            return this;
        }

        public ValidatorBuilder build() {
            return new ValidatorBuilder(this);
        }
    }

    private void validOneField(Field field, Validator[] validators, ValidatorResult result) {
        for (Validator validator : validators) {
            if (needValid(validator.tags())) {
                String fieldName = field.getName();
                String fieldCnName = getFieldShowName(field, validator.chineseName());
                Object fieldValue = null;
                try {
                    field.setAccessible(true);
                    fieldValue = field.get(object);
                } catch (IllegalAccessException e) {
                    logger.warn("验证[{}]属性时出错:获取属性值错误(已跳过验证)", field.getName());
                    continue;
                }
                if (!result.containsError(fieldName) && validator.required()) {
                    validRequired(fieldName, fieldValue, fieldCnName, result);
                }
                if (!result.containsError(fieldName) && validator.onlyAllowed() != null && validator.onlyAllowed().length > 0) {
                    validOnlyAllowed(fieldName, fieldValue, fieldCnName, Arrays.asList(validator.onlyAllowed()), result);
                }
                if (!result.containsError(fieldName) && validator.onlyAllowedEnumName() != null && validator.onlyAllowedEnumName().length > 0) {
                    Set enumNameSet = new HashSet<>();
                    for (Class> aClass : validator.onlyAllowedEnumName()) {
                        enumNameSet.addAll(getEnumNames(aClass));
                    }
                    validOnlyAllowed(fieldName, fieldValue, fieldCnName, enumNameSet, result);
                }
                if (!result.containsError(fieldName) && UtilString.isNotBlank(validator.onlyAllowedByKey())) {
                    ValidatorInterface validatorInterface = null;
                    try {
                        validatorInterface = SpringBeanUtil.getBean(ValidatorInterface.class);
                    } catch (Exception e) {
                    }
                    if (validatorInterface == null) {
                        logger.warn("ValidatorInterface 获取失败,onlyAllowedByKey 配置无效");
                    } else {
                        Collection allows = validatorInterface.onlyAllowedByKey(validator.onlyAllowedByKey());
                        validOnlyAllowed(fieldName, fieldValue, fieldCnName, allows, result);
                    }
                }
                if (!result.containsError(fieldName) && UtilString.isNotBlank(validator.minValue())) {
                    validMinValue(fieldName, fieldValue, fieldCnName, validator.minValue(), result);
                }
                if (!result.containsError(fieldName) && UtilString.isNotBlank(validator.maxValue())) {
                    validMaxValue(fieldName, fieldValue, fieldCnName, validator.maxValue(), result);
                }
                if (!result.containsError(fieldName) && validator.minLength() > 0) {
                    validMinLength(fieldName, fieldValue, fieldCnName, validator.minLength(), result);
                }
                if (!result.containsError(fieldName) && validator.maxLength() < Integer.MAX_VALUE) {
                    validMaxLength(fieldName, fieldValue, fieldCnName, validator.maxLength(), result);
                }
                if (!result.containsError(fieldName) && UtilString.isNotBlank(validator.strFormat())) {
                    validStrFormat(fieldName, fieldValue, fieldCnName, validator.strFormat(), result);
                }
            }
        }
    }

    private boolean needValid(String[] tags) {
        if (includeAllField) {
            return true;
        }
        if (tags == null || tags.length == 0) {
            return includeEmptyTagField;
        }
        for (String tag : tags) {
            if (includeTagsField.contains(tag)) {
                return true;
            }
        }
        return false;
    }

    private Set getEnumNames(Class> enumObject) {
        Set result = new HashSet<>();
        for (Enum anEnum : enumObject.getEnumConstants()) {
            result.add(anEnum.name());
        }
        return result;
    }

    private String getFieldShowName(Field field, String validatorCnName) {
        if (UtilString.isNotBlank(validatorCnName)) {
            return validatorCnName;
        }
        if (field == null) {
            return "";
        }
        String cnName = UtilClass.getAnnotationValue(field, CN_NAME_ANNOTATION_CLASS, "value", String.class);
        if (UtilString.isNotBlank(cnName)) {
            return cnName;
        }
        String apiModelValue = UtilClass.getAnnotationValue(field, API_MODEL_PROPERTY, "value", String.class);
        if (UtilString.isNotBlank(apiModelValue)) {
            return apiModelValue;
        }
        return field.getName();
    }

    private void validRequired(final String fieldName, Object fieldValue, final String fieldCnName, ValidatorResult result) {
        boolean isnull;
        if (fieldValue instanceof String) {
            isnull = UtilString.isBlank((String) fieldValue);
        } else {
            isnull = (fieldValue == null);
        }
        if (isnull) {
            result.setFails(true);
            result.getFailsInfo().put(fieldName, "[" + fieldCnName + "]不能为空");
        }
    }

    private void validMaxLength(final String fieldName, Object fieldValue, final String fieldCnName, int maxLength, ValidatorResult result) {
        if (fieldValue == null) {
            return;
        }
        boolean stringTooLength = ((fieldValue instanceof String) && ((String) fieldValue).length() > maxLength);
        boolean sizeTooMax = (fieldValue instanceof Map && ((Map) fieldValue).size() > maxLength)
                || (fieldValue instanceof Collection && ((Collection) fieldValue).size() > maxLength);
        if (stringTooLength || sizeTooMax) {
            result.setFails(true);
            String unit = stringTooLength ? "长度" : "数量";
            result.getFailsInfo().put(fieldName, "[" + fieldCnName + "]的" + unit + "不能大于[" + maxLength + "]");
        }
    }

    private void validMinLength(final String fieldName, Object fieldValue, final String fieldCnName, int minLength, ValidatorResult result) {
        if (fieldValue == null) {
            return;
        }
        boolean stringTooLength = ((fieldValue instanceof String) && ((String) fieldValue).length() < minLength);
        boolean sizeTooMin = (fieldValue instanceof Map && ((Map) fieldValue).size() < minLength)
                || (fieldValue instanceof Collection && ((Collection) fieldValue).size() < minLength);
        if (stringTooLength || sizeTooMin) {
            result.setFails(true);
            String unit = stringTooLength ? "长度" : "数量";
            result.getFailsInfo().put(fieldName, "[" + fieldCnName + "]的" + unit + "不能小于[" + minLength + "]");
        }
    }

    private void validMaxValue(final String fieldName, Object fieldValue, final String fieldCnName, String maxValue, ValidatorResult result) {
        boolean pass = true;
        if (fieldValue == null) {
            pass = true;
        } else if (fieldValue instanceof Date) {
            Date maxValueObj = this.formatDate(maxValue);
            if (maxValueObj == null) {
                logger.warn("验证[{}]属性时出错:maxValue 设置的值[{}]无法转换成 Date 格式(已跳过验证)", fieldName, maxValue);
                pass = true;
            } else {
                pass = maxValueObj.compareTo((Date) fieldValue) >= 0;
            }
        } else if (fieldValue instanceof BigDecimal) {
            if (!UtilString.isBigDecimal(maxValue)) {
                logger.warn("验证[{}]属性时出错:maxValue 设置的值无法转换成 BigDecimal 格式(已跳过验证)", fieldName);
                pass = true;
            } else {
                BigDecimal maxValueObj = new BigDecimal(maxValue.replaceAll(",", ""));
                pass = maxValueObj.compareTo((BigDecimal) fieldValue) >= 0;
            }
        } else if (fieldValue instanceof Double || fieldValue instanceof Float || fieldValue instanceof Integer || fieldValue instanceof Long) {
            if (!maxValue.matches(UtilRegex.REGEX_NUMERIC)) {
                logger.warn("验证[{}]属性时出错:maxValue 设置的值无法转换成数值格式(已跳过验证)", fieldName);
                pass = true;
            } else {
                Double fieldValueObj = Double.valueOf(String.valueOf(fieldValue));
                Double maxValueObj = Double.valueOf(maxValue);
                pass = maxValueObj.compareTo(fieldValueObj) >= 0;
            }
        }
        if (!pass) {
            result.setFails(true);
            result.getFailsInfo().put(fieldName, "[" + fieldCnName + "]的值不能大于[" + showValue(maxValue) + "]");
        }
    }

    private void validMinValue(final String fieldName, Object fieldValue, final String fieldCnName, String minValue, ValidatorResult result) {
        boolean pass = true;
        if (fieldValue == null) {
            pass = true;
        } else if (fieldValue instanceof Date) {
            Date minValueObj = this.formatDate(minValue);
            if (minValueObj == null) {
                logger.warn("验证[{}]属性时出错:minValue 设置的值[{}]无法转换成 Date 格式(已跳过验证)", fieldName, minValue);
                pass = true;
            } else {
                pass = minValueObj.compareTo((Date) fieldValue) <= 0;
            }
        } else if (fieldValue instanceof BigDecimal) {
            if (!UtilString.isBigDecimal(minValue)) {
                logger.warn("验证[{}]属性时出错:minValue 设置的值无法转换成 BigDecimal 格式(已跳过验证)", fieldName);
                pass = true;
            } else {
                BigDecimal minValueObj = new BigDecimal(minValue.replaceAll(",", ""));
                pass = minValueObj.compareTo((BigDecimal) fieldValue) <= 0;
            }
        } else if (fieldValue instanceof Double || fieldValue instanceof Float || fieldValue instanceof Integer || fieldValue instanceof Long) {
            if (!minValue.matches(UtilRegex.REGEX_NUMERIC)) {
                logger.warn("验证[{}]属性时出错:minValue 设置的值无法转换成数值格式(已跳过验证)", fieldName);
                pass = true;
            } else {
                Double fieldValueObj = Double.valueOf(String.valueOf(fieldValue));
                Double minValueObj = Double.valueOf(minValue);
                pass = minValueObj.compareTo(fieldValueObj) <= 0;
            }
        }
        if (!pass) {
            result.setFails(true);
            result.getFailsInfo().put(fieldName, "[" + fieldCnName + "]的值不能小于[" + showValue(minValue) + "]");
        }
    }

    // 注解中配置的值 => 错误时提示的值
    // 例:now-7 => 7天前
    private String showValue(String configString) {
        if (UtilString.isBlank(configString)) {
            return configString;
        }
        if ("now".equals(configString)) {
            return "当前时间";
        }
        if (configString.startsWith("now+")) {
            String addDay = configString.substring(4);
            if (addDay.matches(UtilRegex.REGEX_NUMBER)) {
                return Integer.valueOf(addDay) + "天后";
            }
        }
        if (configString.startsWith("now-")) {
            String addDay = configString.substring(4);
            if (addDay.matches(UtilRegex.REGEX_NUMBER)) {
                return Integer.valueOf(addDay) + "天前";
            }
        }
        return configString;
    }

    // 格式化 Date 类型的校验值,支持:now、now-5、now+7 等字符串
    private Date formatDate(String dateString) {
        if ("now".equals(dateString)) {
            return new Date();
        }
        if (dateString.startsWith("now+")) {
            String addDay = dateString.substring(4);
            if (addDay.matches(UtilRegex.REGEX_NUMBER)) {
                return UtilDate.getLaterDay(new Date(), Integer.valueOf(addDay));
            }
        }
        if (dateString.startsWith("now-")) {
            String addDay = dateString.substring(4);
            if (addDay.matches(UtilRegex.REGEX_NUMBER)) {
                return UtilDate.getLaterDay(new Date(), Integer.valueOf(addDay) * (-1));
            }
        }
        return UtilDate.format(dateString);
    }

    private void validOnlyAllowed(final String fieldName, Object fieldValue, final String fieldCnName, Collection allowedValues, ValidatorResult result) {
        if (fieldValue == null) {
            return;
        }
        String fieldStrValue = String.valueOf(fieldValue);
        if ("".equals(fieldStrValue)) {
            return;
        }

        if (allowedValues == null || allowedValues.size() == 0) {
            result.setFails(true);
            result.getFailsInfo().put(fieldName, "[" + fieldCnName + "]无有效取值");
            return;
        }
        boolean pass = allowedValues.contains(fieldStrValue);
        if (!pass) {
            result.setFails(true);
            result.getFailsInfo().put(fieldName, "[" + fieldCnName + "]只能取值" + allowedValues);
        }
    }

    private void validStrFormat(final String fieldName, Object fieldValue, final String fieldCnName, String strFormat, ValidatorResult result) {
        boolean pass = true;
        String unPassReason = "";
        if (fieldValue != null && (fieldValue instanceof String)) {
            String fieldValueStr = (String) fieldValue;
            if (UtilString.isNotBlank(fieldValueStr)) {
                if (StrFormat.DATE_STR.equals(strFormat)) {
                    if (UtilDate.format(fieldValueStr) == null) {
                        pass = false;
                        unPassReason = "[" + fieldCnName + "]的值格式错误,只能是日期格式";
                    }
                } else if (StrFormat.BIG_DECIMAL_STR.equals(strFormat)) {
                    if (!UtilString.isBigDecimal(fieldValueStr)) {
                        pass = false;
                        unPassReason = "[" + fieldCnName + "]的值格式错误,只能是数值格式";
                    }
                } else {
                    logger.warn("验证[{}]属性时出错:strFormat 设置的值[{}]不支持(已跳过验证)", fieldName, strFormat);
                }
            }
        }
        if (!pass) {
            result.setFails(true);
            result.getFailsInfo().put(fieldName, unPassReason);
        }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy