JAVA自定义注解校验输入字段是否符合规则

  • 1、类中某个属性,前端只能传入某几个固定的值,使用方法: 在类中属性上使用该注解
  • 2、类中某个属性,输入的值只能是数字
  • 3、某个属性只能是时间类型的值



校验输入信息是否正确有很多方式,这里我们将一种自定义注解实现校验。通过注解的方式,可以避免在项目中输入大量的校验语句,保证代码整洁。可以通过实现 ConstraintValidator<自定义注解,校验的类型> 接口的方式实现

话不多说,上代码



1、类中某个属性,前端只能传入某几个固定的值,使用方法: 在类中属性上使用该注解

案例:

@InputValueMatch(values = {"BUSINESS", "FUNCTION"})
    private String roleType;

这种写法表示,roleType的值只能是BUSINESSFUNCTION

实现:

package com.upbim.twin.park.common.validation.validator;

import com.google.common.collect.Lists;
import com.upbim.twin.park.common.validation.constraint.InputValueMatch;
import com.upbim.twin.park.common.validation.constraint.TwinForestryType;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorContextImpl;
import org.hibernate.validator.internal.engine.constraintvalidation.ConstraintViolationCreationContext;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

public class InputValueMatchValidator implements ConstraintValidator<InputValueMatch, String> {

    private Class<? extends TwinForestryType>[] types;

    private List<String> values;

    private boolean required;

    private boolean emptyToNull;

    @Override
    public void initialize(InputValueMatch constraintAnnotation) {

        types = constraintAnnotation.types();
        values = Arrays.asList(constraintAnnotation.values());
        required = constraintAnnotation.required();
        emptyToNull = constraintAnnotation.emptyToNull();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {

        final List<String> valuesInTypes = Arrays.stream(types).map(clazz ->

                clazz.isEnum() ? clazz.getEnumConstants()[0].getAllNames() : null
        ).filter(Objects::nonNull).flatMap(Collection::stream).collect(Collectors.toList());

        List<String> allValidValues = Lists.newArrayList();

        allValidValues.addAll(valuesInTypes);
        allValidValues.addAll(values);

        // 空字符串转null(因为'空字符串'与'null'具有不同的语意,所以需要指定emptyToNull=true,才会做此转换)
        if (emptyToNull) {
            value = StringUtils.isEmpty(value) ? null : value;
        }

        // 参数非必传条件下:入参为null,通过!
        if (value == null && !required) {

            return true;
        } else {

            // 参数必传条件下:参数为null 或者 参数不匹配指定的字符串组,不通过!
            if (value == null || allValidValues.stream().noneMatch(value::equals)) {

                String field = getField((ConstraintValidatorContextImpl) context);

                context.disableDefaultConstraintViolation();
                context.buildConstraintViolationWithTemplate(String.format("[%s]字段:传入参数 [%s] 无效,参数只能是: %s", field, value, allValidValues))
                        .addConstraintViolation();

                return false;
            }
        }
        return true;
    }

    private String getField(ConstraintValidatorContextImpl context) {
        List<ConstraintViolationCreationContext> creationContexts = context.getConstraintViolationCreationContexts();
        return creationContexts.get(0).getPath().getLeafNode().asString();
    }

}

自定义注解:

package com.upbim.twin.park.common.validation.constraint;


import com.upbim.twin.park.common.validation.validator.InputValueMatchValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = InputValueMatchValidator.class)
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface InputValueMatch {

    /**
     * 制定上传的参数必须匹配数组列表中的值
     *
     * @return values 匹配列表
     */
    String[] values() default {};

    /**
     * 参数是否必传
     * true:必传
     * false:非必传(可以为null,但如果不为null,则必须匹配特定内容)
     *
     * @return required
     */
    boolean required() default true;

    /**
     * 校验不同过时的提示
     *
     * @return message
     */
    String message() default "Invalid input value!";

    /**
     * 将空字符串置为null(默认false)
     *
     * @return emptyToNull
     */
    boolean emptyToNull() default false;

    /**
     * 上传的字符串必须匹配枚举中的值 name()
     *
     * @return twin-forestryType
     */
    Class<? extends TwinForestryType>[] types() default {};

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    @Target({ElementType.TYPE, ElementType.FIELD, ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @interface List {
        InputValueMatch[] value();
    }
}



2、类中某个属性,输入的值只能是数字



案例:

@NumberValid(message = "type只能是数字类型", type = Integer.class)
    private Object type;

实现:

package com.upbim.twin.park.common.validation.constraint;


import com.upbim.twin.park.common.validation.validator.NumberValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = NumberValidator.class)
public @interface NumberValid {

    /**
     * 默认错误提示
     */
    String message() default "param is invalid";

    /**
     * 输入的内容必须可以转化成 指定类型
     */
    Class<?> type();

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    String[] extendNames() default {};
}
package com.upbim.twin.park.common.validation.validator;


import com.upbim.twin.park.common.validation.constraint.NumberValid;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.math.BigDecimal;
public class NumberValidator implements ConstraintValidator<NumberValid, Object> {

    private Class type = null;

    @Override
    public void initialize(NumberValid constraintAnnotation) {
        type = constraintAnnotation.type();
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {

        try {

            if (BigDecimal.class == type) {

                new BigDecimal(String.valueOf(value));
            } else if (Long.class == type) {

                Long.valueOf(String.valueOf(value));
            } else if (Double.class == type) {

                Double.valueOf(String.valueOf(value));
            } else if (Integer.class == type) {

                Integer.valueOf(String.valueOf(value));
            }
        } catch (Exception ex) {
            return false;
        }

        return true;
    }
}

3、某个属性只能是时间类型的值

实现:

package com.upbim.twin.park.common.validation.constraint;

import com.upbim.twin.park.common.validation.validator.DateTimeValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = DateTimeValidator.class)
@Documented
public @interface DateTimeValid {
    String message() default "格式错误";

    String format() default "yyyy-MM-dd HH:mm";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
package com.upbim.twin.park.common.validation.validator;

import com.upbim.twin.park.common.validation.constraint.DateTimeValid;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.text.SimpleDateFormat;

@Slf4j
public class DateTimeValidator implements ConstraintValidator<DateTimeValid, String> {
    private DateTimeValid dateTime;

    @Override
    public void initialize(DateTimeValid dateTime) {
        this.dateTime = dateTime;
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        /** 如果 value 为空则不进行格式验证,为空验证可以使用 @NotBlank @NotNull @NotEmpty 等注解来进行控制,职责分离*/
        if (StringUtils.isEmpty(value)) {
            return true;
        }
        String format = dateTime.format();

        if (value.length() != format.length()) {
            return false;
        }

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format);

        try {
            simpleDateFormat.parse(value);
        } catch (Exception e) {
            return false;
        }
        return true;
    }
}

感谢浏览,如果帮到你了,可以收藏使用。