我有一个 Spring REST API 端点定义如下:
@GetMapping("/books")
public List<Book> getBooks(
@RequestParam @NotNull Long id,
@RequestParam(required = false) String category) {
return libraryService.getBooks(id, category);
}
category
参数是可选的,但是当提供它时,我想确保它不为空或为空。
我尝试使用:
@RequestParam(required = false) @NotNull String category
因为我读到:https://stackoverflow.com/a/57818215/12769096,
@required = false
仅代表param本身的存在,而不代表其值。
这意味着它会验证 url 中是否存在“&category”,但不会继续检查分配给它的值,该值可以是有效的、null 或空的或其他任何值。
但是它引起了冲突,所以我删除了它,现在它运行了,显然没问题,但没有我想要的验证。
问题是,目前,请求如下:
https://library:8080/books?id=1234&category=
https://library:8080/books?id=1234&category=""
https://library:8080/books?id=1234&category
由于 category 值无效,所有结果都会导致 500 内部服务器错误。
我希望这些请求导致 400 Bad Request (或者由于不回答参数约束而引发的任何异常),因为类别参数存在但其值无效。 没有类别的请求应该仍然可以顺利通过,就像现在一样,因为它是可选的。
如何正确验证类别参数以实现此行为,而无需显式检查代码中的空字符串或空字符串,而是使用辅助 Spring 注释和工具?
您可以编写自定义验证器
@Constraint(validatedBy = NotEmptyIfPresentValidator.class)
@Target({ ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmptyIfPresent {
String message() default "Category must not be empty if present";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class NotEmptyIfPresentValidator implements ConstraintValidator<NotEmptyIfPresent, String> {
@Override
public void initialize(NotEmptyIfPresent constraintAnnotation) {
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
return value == null || !value.trim().isEmpty();
}
}
//controller
@GetMapping("/books")
public List<Book> getBooks(
@RequestParam @NotNull Long id,
@RequestParam(required = false) @NotEmptyIfPresent String category) {
return libraryService.getBooks(id, category);
}
确保使用
@Validated
注释你的控制器