Перейти к основному содержимому

Проверка списков в контроллере Spring

· 4 мин. чтения

1. Введение

Проверка вводимых пользователем данных является общим требованием в любом приложении. В этом руководстве мы рассмотрим способы проверки списка объектов в качестве параметра контроллера Spring .

Мы добавим проверку на уровне контроллера, чтобы убедиться, что указанные пользователем данные удовлетворяют заданным условиям.

2. Добавление ограничений к компоненту

В нашем примере мы будем использовать простой контроллер Spring, который управляет базой данных фильмов. Мы сосредоточимся на методе, который принимает список фильмов и добавляет их в базу данных после проверки списка.

Итак, давайте начнем с добавления ограничений на компонент Movie с помощью проверки javax :

public class Movie {

private String id;

@NotEmpty(message = "Movie name cannot be empty.")
private String name;

// standard setters and getters
}

3. Добавление аннотаций проверки в контроллер

Посмотрим на наш контроллер. Во- первых, мы добавим аннотацию @Validated к классу контроллера :

@Validated
@RestController
@RequestMapping("/movies")
public class MovieController {

@Autowired
private MovieService movieService;

//...
}

Далее давайте напишем метод контроллера, в котором мы будем проверять список переданных объектов Movie .

Мы добавим аннотацию @NotEmpty в наш список фильмов , чтобы убедиться, что в списке должен быть хотя бы один элемент. В то же время мы добавим аннотацию @Valid , чтобы убедиться, что сами объекты Movie действительны:

@PostMapping
public void addAll(
@RequestBody
@NotEmpty(message = "Input movie list cannot be empty.")
List<@Valid Movie> movies) {
movieService.addAll(movies);
}

Если мы вызовем метод контроллера с пустым вводом списка фильмов , то проверка завершится ошибкой из-за аннотации @NotEmpty , и мы увидим сообщение:

Input movie list cannot be empty.

Аннотация @Valid гарантирует , что ограничения, указанные в классе Movie , оцениваются для каждого объекта в списке. Следовательно, если мы передаем фильм с пустым именем в списке, проверка завершится ошибкой с сообщением:

Movie name cannot be empty.

4. Пользовательские валидаторы

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

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

@Constraint(validatedBy = MaxSizeConstraintValidator.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface MaxSizeConstraint {
String message() default "The input list cannot contain more than 4 movies.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

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

public class MaxSizeConstraintValidator implements ConstraintValidator<MaxSizeConstraint, List<Movie>> {
@Override
public boolean isValid(List<Movie> values, ConstraintValidatorContext context) {
return values.size() <= 4;
}
}

Наконец, мы добавим аннотацию @MaxSizeConstraint к нашему методу контроллера:

@PostMapping
public void addAll(
@RequestBody
@NotEmpty(message = "Input movie list cannot be empty.")
@MaxSizeConstraint
List<@Valid Movie> movies) {
movieService.addAll(movies);
}

Здесь @MaxSizeConstraint проверит размер ввода. Таким образом, если мы передаем более четырех объектов Movie во входном списке, проверка завершится ошибкой.

5. Обработка исключения

Если какая-либо из проверок не пройдена, создается ConstraintViolationException . Теперь давайте посмотрим, как мы можем добавить компонент обработки исключений для перехвата этого исключения.

@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity handle(ConstraintViolationException constraintViolationException) {
Set<ConstraintViolation<?>> violations = constraintViolationException.getConstraintViolations();
String errorMessage = "";
if (!violations.isEmpty()) {
StringBuilder builder = new StringBuilder();
violations.forEach(violation -> builder.append(" " + violation.getMessage()));
errorMessage = builder.toString();
} else {
errorMessage = "ConstraintViolationException occured.";
}
return new ResponseEntity<>(errorMessage, HttpStatus.BAD_REQUEST);
}

6. Тестирование API

Теперь мы проверим наш контроллер с допустимыми и недопустимыми входными данными.

Во-первых, давайте предоставим допустимые данные для API:

curl -v -d [{"name":"Movie1"}] -H "Content-Type: application/json" -X POST http://localhost:8080/movies

В этом сценарии мы получим ответ HTTP-статуса 200:

...
HTTP/1.1 200
...

Далее мы проверим ответ нашего API при передаче недопустимых входных данных.

Давайте попробуем пустой список:

curl -d [] -H "Content-Type: application/json" -X POST http://localhost:8080/movies

В этом сценарии мы получим ответ HTTP со статусом 400. Это связано с тем, что ввод не удовлетворяет ограничению @NotEmpty .

Input movie list cannot be empty.

Далее попробуем передать пять объектов Movie в списке:

curl -d [{"name":"Movie1"},{"name":"Movie2"},{"name":"Movie3"},{"name":"Movie4"},{"name":"Movie5"}] 
-H "Content-Type: application/json" -X POST http://localhost:8080/movies

Это также приведет к ответу со статусом HTTP 400, потому что мы не нарушаем ограничение @MaxSizeConstraint :

The input list cannot contain more than 4 movies.

7. Заключение

В этой быстрой статье мы узнали, как проверить список объектов в Spring.

Как всегда, полный исходный код примеров закончился на GitHub .