1. введение
Проверка вводимых пользователем данных является общим требованием в любом приложении. В этом уроке мы рассмотрим способы проверки списка объектов в качестве параметра для контроллера Spring .
Мы добавим проверку на уровне контроллера, чтобы убедиться, что указанные пользователем данные удовлетворяют указанным условиям.
2. Добавление ограничений к компоненту
В нашем примере мы будем использовать простой контроллер Spring, который управляет базой данных фильмов. Мы сосредоточимся на методе, который принимает список фильмов и добавляет их в базу данных после выполнения проверки списка.
Итак, давайте начнем с добавления ограничений на фильм боб с использованием проверки 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); }
Если мы вызовем метод контроллера с пустым входом Movie list, то проверка завершится неудачей из-за аннотации @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> { @Override public boolean isValid(List 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> 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 status 200:
... HTTP/1.1 200 ...
Затем мы проверим наш ответ API, когда мы передадим недопустимые входные данные.
Давайте попробуем пустой список:
curl -d [] -H "Content-Type: application/json" -X POST http://localhost:8080/movies
В этом сценарии мы получим ответ HTTP status 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 status 400, поскольку мы не выполняем ограничение @MaxSizeConstraint :
The input list cannot contain more than 4 movies.
7. Заключение
В этой краткой статье мы узнали, как проверить список объектов весной.
Как всегда, полный исходный код примеров находится на GitHub .