Neu*_*nte 5 java validation spring spring-boot
问题很简单,但我还没有找到解决方案:
我懂了:
@RequestMapping("/example")
public class ExampleController {
@GetMapping("get")
public List<WhateverObject> getWhateverObjects(@RequestParam String objectName) {
/* Code */
}
}
Run Code Online (Sandbox Code Playgroud)
我们正在使用 SpringBoot,我希望根据定义的值列表验证“objectName”(该列表是枚举类型,但该部分很容易发生变化,所以我不介意是否需要写下这些值用手)。我所看到的关于@RequestParam对象验证的所有内容仅涵盖基本内容 ( @Min(value),@NotNull以及所有这些。
我知道 bean 的 CustomValidators,但它不适用于我当前的问题(而且我无法更改参数的类型)。Spring 是否有针对此自定义验证的特定内容,还是我需要在该/* Code */部分“直接”进行验证?
您可以创建自己的ConstraintValidator,但是您没有说明是否需要将您的值与Enum或 内部属性的值进行比较。我将在下一节中提供这两种情况的示例。
正如greenPadawan提到的,你可以通过你的 来改变参数的类型Enum,如果你可以/只需要它,那是最好的选择。
以下示例说明了如果您想保留String(甚至可以根据需要更新它以包括更多/其他检查),如何自定义该用例。第一步是创建用于检查约束的注释:
/**
* The annotated element must be included in value of the given accepted {@link Class} of {@link Enum}.
*/
@Documented
@Retention(RUNTIME)
@Target({FIELD, ANNOTATION_TYPE, PARAMETER})
@Constraint(validatedBy = EnumHasValueValidator.class)
public @interface EnumHasValue {
String message() default "must be one of the values included in {values}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* @return {@link Class} of {@link Enum} used to check the value
*/
Class<? extends Enum> enumClass();
/**
* @return {@code true} if {@code null} is accepted as a valid value, {@code false} otherwise.
*/
boolean isNullAccepted() default false;
}
Run Code Online (Sandbox Code Playgroud)
第二个是创建验证器本身:
/**
* Validates if the given {@link String} matches with one of the values belonging to the
* provided {@link Class} of {@link Enum}
*/
public class EnumHasValueValidator implements ConstraintValidator<EnumHasValue, String> {
private static final String ERROR_MESSAGE_PARAMETER = "values";
List<String> enumValidValues;
String constraintTemplate;
private boolean isNullAccepted;
@Override
public void initialize(final EnumHasValue hasValue) {
enumValidValues = Arrays.stream(hasValue.enumClass().getEnumConstants())
.map(Enum::name)
.collect(Collectors.toList());
constraintTemplate = hasValue.message();
isNullAccepted = hasValue.isNullAccepted();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
boolean isValid = null == value ? isNullAccepted
: enumValidValues.contains(value);
if (!isValid) {
HibernateConstraintValidatorContext hibernateContext = context.unwrap(HibernateConstraintValidatorContext.class);
hibernateContext.disableDefaultConstraintViolation();
hibernateContext.addMessageParameter(ERROR_MESSAGE_PARAMETER, enumValidValues)
.buildConstraintViolationWithTemplate(constraintTemplate)
.addConstraintViolation();
}
return isValid;
}
}
Run Code Online (Sandbox Code Playgroud)
现在您可以在以下示例中使用它:
public enum IngredientEnum {
CHEESE,
HAM,
ONION,
PINEAPPLE,
BACON,
MOZZARELLA
}
Run Code Online (Sandbox Code Playgroud)
和控制器:
@AllArgsConstructor
@RestController
@RequestMapping("/test")
@Validated
public class TestController {
@GetMapping("/testAgainstEnum")
public List<WhateverObject> testAgainstEnum(@RequestParam @EnumHasValue(enumClass=IngredientEnum.class) String objectName) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
您可以在下图中看到一个示例:
(如您所见,在这种情况下,考虑了小写/大写,如果需要,您可以在验证器中更改它)
在这种情况下,第一步是定义一种提取此类内部属性的方法:
/**
* Used to get the value of an internal property in an {@link Enum}.
*/
public interface IEnumInternalPropertyValue<T> {
/**
* Get the value of an internal property included in the {@link Enum}.
*/
T getInternalPropertyValue();
}
public enum PizzaEnum implements IEnumInternalPropertyValue<String> {
MARGUERITA("Margherita"),
CARBONARA("Carbonara");
private String internalValue;
PizzaEnum(String internalValue) {
this.internalValue = internalValue;
}
@Override
public String getInternalPropertyValue() {
return this.internalValue;
}
}
Run Code Online (Sandbox Code Playgroud)
所需的注释和相关验证器与之前的非常相似:
/**
* The annotated element must be included in an internal {@link String} property of the given accepted
* {@link Class} of {@link Enum}.
*/
@Documented
@Retention(RUNTIME)
@Target({FIELD, ANNOTATION_TYPE, PARAMETER})
@Constraint(validatedBy = EnumHasInternalStringValueValidator.class)
public @interface EnumHasInternalStringValue {
String message() default "must be one of the values included in {values}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
/**
* @return {@link Class} of {@link Enum} used to check the value
*/
Class<? extends Enum<? extends IEnumInternalPropertyValue<String>>> enumClass();
/**
* @return {@code true} if {@code null} is accepted as a valid value, {@code false} otherwise.
*/
boolean isNullAccepted() default false;
}
Run Code Online (Sandbox Code Playgroud)
验证器:
/**
* Validates if the given {@link String} matches with one of the internal {@link String} property belonging to the
* provided {@link Class} of {@link Enum}
*/
public class EnumHasInternalStringValueValidator implements ConstraintValidator<EnumHasInternalStringValue, String> {
private static final String ERROR_MESSAGE_PARAMETER = "values";
List<String> enumValidValues;
String constraintTemplate;
private boolean isNullAccepted;
@Override
public void initialize(final EnumHasInternalStringValue hasInternalStringValue) {
enumValidValues = Arrays.stream(hasInternalStringValue.enumClass().getEnumConstants())
.map(e -> ((IEnumInternalPropertyValue<String>)e).getInternalPropertyValue())
.collect(Collectors.toList());
constraintTemplate = hasInternalStringValue.message();
isNullAccepted = hasInternalStringValue.isNullAccepted();
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
boolean isValid = null == value ? isNullAccepted
: enumValidValues.contains(value);
if (!isValid) {
HibernateConstraintValidatorContext hibernateContext = context.unwrap(HibernateConstraintValidatorContext.class);
hibernateContext.disableDefaultConstraintViolation();
hibernateContext.addMessageParameter(ERROR_MESSAGE_PARAMETER, enumValidValues)
.buildConstraintViolationWithTemplate(constraintTemplate)
.addConstraintViolation();
}
return isValid;
}
}
Run Code Online (Sandbox Code Playgroud)
和控制器:
@AllArgsConstructor
@RestController
@RequestMapping("/test")
@Validated
public class TestController {
@GetMapping("/testStringInsideEnum")
public List<WhateverObject> testStringInsideEnum(@RequestParam @EnumHasInternalStringValue(enumClass=PizzaEnum.class) String objectName) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
您可以在下图中看到一个示例:
| 归档时间: |
|
| 查看次数: |
726 次 |
| 最近记录: |