Spring Boot项目javax validation 自定义参数验证规则枚举限制

在我们的项目中,大量使用了枚举类型。在某些业务情况下,我们需要限制枚举类型仅接受特定的枚举值。例如,思考一个订单状态的枚举变量,其中包含【用户撤销】和【管理员撤销】等值。不过,在前端修改订单状态的接口中,我们只允许将订单状态设置为【用户撤销】。为了实现这种限制,我们可以使用自定义参数验证规则。

通过自定义参数验证规则,我们可以确保只有指定的枚举值可以作为参数值被接受。这样,无论是在前端请求还是后端处理过程中,我们都可以验证参数的有效性。这种方式既可以提高数据的一致性,又能为开发人员提供有意义的错误消息和准确的验证结果。

通过自定义参数验证规则,我们能够更好地控制枚举类型参数的取值范围,满足特定业务需求,并保持代码的可读性和可维护性。这样的优化措施能够提高项目的质量、开发效率和用户体验。

定义允许枚举值约束

# platform-module/platform-module-validate/src/main/java/com/tinem/platform/module/validate/EnumAllowedValuesConstraint.java
package com.tinem.platform.module.validate;

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, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumAllowedValuesValidator.class)
public @interface EnumAllowedValuesConstraint {

    String message() default "Invalid value";

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

}

定义允许枚举值约束验证规则

# platform-module/platform-module-validate/src/main/java/com/tinem/platform/module/validate/EnumAllowedValuesValidator.java
package com.tinem.platform.module.validate;

import cn.hutool.core.util.ReflectUtil;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;

/**
 * 允许枚举值约束验证
 */
public class EnumAllowedValuesValidator implements ConstraintValidator<EnumAllowedValuesConstraint, Object> {

    private List<String> allowedValues;

    @Override
    public void initialize(EnumAllowedValuesConstraint constraintAnnotation) {
        allowedValues = Arrays.asList(constraintAnnotation.allowedValues());
    }

    @Override
    public boolean isValid(Object value, ConstraintValidatorContext context) {
        if (value == null) {
            return true; // 允许为空值
        }
        if (value instanceof String) {
            return allowedValues.stream()
                    .anyMatch(v->v.equals(value));
        }
        if (value instanceof Integer) {
            return allowedValues.stream()
                    .map(Integer::parseInt)
                    .anyMatch(v->v.equals(value));
        }
        if (value instanceof Short) {
            return allowedValues.stream()
                    .map(Short::parseShort)
                    .anyMatch(v->v.equals(value));
        }
        if (value instanceof Byte) {
            return allowedValues.stream()
                    .map(Byte::parseByte)
                    .anyMatch(v->v.equals(value));
        }
        if (value instanceof Boolean) {
            return allowedValues.stream()
                    .map(Boolean::parseBoolean)
                    .anyMatch(v->v.equals(value));
        }
        if (value instanceof Float) {
            return allowedValues.stream()
                    .map(Float::parseFloat)
                    .anyMatch(v->v.compareTo((Float) value) == 0);
        }
        if (value instanceof Double) {
            return allowedValues.stream()
                    .map(Double::parseDouble)
                    .anyMatch(v->v.compareTo((Double) value) == 0);
        }
        if (value instanceof BigDecimal) {
            return allowedValues.stream()
                    .map(BigDecimal::new)
                    .anyMatch(v->v.compareTo((BigDecimal)value)==0);
        }

        if (value.getClass().isEnum()) {
            Method valueOf = ReflectUtil.getMethod(value.getClass(),"name");
            String name = ReflectUtil.invoke(value,valueOf);
            return allowedValues.stream()
                    .anyMatch(v->v.equals(name));
        }
        return false; // 值无效
    }
}

编写测试类

# platform-module/platform-module-validate/src/test/java/com/tinem/platform/module/validate/EnumAllowedValuesValidatorTest.java
package com.tinem.platform.module.validate;

import lombok.Data;
import org.junit.Test;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.math.BigDecimal;
import java.util.Set;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

/**
 * 测试自定义枚举类型验证
 */
public class EnumAllowedValuesValidatorTest {

    private Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    /**
     * 测试传入正确的枚举值
     */
    @Test
    public void allowed(){
        Params params = new Params();
        params.value = EnumTest.allowed;
        params.i = 1;
        params.f = 2;
        params.d = 3;
        params.s = "4";
        params.b = new BigDecimal("5");
        params.b2 = 6;
        params.s2 = 7;
        Set<ConstraintViolation<Params>> violations = validator.validate(params,Default.class);
        assertTrue(violations.isEmpty());
    }
    /**
     * 测试传入错误的枚举值
     */
    @Test
    public void notAllow(){
        Params params = new Params();
        params.value = EnumTest.not_allow;
        params.i = -1;
        params.f = -2;
        params.d = -3;
        params.s = "-4";
        params.b = new BigDecimal("-5");
        params.b2 = -6;
        params.s2 = -7;
        Set<ConstraintViolation<Params>> violations = validator.validate(params,Default.class);
        violations.stream().map(ConstraintViolation::getMessage).forEach(System.out::println);
        assertFalse(violations.isEmpty());

    }

    /**
     * 测试参数对象
     */
    @Data
    class Params{
        @EnumAllowedValuesConstraint(allowedValues = {"allowed"},message = "仅支持:allowed")
        EnumTest value;
        @EnumAllowedValuesConstraint(allowedValues = {"1","2","3"},message = "仅支持:1")
        int i;
        @EnumAllowedValuesConstraint(allowedValues = {"2"},message = "仅支持:2")
        float f;
        @EnumAllowedValuesConstraint(allowedValues = {"3"},message = "仅支持:3")
        double d;
        @EnumAllowedValuesConstraint(allowedValues = {"4"},message = "仅支持:4")
        String s;
        @EnumAllowedValuesConstraint(allowedValues = {"5"},message = "仅支持:5")
        BigDecimal b;
        @EnumAllowedValuesConstraint(allowedValues = {"6"},message = "仅支持:6")
        byte b2;
        @EnumAllowedValuesConstraint(allowedValues = {"7"},message = "仅支持:7")
        short s2;
    }

    /**
     * 测试枚举类型
     */
    enum EnumTest{
        // 被允许的值
        allowed,
        // 不被允许的值
        not_allow
    }
}

测试结果

Spring Boot项目javax validation 自定义参数验证规则枚举限制

字符串类型值约束

这里还有一个验证规则是验证字符串类型的值仅支持部分内容。

Spring Boot项目javax validation 自定义参数验证规则枚举限制

具体代码请参考:微服务项目代码说明

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
熊晟华的头像 - 鹿快
评论 共1条

请登录后发表评论