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 .