我不明白为枚举类实现自定义验证器而不是直接处理引发的错误(即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]]
1条答案
按热度按时间5lhxktic1#
如果你想限制用户只能输入枚举的子集值,这是有意义的。
当然,您可以创建另一个单独的枚举,只包含这些子集值,但随后您需要实现一些代码来在此枚举与原始枚举之间进行Map。虽然这并不难做到,但有些人可能不想这样做。