Статьи

Обработка ошибки проверки бина

Как JAX-RS справляется с ошибкой проверки

Результатом ошибки проверки bean-компонента является ответ «400 Bad Request» от сервера. Давайте узнаем, как ответить клиенту более информативным ответом.

Два способа справиться с ошибками

Два способа сообщить клиенту о нарушениях целостности данных:

  • Ответьте клиенту со списком проблемных полей в HTTP-заголовке пользовательской пары ключ-значение, и
  • Используйте  тело ответа для инкапсуляции ответа об ошибке .

Оба метода имеют свои  плюсы и минусы . Выбор, который вы сделаете, будет зависеть от вашей бизнес-модели и требований клиентов. В любом случае вам нужно   хорошо документировать это, чтобы разработчик внешнего интерфейса знал,  как использовать ответ об ошибке .

JAX-RS_manage_validation_failures

Изучите Валидацию Бина с JAX-RS .

Заголовок HTTP пользовательской пары ключ-значение

Давайте посмотрим на первую технику.

Я собираюсь представить один способ обработки списка проблемных полей в теле ответа. Поскольку не существует принятой конвенции, вы можете разработать свою собственную структуру.

Я буду использовать карту имен свойств и сообщение с подробным описанием причин сбоя проверки.

Реализуйте менеджер исключений

В обоих случаях мы должны реализовать диспетчер исключений для  ConstraintViolationException . Это исключение содержит набор  объектов ConstraintViolation, каждый из  которых представляет нарушение.

Исключение нарушения ограничений

ConstraintViolation  экземпляр  содержит много полезной информации о нарушении , например , как имя поля и сообщения нарушения. Мы можем использовать эту информацию, чтобы построить ответ клиенту. Для этого  извлеките имена полей и сообщения об ошибках , превратив набор в поток и собрав его на карту следующим образом.

final Map<String, String> errorResponse =
    exception.getConstraintViolations()
      .stream()
      .collect(Collectors.toMap(o -> o.getPropertyPath().toString(), o -> o.getMessage()));

Добавить ошибки в тело ответа

Затем мы оборачиваем карту в пользовательский POJO, в котором есть одно поле — карта. Я вызываю пользовательское POJO  DataIntegrityValidation . Затем добавьте его в тело ответа так же, как мы делали это раньше.

return Response
         .status(Response.Status.BAD_REQUEST)
         .entity(new DataIntegrityValidation(errorResponse))
         .build();

Теперь тело ответа HTTP будет содержать ответ, аналогичный тому, который вы видите здесь.

{
  "errorResponse": {
  "entry": [{
      "key": "description",
      "value": "size must be between 100 and 2147483647"
    },
    {
      "key": "published",
      "value": "must be in the past"
    },
    {
      "key": "link",
      "value": "must match \"^(https?:\\/\\/)?([\\da-z\\.-]+)\\.([a-z\\.]{2,6})([\\/\\w \\.-]*)*\\/?$\""
    }]
 }
}

Вы заметите, что для каждого нарушения бина есть  сообщение. Bean Validation API  добавляет это для нас, поэтому мы не должны.

Тем не менее, мы можем настроить это сообщение. Передайте пользовательское сообщение в аннотации ограничений в виде метаданных. Можно интернационализировать его так, чтобы ответ отображался на родном языке клиента. Это выходит за рамки данной статьи, но я призываю вас найти примеры того, как это сделать.

Инкапсулируйте ответ об ошибке

Давайте посмотрим на второй способ сообщить клиенту о нарушениях.

Этот способ собирает ту же информацию, что и раньше, и  помещает ее в настраиваемое поле заголовка HTTP . Как и прежде, извлеките данные нарушения из  ConstraintViolationException  и создайте строку ошибок, разделенную запятыми.

final String message = 
    exception
      .getConstraintViolations()
      .stream()
      .map(cv -> extractPropertyName(cv.getPropertyPath().toString()) + " : " + cv.getMessage())
      .collect(Collectors.joining(", "));

Затем мы можем добавить это к ответу:

return Response
         .status(Response.Status.BAD_REQUEST)
         .header("X-Validation-Failure", message)
         .build();

Используйте пользовательский заголовок

Ответ включает в себя пользовательский заголовок «X-Validation-Failure», значением которого является строка сообщения. Это соглашение ставит префикс пользовательских заголовков с заглавной буквы  X,  за которым следует строка, описывающая назначение заголовков.

Затем в ответ заголовка HTTP добавляется следующая строка:

link : must match "^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$", 
published : must be in the past, 
description : size must be between 100 and 2147483647

Вы увидите, что он содержит те же данные, что и в предыдущем примере.

Что дальше?

Lynda.com предлагает онлайн-видео обучение для широкого спектра технологий Java EE. Идеальным курсом для тех, кто только начинает работать с корпоративной Java, является  Learning Java Enterprise Edition,  представленный мной. Курс длится чуть более 2 часов и охватывает все наиболее важные API Java EE, включая JAX-RS для RESTful API, JavaServerFaces, Enterprise Java Beans и многое другое.

Завершив этот курс, вы можете глубже погрузиться в Java, API Java EE и пройти курс о том, как создать  RESTful API с помощью JAX-RS , создать приложение для  чата с WebSocket API  и работать с JSON с помощью собственной JSON-обработки в Java EE.  API . Появляются новые курсы, так что почему бы не взглянуть и не подготовиться, чтобы ваша карьера в Java EE была ускорена.

Дальнейшее чтение

Я регулярно пишу о Java EE на  readlearncode.com  и только что опубликовал серию статей,   в которых более подробно рассматривается API JAX-RS и отвечаю на вопрос «  Что такое javax.ws.rs.core.context?». , Это серия из пяти частей, в которой более подробно рассматривается многократное использование аннотации @Context.

Если вы хотите расширить свои знания об этой технологии, в моих статьях по работе с  MediaTypes, JAX-RS  и Resource Entities изучите этот необходимый API более подробно.