bean-validation - 使用 javax 验证器或 spring 验证器如何为相同类型的不同字段提供单独的错误消息

标签 bean-validation spring-validator

目前我有一个 Spring Boot 应用程序,为了验证 POJO,我正在使用 javax 验证器。我们在应用程序中有休息 api。

我的问题是 :如何为相同类型的不同字段提供单独的错误消息。

举例说明 :引用下面的示例代码:如果 a1.name 不存在,则有单独的错误消息(ERROR1),如果 a2.name 不存在,则有单独的错误消息(ERROR2)

我的 POJO,带有 javax 验证器注释,如下所示:

public class A{
 @NotNull
 private String name;
 @NotNull
 private String age;
 //..getters and setters
}

public class B{
 @Valid
 private A a1;
 @Valid
 private A a2;
 }

我的休息 Controller 看起来像:
@RestController
public class Controller1{
 @GetMapping(value="/abc")
 public void api1(@Valid @RequestBody B b){...}
}

我尝试使用组,但 javax @valid annotaion 不支持组。
我尝试使用 spring @Validated 注释的另一种选择,但问题是它不能应用于字段。

最佳答案

据我所知,Bean 验证组不是为满足此用例而设计的。

如果您这样调用 REST 服务:

curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X GET -d '{"a1":{}, "a2":{}}}' http://localhost:8080/abc

回应是:
{
       "timestamp":"2017-11-10T17:22:07.534+0000",
       "status":400,
       "error":"Bad Request",
       "exception":"org.springframework.web.bind.MethodArgumentNotValidException",
       "errors":[
          {
             "codes":["NotNull.b.a1.name", "NotNull.a1.name", "NotNull.name", "NotNull.java.lang.String", "NotNull"],
             "arguments":[
                {
                   "codes":["b.a1.name", "a1.name" ],
                   "arguments":null,
                   "defaultMessage":"a1.name",
                   "code":"a1.name"
                }
             ],
             "defaultMessage":"may not be null",
             "objectName":"b",
             "field":"a1.name",
             "rejectedValue":null,
             "bindingFailure":false,
             "code":"NotNull"
          },
          {
             "codes":["NotNull.b.a2.age", "NotNull.a2.age", "NotNull.age", "NotNull.java.lang.String", "NotNull"],
             "arguments":[
                {
                   "codes":[ "b.a2.age", "a2.age"],
                   "arguments":null,
                   "defaultMessage":"a2.age",
                   "code":"a2.age"
                }
             ],
             "defaultMessage":"may not be null",
             "objectName":"b",
             "field":"a2.age",
             "rejectedValue":null,
             "bindingFailure":false,
             "code":"NotNull"
          },
          {
             "codes":[ "NotNull.b.a1.age", "NotNull.a1.age", "NotNull.age", "NotNull.java.lang.String", "NotNull"],
             "arguments":[
                {
                   "codes":["b.a1.age", "a1.age"],
                   "arguments":null,
                   "defaultMessage":"a1.age",
                   "code":"a1.age"
                }
             ],
             "defaultMessage":"may not be null",
             "objectName":"b",
             "field":"a1.age",
             "rejectedValue":null,
             "bindingFailure":false,
             "code":"NotNull"
          },
          {
             "codes":["NotNull.b.a2.name", "NotNull.a2.name", "NotNull.name", "NotNull.java.lang.String", "NotNull"],
             "arguments":[
                {
                   "codes":["b.a2.name", "a2.name"],
                   "arguments":null,
                   "defaultMessage":"a2.name",
                   "code":"a2.name"
                }
             ],
             "defaultMessage":"may not be null",
             "objectName":"b",
             "field":"a2.name",
             "rejectedValue":null,
             "bindingFailure":false,
             "code":"NotNull"
          }
       ],
       "message":"Validation failed for object='b'. Error count: 4",
       "path":"/api/profile/abc"
    }

如果您仔细观察,您会发现响应显示您收到四个验证错误,并且每个错误都包含验证详细信息,例如约束、对象和目标字段,例如:NotNull.b.a1.name .

插入这个详细的响应以显示适当的验证消息是 View (REST 客户端)的责任。

有时在客户端插入消息不是一种选择。在这种情况下,您可以使用 Spring 添加自定义“验证错误”处理程序。类似的东西:
@RestController
public class Controller1 {

    // This assumes that Spring i18n is properly configured
    @Autowired
    private MessageSource messageSource;

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ResponseBody
    public Map<String, String> processValidationError(MethodArgumentNotValidException ex) {
        BindingResult result = ex.getBindingResult();
        List<FieldError> fieldErrors = result.getFieldErrors();

        Map<String, String> errors = new HashMap<>();
        for (FieldError fieldError: fieldErrors) {
            String fieldPath = fieldError.getField();
            String messageCode = fieldError.getCode() + "." + fieldPath;
            String validationMessage = messageSource.getMessage(messageCode, new Object[]{fieldError.getRejectedValue()}, Locale.getDefault());

            // add the validation message, for example "NotNull.a1.name" => "a should not be null"
            errors.put(fieldError.getField(), validationMessage);
        }

        return errors;
    } 


    @GetMapping(value="/abc")
    public void api1(@Valid @RequestBody B b){
        //...
    }
}

关于bean-validation - 使用 javax 验证器或 spring 验证器如何为相同类型的不同字段提供单独的错误消息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47060454/

相关文章:

java - JSR 303 Bean 验证

java - Bean Validation + Resource Bundle 的想法?

java - 错误 : No validator could be found for type: java. time.LocalDate

spring-boot - 在 SpringBoot 中,如何为 MultipartFile 参数创建自定义验证器?

json - 如何配置 Gson 以序列化一组 JSR-303 ConstraintViolation 对象?

java - 将验证消息放入数据库

java - 多种 View ,一种形式,不同的验证

java - 多约束 Spring 验证

Java Spring Web - 使用 validator 将子属性转换为对象