1. Introduction
1.绪论
Validating user inputs is a common requirement in any application. In this tutorial, we’ll go over ways to validate a List of objects as a parameter to a Spring controller.
在任何应用程序中,验证用户输入是一个常见的要求。在本教程中,我们将讨论如何验证一个List对象作为Spring控制器的参数。
We’ll add validation in the controller layer to ensure that the user-specified data satisfies the specified conditions.
我们将在控制器层添加验证,以确保用户指定的数据满足指定条件。
2. Adding Constraints to Fields
2.为字段添加约束条件
For our example, we’ll use a simple Spring controller that manages a database of movies. We’ll focus on a method that accepts a list of movies and adds them to the database after performing validations on the list.
在我们的例子中,我们将使用一个简单的Spring控制器来管理一个电影数据库。我们将关注一个方法,该方法接受一个电影列表,并在对该列表进行验证后将其添加到数据库中。
So, let’s start by adding constraints on the Movie class using javax validation:
因此,让我们首先使用javax验证在Movie类上添加约束。
public class Movie {
private String id;
@NotEmpty(message = "Movie name cannot be empty.")
private String name;
// standard setters and getters
}
3. Adding Validation Annotations in the Controller
3.在控制器中添加验证注解
Let’s look at our controller. First, we’ll add the @Validated annotation to the controller class:
让我们看一下我们的控制器。首先,我们将添加@Validated注解到控制器类。
@Validated
@RestController
@RequestMapping("/movies")
public class MovieController {
@Autowired
private MovieService movieService;
//...
}
Next, let’s write the controller method where we’ll validate the list of Movie objects passed in.
接下来,让我们编写控制器方法,在这里我们将验证传入的Movie对象的列表。
We’ll add the @NotEmpty annotation to our list of movies to validate that there should be at least one element in the list. At the same time, we’ll add the @Valid annotation to ensure that the Movie objects themselves are valid:
我们将为我们的电影列表添加@NotEmpty注解以验证列表中至少应该有一个元素。同时,我们将添加@Valid注解以确保Movie对象本身是有效的。
@PostMapping
public void addAll(
@RequestBody
@NotEmpty(message = "Input movie list cannot be empty.")
List<@Valid Movie> movies) {
movieService.addAll(movies);
}
If we call the controller method with an empty Movie list input, then the validation will fail because of the @NotEmpty annotation, and we’ll see the message:
如果我们用一个空的Movie列表输入来调用控制器方法,那么由于@NotEmpty注解,验证将失败,我们将看到这个消息。
Input movie list cannot be empty.
The @Valid annotation will make sure that the constraints specified in the Movie class are evaluated for each object in the list. Hence, if we pass a Movie with an empty name in the list, validation will fail with the message:
@Valid注解将确保Movie类中指定的约束条件对列表中的每个对象进行评估。因此,如果我们在列表中传递一个名字为空的Movie,验证就会失败,消息是。
Movie name cannot be empty.
4. Custom Validators
4.自定义验证器
We can also add custom constraint validators to the input list.
我们还可以将自定义约束验证器添加到输入列表。
For our example, the custom constraint will validate the condition that the input list size is restricted to a maximum of four elements. Let’s create this custom constraint annotation:
对于我们的例子,自定义约束将验证输入列表的大小被限制为最多四个元素的条件。让我们来创建这个自定义约束注解。
@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 {};
}
Now, we’ll create a validator that will apply the above constraint:
现在,我们将创建一个验证器,来应用上述约束。
public class MaxSizeConstraintValidator implements ConstraintValidator<MaxSizeConstraint, List<Movie>> {
@Override
public boolean isValid(List<Movie> values, ConstraintValidatorContext context) {
return values.size() <= 4;
}
}
Finally, we’ll add the @MaxSizeConstraint annotation to our controller method:
最后,我们将在控制器方法中添加@MaxSizeConstraint 注释。
@PostMapping
public void addAll(
@RequestBody
@NotEmpty(message = "Input movie list cannot be empty.")
@MaxSizeConstraint
List<@Valid Movie> movies) {
movieService.addAll(movies);
}
Here, @MaxSizeConstraint will validate the size of the input. So, if we pass more than four Movie objects in the input list, the validation will fail.
这里,@MaxSizeConstraint将验证输入的大小。因此,如果我们在输入列表中传递超过四个Movie对象,验证将失败。
5. Handling the Exception
5.处理异常情况
If any of the validations fail, ConstraintViolationException is thrown. Now, let’s see how we can add an exception handling component to catch this exception.
如果任何验证失败,ConstraintViolationException被抛出。现在,让我们看看如何添加一个exception handling组件来捕获这个异常。
@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. Testing the API
6.测试API
Now, we’ll test our controller with valid and invalid inputs.
现在,我们将用有效和无效的输入来测试我们的控制器。
Firstly, let’s provide valid input to the API:
首先,让我们向API提供有效的输入。
curl -v -d '[{"name":"Movie1"}]' -H "Content-Type: application/json" -X POST http://localhost:8080/movies
In this scenario, we’ll get an HTTP status 200 response:
在这种情况下,我们会得到一个HTTP状态200的响应。
...
HTTP/1.1 200
...
Next, we’ll check our API response when we pass invalid inputs.
接下来,我们将检查我们的API响应,当我们传递无效的输入。
Let’s try an empty list:
让我们试试一个空列表。
curl -d [] -H "Content-Type: application/json" -X POST http://localhost:8080/movies
In this scenario, we’ll get an HTTP status 400 response. This is because the input doesn’t satisfy the @NotEmpty constraint.
在这种情况下,我们会得到一个HTTP状态400的响应。这是因为输入不满足@NotEmpty的约束。
Input movie list cannot be empty.
Next, let’s try passing five Movie objects in the list:
接下来,让我们试着在列表中传递五个Movie对象。
curl -d '[{"name":"Movie1"},{"name":"Movie2"},{"name":"Movie3"},{"name":"Movie4"},{"name":"Movie5"}]'\
-H "Content-Type: application/json" -X POST http://localhost:8080/movie
This will also result in HTTP status 400 response because we fail the @MaxSizeConstraint constraint:
这也将导致HTTP状态400的响应,因为我们没有通过@MaxSizeConstraint约束。
The input list cannot contain more than 4 movies.
7. Conclusion
7.结语
In this quick article, we learned how to validate a list of objects in Spring.
在这篇快速文章中,我们学习了如何在Spring中验证一个对象的列表。
As always, the full source code of the examples is over on GitHub.
一如既往,这些例子的完整源代码在GitHub上。