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

时间:2019-07-14 11:00:17

标签: java spring validation spring-validator

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

@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);
}

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

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

由于有一个MapBindingResult,我很肯定Spring必须支持Maps进行验证,想知道如何做。所以想知道这是走的路,还是我朝着错误的方向前进,并且有更好的方法可以做到这一点。

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

2 个答案:

答案 0 :(得分:1)

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

您可以查看以下链接:

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

答案 1 :(得分:1)

就像我想的那样,Spring Validator org.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);
}

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");

其中“校验和”是我地图中的键。啊,继承的美丽! :)

对于其他非平凡的验证,我只需将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");
}