В ответе проверки отсутствуют сведения об ошибках

#java #spring-boot #validation

#java #весенняя загрузка #проверка

Вопрос:

У меня есть контроллер Spring Boot Rest, который получает текст сообщения с проверенным полем. Если я отправляю тело, которое нарушает проверку, я получаю ответ об ошибке.

Но в этом ответе мне не хватает подробного описания ошибок, какая часть проверки не выполняется. В зарегистрированном исключении в серверной части это включено, но я бы хотел, чтобы оно было видно для клиента:

HTTP-ответ:

 {
  "timestamp": "2020-11-19T12:15:34.957 00:00",
  "status": 400,
  "error": "Bad Request",
  "message": "Validation failed for object='postBody'. Error count: 1",
  // <-- here I am missing the errors field that contains the (list of) error messages.
  "path": "/comments"
}
 

Контроллер и PostBody:

 @RestController
@Validated
public class CommentsController {

    public void createComment(PostBody postBody) {
      //do stuff
    }
}

public class PostBody {
    private String text;

    @Size(max = 10) 
    public String getText() {
        return text;
    }
    // setter
}
 

Исключение в журналах серверной части содержит ошибки:

 2020-11-19 13:15:34 WARN  o.s.w.s.m.s.DefaultHandlerExceptionResolver - 
    Resolved [org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument [0] in 
    public CommentsController.createComment(PostBody): 
    [Field error in object 'postBody' on field 'text': rejected value [my very long input]; 
    codes [Size.postBody.text,Size.text,Size.java.lang.String,Size]; arguments 
    [org.springframework.context.support.DefaultMessageSourceResolvable: codes [postBody.text,text]; 
    arguments []; default message [text],10,0]; default message [size must be between 0 and 10]] ]
 

Нужно ли мне настраивать что-либо дополнительное, чтобы получить сведения об ошибках в ответе? Я бы ожидал, что это будет включено из коробки.

Ответ №1:

Я должен добавить server.error.include-binding-errors: always в свой application.yml , чтобы включить "errors" поле в резонансе ошибки:

Итак, мой application.yml сейчас:

 server:
  error:
    include-message: always
    include-binding-errors: always
 

И ответ выглядит следующим образом. Это более подробно, чем я ожидал, но оно содержит необходимую информацию без необходимости написания кода, просто конфигурацию:

 {
  "timestamp": "2020-11-19T12:15:34.957 00:00",
  "status": 400,
  "errors": [
    {
      "codes": [
        "Size.postBody.text",
        "Size.text",
        "Size.java.lang.String",
        "Size"
      ],
      "arguments": [
        {
          "codes": [
            "postBody.text",
            "text"
          ],
          "arguments": null,
          "defaultMessage": "text",
          "code": "text"
        },
        10,
        0
      ],
      "defaultMessage": "size must be between 0 and 10",
      "objectName": "postBody",
      "field": "text",
      "rejectedValue": "my very long input",
      "bindingFailure": false,
      "code": "Size"
    }
  "error": "Bad Request",
  "message": "Validation failed for object='postBody'. Error count: 1", messages.
  "path": "/comments"
}
 

В application.yml я уже настроил поле server.error.include-message: always . В противном "message": случае значение в ответе об ошибке было бы просто пустой строкой.

А вот обсуждение на GitHub по этому поводу: https://github.com/spring-projects/spring-boot/issues/20505#issuecomment-621295137

Ответ №2:

Я рекомендую вам использовать метод для проверки проверки вашей сущности, есть пример

  private void checkIfReadyToSave(PostBody myPost) {
    Set<ConstraintViolation<Product>> violations =
        validator.validate(product, PostBodyCreation.class);
    if (!violations.isEmpty()) {
      Map<String, Object> body = new LinkedHashMap<>();
      Set<String> keys =
          violations.stream().map(ConstraintViolation::getMessage).collect(Collectors.toSet());
      body.put("errors", keys);
      throw new BeanValidationException(ErrorConstants.POST_BODY_MISSING_ERROR_MSG, body.toString());
    }
  }
 

И вот как вы можете выполнить проверку своей модели с помощью весенней проверки

 public class PostBody {



@NotBlank(groups = PostBodyCreation.class, message = "text.notSetted")
@Field("text")
private String text;
 

И это, как создать интерфейс проверки :

 import javax.validation.groups.Defau<

public interface PostBodyCreation extends Default {
}
 

Комментарии:

1. Я использую сгенерированный OpenAPI объект RequestBody, поэтому, я думаю, было бы сложно добавить пользовательский валидатор в поле.

2. Вы можете добавить его в свою модель, которая будет отображать объект запроса open API