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 .