场景
当使用Spring中接口的校验器校验Json
参数时,我们会把@NotNull
、@Range
等校验注解标注在对应实体类的属性之上。但是如果我们多个接口使用了这个实体类,可能会造成校验注解的干扰。
当然比较简单的方法是不同接口使用不同的实体类接收参数,但是有时像新增和删除接口可能就是id一个属性不一样,此时如果想使用注解校验参数并少写一个实体类的话可以使用参数分解校验。
定义分组接口
自定一个分组接口,具体的分组继承默认分组Default
,让不指定分组的校验属性规则也可以生效。
import javax.validation.groups.Default;
public interface SaveGroup extends Default {
interface Insert extends Default{
}
interface Update extends Default{
}
}
复制
使用分组校验
实体类指定分组
如果自定义的具体使用的分组接口没有继承Default
,那么实体类上未指定分组的校验不会生效。
没有继承Default
时实体类上指定分组时最好尽可能指定完整,否则校验处指定了分组但是校验注解上未指定分组时校验注解不会生效。
@Data
public class User{
@NotNull(message = "id不能为空", groups = SaveGroup.Insert.class)
private Long id;
@NotBlank
@NotNull(message = "name不能为空",groups = {SaveGroup.Insert.class, SaveGroup.Update.class})
private String name;
@Range(message = "age范围0-150", min = 0, max = 150) //分组未指定取决于自定分组是否继承Default分组
private Integer age;
private LocalDateTime createTime;
}
复制
Controller分组校验
API接口上使用@Validated
时指定对应的校验分组即可。此时在请求接口时,实体类上标注了Insert
和Update
分组的校验注解会分别生效。
@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
@PostMapping("/add")
public R<Object> insertUser(@RequestBody @Validated(SaveGroup.Insert.class) User user) {
userService.save(user);
return R.ok();
}
@PostMapping("/update")
public R<Object> updateUser(@RequestBody @Validated(SaveGroup.Update.class) User user) {
userService.updateById(user);
return R.ok();
}
}
复制
Service分组校验
有时可能会根据业务条件来进行区分校验,可以将分组校验的逻辑放在service层,根据不同的条件调用service层方法再触发校验。
- 在service的接口上使用
@Validated
- 在对应需要校验的方法上使用分组标识
@Validated(SaveGroup.Insert.class)
- 在对应需要校验的参数上标识
@Valid
@Validated
public interface UserService{
@Validated(SaveGroup.Insert.class)
void insertUser(@Valid User user);
@Validated(SaveGroup.Update.class)
void updateUser(@Valid User user);
}
复制
校验到非法参数时会打印ConstraintViolationException
,提示消息格式:methodName.paramName.fieldName: 具体的msg
自定义校验规则
自定义一个校验手机号的注解,定义完毕后就可以在属性中使用@Phone
来校验手机号
自定义注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = { PhoneValidator.class })
public @interface Phone {
String message() default "手机号码格式异常";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
复制
自定义校验器
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class PhoneValidator implements ConstraintValidator<Phone, String> {
private static final String REGEX = "^1[3456789]\\\\d{9}$";
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value != null) {
return value.matches(REGEX);
}
return true;
}
}
复制
最后修改时间:2023-12-12 17:24:08
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。