如何以编程方式使用 Spring Validator 验证 Map<String, String>

How to validate a Map<String, String> using Spring Validator programmatically

我有一个地图,我从第三方的浏览器重定向回我的 Spring 控制器,如下所示 -

@RequestMapping(value = "/capture", method = RequestMethod.POST, consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
    public void capture(@RequestParam
    final Map<String, String> response)
    {
        // TODO : perform validations first.
        captureResponse(response);
    }

在使用此负载之前,我需要进行重要的验证,包括首先检查映射的非空值,然后在校验和验证中使用这些值。因此,我想使用 Spring Validator 接口以编程方式验证我的有效载荷。但是,我找不到任何用于验证 Map 的验证器示例。

为了验证 Java 对象,我了解如何通过传递对象和 BeanPropertyBindingResult 来调用验证器以将错误包含到验证器,如下所示 -

final Errors errors = new BeanPropertyBindingResult(object, objectName);
myValidator.validate(object, errors);
if (errors.hasErrors())
{
    throw new MyWebserviceValidationException(errors);
}

对于地图,我可以看到 MapBindingResult class 延伸 AbstractBindingResult。我应该简单地使用它,并在 Object object 中传递我的地图,然后在验证器中将其转换回 Map 吗?另外,supports(final Class<?> clazz) 的 Validator 方法将如何在我的验证器中实现?它会像下面的代码片段一样,只能有一个验证器支持 HashMap 的这个通用 class 吗?怎么感觉不太对。 (虽然这对我来说并不重要,因为我将注入我的验证器并直接使用它,而不是通过验证器注册表,但仍然很好奇。)

@Override
public boolean supports(final Class<?> clazz)
{
    return HashMap.class.equals(clazz);
}

因为有一个 MapBindingResult,我肯定 Spring 必须支持地图进行验证,想知道如何。所以想知道这是不是要走的路,还是我走错了方向,还有更好的方法。

请注意,我想以编程方式而不是通过注释来执行此操作。

另一种方法是为地图创建自定义约束注释。

你可以看看下面的link:

https://www.baeldung.com/spring-mvc-custom-validator

正如我所想,Spring Validator org.springframework.validation.Validator 确实支持对 Map 的验证。我自己试了一下,确实有效!

我通过传入我需要验证的地图和该地图的标识符名称(用于 global/root-level 错误消息)创建了一个 org.springframework.validation.MapBindingResult。这个 Errors 对象在验证器中传递,连同要验证的地图一起传递,如下面的代码片段所示。

final Errors errors = new MapBindingResult(responseMap, "responseMap");
myValidator.validate(responseMap, errors);
if (errors.hasErrors())
{
    throw new MyWebserviceValidationException(errors);
}

MapBindingResult 扩展了 AbstractBindingResult 并覆盖了方法 getActualFieldValue 以提供它自己的实现以从正在验证的地图中获取字段。

private final Map<?, ?> target;

@Override
protected Object getActualFieldValue(String field) {
    return this.target.get(field);
}

因此,在验证器中,我能够使用 org.springframework.validation.ValidationUtils 中提供的所有有用的实用方法,就像我们在标准对象 bean 验证器中使用的那样。例如 -

ValidationUtils.rejectIfEmpty(errors, "checksum", "field.required");

其中 "checksum" 是我地图中的一个键。啊,传承之美! :)

对于其他 non-trivial 验证,我只是将 Object 转换为 Map 并编写了我的自定义验证代码。

所以验证器看起来像 -

@Override
public boolean supports(final Class<?> clazz)
{
    return HashMap.class.equals(clazz);
}
@Override
public void validate(final Object target, final Errors errors)
{
    ValidationUtils.rejectIfEmpty(errors, "transactionId", "field.required");
    ValidationUtils.rejectIfEmpty(errors, "checksum", "field.required");

    final Map<String, String> response = (HashMap<String, String>) target;
    // do custom validations with the map's attributes
    // ....
    // if validation fails, reject the whole map - 
         errors.reject("response.map.invalid");
}

验证地图中的参数

为了按照特定映射验证您的地图,您将需要一个自定义验证器。

因为这可能是某些人的用例,所以可以使用 org.springframework.validation 注释来完成 @RequestParam 的验证,例如

@GetMapping(value = "/search")
public ResponseEntity<T> search(@RequestParam 
   Map<@NotBlank String,@NotBlank String> searchParams,

虽然 @NotBlank 检查您的字符串是否不是 ""@NotNull 可以验证 non-null 个参数,我猜这是你需要的。