当前位置:网站首页>Enum + Validation 的个人最佳实践 demo 分享

Enum + Validation 的个人最佳实践 demo 分享

2022-07-07 15:39:00 小水牛...

Enum + Validation 的个人最佳实践 demo 分享

前言

很多场景中我们需要校验前端传来的参数是否属于某个 Enum 值,分享一段个人最佳实践的 demo

  • Enum 的最简声明
  • @OfEnum & OfEnumValidator
  • Test suite

Enum 声明

通常 Enum 的声明是映射到对应的 DB 字段,个人实践是直接以 Enum Name 对应具体值,无需在 Enum 里包含释义信息等,比如 SexEnum 声明为 man woman 而不是类似 男("man") 女("woman"),这样也方便后续 Validator 类的编写

public enum SexEnum {
    

    man
    , woman
    ;

}

@OfEnum

@Constraint(
        validatedBy = {
     OfEnumValidator.class }
)
@Target({
    ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OfEnum {
    

    Class<?> enumType();

    String message() default "目标值必须是 ${enumType.simpleName} 类型的枚举值";

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

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

}

该注解主要用于字段、参数上结合对应的 OfEnumValidator 执行校验

  • @Constraint 注解声明对应的 OfEnumValidator
  • 属性 enumType 声明对应的枚举类型
  • message 中引用 EL 表达式输出合理的校验信息

OfEnumValidator

public class OfEnumValidator implements ConstraintValidator<OfEnum, String> {
    

    private List<String> enums;

    // 枚举值初始化
    @Override
    public void initialize(OfEnum constraintAnnotation) {
    
        enums = Optional.ofNullable(constraintAnnotation)
                .map(OfEnum::enumType)
                .filter(Class::isEnum)
                .map(Class::getEnumConstants)
                .map(arr -> Arrays.stream(arr)
                        .map(Object::toString)
                        .collect(Collectors.toList()))
                .orElse(new ArrayList<>());
    }

    @Override
    public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
    

        return !ObjectUtils.isEmpty(enums) && enums.contains(s);
    }
}

OfEnumValidator 类负责执行 @OfEnum 注解对应的校验

  • 基于指定的枚举类来初始化 enums 属性,直接基于 toString 方法,因此前文推荐 Enum 的简单声明
  • isValid 进行校验

Test

public class OfEnumTest {
    

    ApplicationContextRunner runner = new ApplicationContextRunner()
            .withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class));

    @Validated
    static class Handler {
    

        public void handle(@OfEnum(enumType = SexEnum.class) String sex) {
    

        }
    }

    static class Config {
    

        @Bean
        public Handler handler() {
    
            return new Handler();
        }
    }

    @Test
    public void test() {
    
        runner.withUserConfiguration(Config.class)
                .run(context -> {
    
                    Handler bean = context.getBean(Handler.class);
                    bean.handle("man");
                    assertThatThrownBy(() -> bean.handle("error"))
                            .isInstanceOf(ConstraintViolationException.class)
                            .hasMessage("handle.sex: 目标值必须是 SexEnum 类型的枚举值");
                });
    }
}

针对 @OfEnum 注解的测试类:

  • 基于 ApplicationContextRunner 编写,很好用的测试辅助类,之前有分享
  • 可以看到,当传入 SexEnum 成员之外的值时,会抛出校验异常

总结

以上就是个人 Enum + Validation 的最佳实践分享

原网站

版权声明
本文为[小水牛...]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_42189048/article/details/125276495