Как JAX-RS справляется с ошибкой проверки
Результатом ошибки проверки bean-компонента является ответ «400 Bad Request» от сервера. Давайте узнаем, как ответить клиенту более информативным ответом.
Два способа справиться с ошибками
Два способа сообщить клиенту о нарушениях целостности данных:
- Ответьте клиенту со списком проблемных полей в HTTP-заголовке пользовательской пары ключ-значение, и
- Используйте тело ответа для инкапсуляции ответа об ошибке .
Оба метода имеют свои плюсы и минусы . Выбор, который вы сделаете, будет зависеть от вашей бизнес-модели и требований клиентов. В любом случае вам нужно хорошо документировать это, чтобы разработчик внешнего интерфейса знал, как использовать ответ об ошибке .
Изучите Валидацию Бина с 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 более подробно.