gpt4 book ai didi

java - SpringBoot : Custom validation for a @RequestParam parameter in a REST endpint

转载 作者:行者123 更新时间:2023-12-01 11:57:36 27 4
gpt4 key购买 nike

问题很简单,但是我还没有找到解决方案:
我懂了:

@RequestMapping("/example")
public class ExampleController {

@GetMapping("get")
public List<WhateverObject> getWhateverObjects(@RequestParam String objectName) {

/* Code */
}

}
我们正在使用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;

}
第二个是创建 validator 本身:
/**
* 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;
}
}
现在,您可以在以下示例中使用它:
public enum IngredientEnum {
CHEESE,
HAM,
ONION,
PINEAPPLE,
BACON,
MOZZARELLA
}
和 Controller :
@AllArgsConstructor
@RestController
@RequestMapping("/test")
@Validated
public class TestController {

@GetMapping("/testAgainstEnum")
public List<WhateverObject> testAgainstEnum(@RequestParam @EnumHasValue(enumClass=IngredientEnum.class) String objectName) {
...
}
}
您可以在下图中看到一个示例:
EnumHasValue example
(如您所见,在这种情况下,考虑到了大小写,您可以根据需要在 validator 中进行更改)

与内部枚举属性比较
在这种情况下,第一步是定义一种提取此类内部属性的方法:
/**
* 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;
}
}
所需的注释和相关的 validator 与之前的注释非常相似:
/**
* 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;
}
validator :
/**
* 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;
}
}
和 Controller :
@AllArgsConstructor
@RestController
@RequestMapping("/test")
@Validated
public class TestController {

@GetMapping("/testStringInsideEnum")
public List<WhateverObject> testStringInsideEnum(@RequestParam @EnumHasInternalStringValue(enumClass=PizzaEnum.class) String objectName) {
...
}
}
您可以在下图中看到一个示例:
EnumHasValue example
最后的注释和 validator 的源代码可以在 here中找到

关于java - SpringBoot : Custom validation for a @RequestParam parameter in a REST endpint,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63487389/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com