springboot如何校验参数
- 后端
- 阿Qoder
- 0
前言
在日常开发中,我们少不了需要对前端的请求参数的验证。Spring提供了多种方法来实现请求参数的验证。我们一起了解一下吧。
注解
设置依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
注解
以下是 validation-api中提供的可用的注解列表
以上大致就是validation-api默认提供的参数验证注解。
另外需要注意的是,在每个注解中基本上都一个分组属性:Class<?>[] groups() default { };
其作用就是对对象属性分组,用于在不同的场景下支持不同的参数验证。我们来举一个列子:
比如我们新增和更新数据的操作一般都用同一个对象来接收前端传入参数。那么新增时的Id可能为空,而编辑时的Id不能为空,我们对参数的验证规则是不一样的。那么怎么实现呢?这里就需要用到我们的groups()了。代码如下:
@RequestMapping("create")
@ResponseBody
public String create(@RequestBody @Validated(Create.class) User user) {
return "create success";
}
@RequestMapping("update")
@ResponseBody
public String update(@RequestBody @Validated(Update.class) User user) {
return "update success";
}
@Data
public static class User {
@NotBlank(message = "id不能为空", groups = {Update.class})
private String id;
@NotNull(message = "用户名不能为空", groups = {Create.class, Update.class})
private String username;
@NotNull(message = "密码不能为空")
private String password;
}
public interface Create {
}
public interface Update {
}
根据需求,我们在 User 的 id 属性上标记上 groups = {Update.class}
,在 username 属性上标记 groups = {Create.class, Update.class}
。则表明我们对id只在 @Validated(Update.class)
时验证id的值;username 则在 @Validated(Update.class)
或者 @Validated(Create.class)
时都需要验证。
自定义验证
现在我们来实现一个怎么验证枚举的数据是否合规。
首先,定义一个自定义注解,例如 @ValidEnum:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = ValidEnumValidator.class)
public @interface ValidEnum {
String message() default "无效的枚举值";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> value();
}
@ValidEnum 注解用于验证一个枚举类型的值是否在指定的枚举类型中,使用 ValidEnumValidator 类对其进行验证。
接下来,定义一个 ValidEnumValidator 类,实现对 @ValidEnum 注解的验证逻辑:
public class ValidEnumValidator implements ConstraintValidator<ValidEnum, Object> {
private Set<String> validValues = new HashSet<>();
@Override
public void initialize(ValidEnum constraintAnnotation) {
Class<? extends Enum<?>> enumClass = constraintAnnotation.value();
Enum<?>[] enumValues = enumClass.getEnumConstants();
for (Enum<?> enumValue : enumValues) {
validValues.add(enumValue.name());
}
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
if (value == null) {
return true;
}
return validValues.contains(value.toString());
}
}
ValidEnumValidator 类实现了 ConstraintValidator 接口,并重写了 initialize() 和 isValid() 两个方法。initialize() 方法用于初始化验证器,获取枚举类型的所有枚举值;isValid() 方法用于实现验证逻辑,判断枚举值是否在指定的枚举类型中。
最后,在使用 @Validated 注解的 Controller 中,对请求参数使用自定义的 @ValidEnum 注解进行验证
@RestController
@Validated
public class UserController {
@GetMapping("/user")
public void getUser(@RequestParam @ValidEnum(value = Gender.class) String gender) {
// 处理请求
}
}
@ValidEnum 注解用于验证 gender 参数是否在 Gender 枚举类型中。如果 gender 参数的值不在 Gender 枚举类型中,则会抛出 ConstraintViolationException 异常,并带有指定的错误消息。
需要注意的是,自定义的 Bean Validation 注解需要使用 @Constraint 注解进行标注,并指定对应的验证器类。
在验证器类中,需要实现 ConstraintValidator 接口,并实现 initialize() 和 isValid() 方法。在使用自定义注解进行参数验证时,需要在对应的 Controller 中使用 @Validated 注解进行标注。
大家可以看到spring-boot-starter-validation 中依赖的包是 jakarta.validation-api,其命名空间属于jakarta。jakarta.validation-api 实现的规范依旧是JSR380,熟悉的小伙伴可能知道其实以前用的是 javax.validation-api。可是为什么现在会是jakarta.validation-api 呢,而不是 javax.validation-api?这中间其实涉及到了太多的商业上的博弈。有兴趣的大家可以自己去了解下,有时间单独出一篇介绍。
免责申明:本站发布的内容(图片、视频和文字)以转载和分享为主,文章观点不代表本站立场,如涉及侵权请联系站长邮箱:xbc-online@qq.com进行反馈,一经查实,将立刻删除涉嫌侵权内容。