Spring Boot 为枚举类型编写验证的真实的优势是什么?

7uzetpgm  于 2023-06-22  发布在  Spring
关注(0)|答案(1)|浏览(186)

我不明白为枚举类实现自定义验证器而不是直接处理引发的错误(即org.springframework.http.converter.HttpMessageNotReadableExceptin)的真实的好处
按照各种示例中所报告的内容,对于每个Enum类,我必须编写两个类进行验证,大大增加了代码,但我没有看到错误处理中的任何真实的好处(例如,在String message() default "must be any of {anyOf}";给出的错误消息中自动生成)。那么,为什么不直接在RestControlAdvice中编写一个方法来处理错误呢?
按照Validations for Enum Types给出的示例,我编写了一个在 Boot 中测试枚举类的自定义验证器

public enum GenderTypeEnum {

    MALE("male"),
    FEMALE("female");

    private final String value;

    private GenderTypeEnum(String value) {
        this.value = value;
    }
    
    public String getGender(){
        return this.value;
    }
}

和/或

import com.example.springbootenumvalidator.enums.GenderTypeEnum;
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

import java.util.Arrays;

public class GenderTypeEnumValidator implements ConstraintValidator<ValidGenderTypeEnum, GenderTypeEnum> {
    private GenderTypeEnum[] subset;

    @Override
    public void initialize(ValidGenderTypeEnum constraint) {

        this.subset = constraint.anyOf();
    }

    @Override
    public boolean isValid(GenderTypeEnum value, ConstraintValidatorContext context) {
        return value == null || Arrays.asList(subset).contains(value);
    }
}

和/或

import com.example.springbootenumvalidator.enums.GenderTypeEnum;
import jakarta.validation.Constraint;
import jakarta.validation.Payload;

import java.lang.annotation.*;

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

    GenderTypeEnum[] anyOf();
    String message() default "must be any of {anyOf}";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};

}

和/或

import com.example.springbootenumvalidator.enums.GenderTypeEnum;
import com.example.springbootenumvalidator.validator.ValidGenderTypeEnum;
import lombok.*;

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class UserDTO {

    @ValidGenderTypeEnum(anyOf = {GenderTypeEnum.MALE, GenderTypeEnum.FEMALE})
    private GenderTypeEnum gender;

}

和/或

import com.example.springbootenumvalidator.dto.UserDTO;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api/v1")
public class UserController {

    @GetMapping(path = "/user")
    @ResponseBody
    public ResponseEntity<?> getUser(

            @Valid
            @RequestBody
            UserDTO user

    ) {
        return ResponseEntity
                .ok()
                .body(user);

    }
}

设置为application.properties

spring.jackson.mapper.accept-case-insensitive-enums=true

然后

和/或

控制台中的错误消息:

2023-06-11T09:17:23.702+02:00  WARN 16912 --- [nio-8080-exec-2] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize value of type `com.example.springbootenumvalidator.enums.GenderTypeEnum` from String "MALEXX": not one of the values accepted for Enum class: [FEMALE, MALE]]
5lhxktic

5lhxktic1#

如果你想限制用户只能输入枚举的子集值,这是有意义的。
当然,您可以创建另一个单独的枚举,只包含这些子集值,但随后您需要实现一些代码来在此枚举与原始枚举之间进行Map。虽然这并不难做到,但有些人可能不想这样做。

相关问题