1. 引言
驗證用户輸入是任何應用程序中的常見需求。在本教程中,我們將介紹如何將一個包含 列表 的對象作為參數傳遞給 Spring 控制器進行驗證。
我們將為控制器層添加驗證,以確保用户提供的的數據滿足指定的條件。
2. 為字段添加約束
對於我們的示例,我們將使用一個簡單的 Spring 控制器,該控制器管理電影數據庫。我們將重點關注一個接受電影列表的方法,並在對列表執行驗證後將其添加到數據庫。
因此,我們首先應該 使用 javax validation 為 Movie 類添加約束。
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註解添加到我們的Movie對象列表中,以驗證列表中至少應包含一個元素。同時,我們還將@Valid註解添加到它以確保Movie對象本身有效。
@PostMapping
public void addAll(
@RequestBody
@NotEmpty(message = "Input movie list cannot be empty.")
List<@Valid Movie> movies) {
movieService.addAll(movies);
}
如果我們調用控制器方法,並傳入一個空Movie列表,那麼由於@NotEmpty註解,驗證將會失敗,我們將會看到以下消息:
Input movie list cannot be empty.
@Valid註解將會確保Movie類中指定的約束對於列表中的每個對象進行評估。因此,如果在列表中傳入一個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 發生了。";
}
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 約束。
電影列表不能為空。
接下來,讓我們嘗試在列表中傳遞五個 Movie 對象:
curl -d '[{"name":"Movie1"},{"name":"Movie2"},{"name":"Movie3"},{"name":"Movie4"},{"name":"Movie5"}]'\
-H "Content-Type: application/json" -X POST http://localhost:8080/movie
這將導致 HTTP 狀態碼 400 的響應,因為我們違反了 @MaxSizeConstraint 約束:
輸入列表不能包含超過 4 部電影。
7. 結論
在本文中,我們學習瞭如何驗證 Spring 中對象的列表。