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

Anu*_*rag 9 java validation spring spring-validator

我有一个从第三方浏览器重定向回我的 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);
    }
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

因为有一个 MapBindingResult,所以我确信 Spring 必须支持 Maps 进行验证,想知道如何实现。所以想知道这是否是正确的方法,或者我是否朝着错误的方向前进,并且有更好的方法可以做到这一点。

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

Anu*_*rag 5

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

org.springframework.validation.MapBindingResult我通过传入需要验证的映射和该映射的标识符名称(用于全局/根级错误消息)来创建一个。此 Errors 对象与要验证的映射一起传递到验证器中,如下面的代码片段所示。

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

扩展并重写该方法以提供其自己的实现,以从正在验证的映射中获取字段MapBindingResultAbstractBindingResultgetActualFieldValue

private final Map<?, ?> target;

@Override
protected Object getActualFieldValue(String field) {
    return this.target.get(field);
}
Run Code Online (Sandbox Code Playgroud)

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

ValidationUtils.rejectIfEmpty(errors, "checksum", "field.required");
Run Code Online (Sandbox Code Playgroud)

其中“checksum”是我地图中的关键。啊,传承之美!:)

对于其他重要的验证,我只需将对象转换为映射并编写自定义验证代码。

所以验证器看起来像 -

@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");
}
Run Code Online (Sandbox Code Playgroud)