Автор оригинала: Jonathan Cook.
1. Обзор
В этом уроке мы рассмотрим проверку компонентов с использованием фреймворка с открытым исходным кодом Jersey .
Как мы уже видели в предыдущих статьях, Jersey-это платформа с открытым исходным кодом для разработки веб-сервисов RESTful. Мы можем получить более подробную информацию о Джерси в нашем введении о том, как создать API с помощью Джерси и Spring.
2. Проверка бобов в Джерси
Валидация-это процесс проверки того, что некоторые данные подчиняются одному или нескольким заранее определенным ограничениям . Это, конечно, очень распространенный случай использования в большинстве приложений.
Фреймворк Java Bean Validation (JSR-380) стал стандартом де-факто для обработки такого рода операций в Java. Чтобы кратко изложить основы проверки Java Bean, пожалуйста, обратитесь к нашему предыдущему учебнику .
Джерси содержит модуль расширения для поддержки проверки бобов . Чтобы использовать эту возможность в нашем приложении, нам сначала нужно настроить ее. В следующем разделе мы рассмотрим, как настроить наше приложение.
3. Настройка приложения
Теперь давайте опираться на простой пример Fruit API из отличной статьи поддержки Jersey MVC.
3.1. Зависимости Maven
Прежде всего, давайте добавим зависимость проверки бобов в ваш pom.xml :
org.glassfish.jersey.ext jersey-bean-validation 2.27
Мы можем получить последнюю версию из Maven Central .
3.2. Настройка сервера
В Джерси мы обычно регистрируем функцию расширения, которую хотим использовать, в нашем классе конфигурации пользовательских ресурсов.
Однако для расширения проверки компонентов нет необходимости выполнять эту регистрацию. К счастью, это одно из немногих расширений, которые фреймворк Джерси регистрирует автоматически.
Наконец, чтобы отправить клиенту ошибки проверки мы добавим свойство сервера в нашу пользовательскую конфигурацию ресурсов :
public ViewApplicationConfig() { packages("com.baeldung.jersey.server"); property(ServerProperties.BV_SEND_ERROR_IN_RESPONSE, true); }
4. Проверка методов ресурсов JAX-RS
В этом разделе мы объясним два различных способа проверки входных параметров с помощью аннотаций ограничений:
- Использование встроенных ограничений API проверки компонентов
- Создание пользовательского ограничения и валидатора
4.1. Использование встроенных аннотаций ограничений
Давайте начнем с рассмотрения встроенных аннотаций ограничений:
@POST @Path("/create") @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public void createFruit( @NotNull(message = "Fruit name must not be null") @FormParam("name") String name, @NotNull(message = "Fruit colour must not be null") @FormParam("colour") String colour) { Fruit fruit = new Fruit(name, colour); SimpleStorageService.storeFruit(fruit); }
В этом примере мы создаем новый Фрукт , используя два параметра формы: имя и цвет . Мы используем аннотацию @NotNull , которая уже является частью API проверки компонентов.
Это накладывает простое ограничение not null на наши параметры формы. В случае, если один из параметров равен null , будет возвращено сообщение, объявленное в аннотации|/.
Естественно, мы продемонстрируем это с помощью модульного теста:
@Test public void givenCreateFruit_whenFormContainsNullParam_thenResponseCodeIsBadRequest() { Form form = new Form(); form.param("name", "apple"); form.param("colour", null); Response response = target("fruit/create").request(MediaType.APPLICATION_FORM_URLENCODED) .post(Entity.form(form)); assertEquals("Http Response should be 400 ", 400, response.getStatus()); assertThat(response.readEntity(String.class), containsString("Fruit colour must not be null")); }
В приведенном выше примере мы используем класс поддержки Jersey Test для тестирования нашего фруктового ресурса . Мы отправляем запрос POST с нулевым цветом и проверяем, что ответ содержит ожидаемое сообщение.
Для получения списка встроенных ограничений проверки посмотрите в документах .
4.2. Определение аннотации пользовательского ограничения
Иногда нам приходится накладывать более сложные ограничения. Мы можем сделать это, определив вашу собственную пользовательскую аннотацию.
Используя наш простой пример Fruit API, давайте представим, что нам нужно проверить, что все фрукты имеют действительный серийный номер:
@PUT @Path("/update") @Consumes("application/x-www-form-urlencoded") public void updateFruit(@SerialNumber @FormParam("serial") String serial) { //... }
В этом примере параметр serial должен удовлетворять ограничениям, определенным @SerialNumber , которые мы определим далее.
Сначала мы определим аннотацию ограничения:
@Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = { SerialNumber.Validator.class }) public @interface SerialNumber { String message() default "Fruit serial number is not valid"; Class>[] groups() default {}; Class extends Payload>[] payload() default {}; }
Далее мы определим класс валидатора Серийный номер.Валидатор :
public class Validator implements ConstraintValidator{ @Override public void initialize(SerialNumber serial) { } @Override public boolean isValid(String serial, ConstraintValidatorContext constraintValidatorContext) { String serialNumRegex = "^\\d{3}-\\d{3}-\\d{4}$"; return Pattern.matches(serialNumRegex, serial); } }
Ключевым моментом здесь является класс Validator должен реализовать ConstraintValidator , где T – это тип значения, которое мы хотим проверить , в нашем случае Строка .
Наконец, затем мы реализуем нашу пользовательскую логику проверки в isValid методе .
5. Проверка ресурсов
Кроме того, API проверки бобов также позволяет нам проверять объекты с помощью @Valid аннотации .
В следующем разделе мы объясним два различных способа проверки классов ресурсов с помощью этой аннотации:
- Во-первых, запросите проверку ресурсов
- Во-вторых, Проверка ресурсов ответа
Давайте начнем с добавления аннотации @Min к нашему объекту Fruit :
@XmlRootElement public class Fruit { @Min(value = 10, message = "Fruit weight must be 10 or greater") private Integer weight; //... }
5.1. Запрос Проверки ресурсов
Прежде всего, мы включим проверку с помощью @Valid в нашем Фруктовом ресурсе классе:
@POST @Path("/create") @Consumes("application/json") public void createFruit(@Valid Fruit fruit) { SimpleStorageService.storeFruit(fruit); }
В приведенном выше примере если мы попытаемся создать плод с весом менее 10, мы получим ошибку проверки.
5.2. Проверка ресурсов ответа
Аналогично, в следующем примере мы увидим, как проверить ресурс ответа:
@GET @Valid @Produces("application/json") @Path("/search/{name}") public Fruit findFruitByName(@PathParam("name") String name) { return SimpleStorageService.findByName(name); }
Обратите внимание, как мы используем одну и ту же аннотацию @Valid . Но на этот раз мы используем его на уровне метода ресурсов, чтобы убедиться, что ответ действителен.
6. Пользовательский обработчик Исключений
В этой последней части мы кратко рассмотрим, как создать пользовательский обработчик исключений. Это полезно, когда мы хотим вернуть пользовательский ответ, если мы нарушаем определенное ограничение.
Давайте начнем с определения нашего Fruit ExceptionMapper :
public class FruitExceptionMapper implements ExceptionMapper{ @Override public Response toResponse(ConstraintViolationException exception) { return Response.status(Response.Status.BAD_REQUEST) .entity(prepareMessage(exception)) .type("text/plain") .build(); } private String prepareMessage(ConstraintViolationException exception) { StringBuilder message = new StringBuilder(); for (ConstraintViolation> cv : exception.getConstraintViolations()) { message.append(cv.getPropertyPath() + " " + cv.getMessage() + "\n"); } return message.toString(); } }
Прежде всего, мы определяем пользовательский поставщик сопоставления исключений. Для этого мы реализуем интерфейс ExceptionMapper , используя исключение ConstraintViolationException .
Следовательно, мы увидим, что при этом исключении бросается то ответ метод нашего пользовательского экземпляра сопоставления исключений будет быть вызванным .
Кроме того, в этом простом примере мы перебираем все нарушения и добавляем каждое свойство и сообщение, которое будет отправлено обратно в ответ.
Далее, чтобы использовать наш пользовательский картограф исключений, нам необходимо зарегистрировать вашего провайдера :
@Override protected Application configure() { ViewApplicationConfig config = new ViewApplicationConfig(); config.register(FruitExceptionMapper.class); return config; }
Наконец, мы добавляем конечную точку для возврата недопустимого Фрукта , чтобы показать обработчик исключений в действии:
@GET @Produces(MediaType.TEXT_HTML) @Path("/exception") @Valid public Fruit exception() { Fruit fruit = new Fruit(); fruit.setName("a"); fruit.setColour("b"); return fruit; }
7. Заключение
Подводя итог, в этом уроке мы рассмотрели расширение API проверки Jersey Bean.
Во-первых, мы начали с представления того, как API проверки бобов может использоваться в Джерси. Кроме того, мы рассмотрели, как настроить пример веб-приложения.
Наконец, мы рассмотрели несколько способов проверки с помощью Jersey и как написать пользовательский обработчик исключений.
Как всегда, полный исходный код статьи доступен на GitHub .