首页 > 解决方案 > 检查 RequestParam Springboot 中的特定枚举值

问题描述

我有一个带有一些控制器的 Spring Boot API,这些控制器使用枚举作为 RequestParam。这一切都很好。如果我使用不在枚举中的值,我会得到一个错误。但是,如果可以验证 requestParam 是否是枚举子集的一部分,我似乎找不到任何地方。

枚举看起来像这样:

public enum Type {
    @JsonProperty("een")
    ONE("een"),

    @JsonProperty("twee")
    TWO("twee"),

    @JsonProperty("drie")
    THREE("drie");

    private final String value;

    private static final Map<String, Type> lookup = new HashMap<String, Type>();

    static {
        for (Type type : Type.values()) {
            lookup.put(type.value, type);
        }
    }

    private Type(String value) {
        this.value = value;
    }

    public String getValue() {
        return this.value;
    }

    public static Type get(String value) {
        return lookup.get(value);
    }

    @Override
    public String toString() {
        return this.value;
    }
}

我创建了一个 org.springframework.core.convert.converter.Converter 以便像这样使用枚举(具有不同枚举名称的值)。

端点看起来像这样:

@GetMapping("/my-endpoint")
    public ResponseEntity<Set<Item>> getItems(
        @RequestParam Type type
    ) {
        <... etc>
    return new ResponseEntity<Set<Item>>(items, HttpStatus.OK);
}

因此,例如,如果 RequestParam 的值为“een”或“twee”,我想验证我的一个端点,如果它的值为“drie”,则应该返回一个错误的请求。对于另一个端点,我想验证 RequestParam 的值是否为“twee”或“drie”。这是一个简化的示例,实际上我在枚举中有更多选项,并且有很多使用枚举的全部或子集的端点。我知道我可以使用子集创建不同的枚举,但是因为它们每次都经常在不同的子集中使用,所以这并不是一个真正的选择。

有没有其他方法可以做到这一点?

标签: spring-bootenumsparameterscontroller

解决方案


我通过这篇文章想出了如何做到这一点:https ://www.baeldung.com/javax-validations-enums 。

基本上,我为我的枚举创建了一个特定的注释(我不确定这是否可以更通用)。

@Constraint(validatedBy = TypeSubsetValidator.class)
@Target({ ElementType.TYPE, ElementType.PARAMETER, ElementType.FIELD })
@Retention(RUNTIME)
public @interface TypeSubset {
    Type[] anyOf();

    String message() default "error.wrongType";

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

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

并创建了随附的验证器:

 public class TypeSubsetValidator implements ConstraintValidator<TypeSubset, Type> {
    private Type[] subset;

    @Override
    public void initialize(TypeSubset annotation) {
        this.subset = annotation.anyOf();
    }

    @Override
    public boolean isValid(Type value, ConstraintValidatorContext context) {
        if (value == null) {
            return true;
        }

        return Arrays.asList(subset).contains(value);
    }
}

比验证可以这样使用:

@GetMapping("/my-endpoint")
    public ResponseEntity<Set<Item>> getItems(
        @TypeSubset(anyOf = { Type.ONE, Type.TWO}) @RequestParam  Type type
    ) {
        <... etc>
    return new ResponseEntity<Set<Item>>(items, HttpStatus.OK);
}

现在只有 Type.ONE 和 Type.TWO 可以用作 RequestParam,其他值将返回错误请求。


推荐阅读