自定义注解实现参数校验
末尾有常用约束注解
一、自定义验证注解的好处
- 验证逻辑和业务逻辑分离
- 验证逻辑的复用
二、步骤
- 自定义注解,指定验证器
- 实现验证器
这里我们实现一个注解来验证参数是否为true或者false
首先,自定义注解 @BooleanCheck
@Target({ElementType.FIELD}) // 作用范围:字段
@Retention(RetentionPolicy.RUNTIME) // 最长生命周期:运行时保留
@Constraint(validatedBy = BooleanCheckValidator.class) // 表示这个注解是一个验证注解,并且指定了一个实现验证逻辑的验证器
@Documented
public @interface BooleanCheck {
String message() default "err: strict must be true or false or not set"; // 参数,指明了验证失败后返回的消息
// groups()和payload()也为@Constraint要求,可默认为空
Class<?>[] groups() default {}; // 分组校验,不同的场景下有不同的验证逻辑,比如创建方法参数不能为空,更新方法参数可以为空
Class<? extends Payload>[] payload() default {}; // 暂不清楚作用
}
第二步,创建验证器实现验证逻辑
/**
* 验证器
*/
public class BooleanCheckValidator implements ConstraintValidator<BooleanCheck, String> {
/**
* 在参数验证开始前调用注解里的方法,从而获取到一些注解里的参数
*
* @param constraintAnnotation 自定义的注解
*/
@Override
public void initialize(BooleanCheck constraintAnnotation) {
ConstraintValidator.super.initialize(constraintAnnotation);
}
/**
* 验证器验证逻辑
*
* @param strict 需要验证的参数
* @param constraintValidatorContext
* @return 返回验证结果
*/
@Override
public boolean isValid(String strict, ConstraintValidatorContext constraintValidatorContext) {
return strict.equals("true") || strict.equals("false");
}
}
第三步,使用注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class People {
private String name;
@BooleanCheck
private String strict;
}
第四步,开启验证,需要在验证的地方加上@Valid注解
@RestController
@RequestMapping("/hello")
public class TestController {
/**
* controller
*
* @param list People集合对象
* @param validRes 接收验证结果
* @return
*/
@PostMapping("/test")
public String test(@Valid @RequestBody ValidList<People> list, BindingResult validRes) {
if (validRes.hasErrors()) {
// 返回自定义的验证失败信息
return validRes.getAllErrors().get(0).getDefaultMessage();
}
return "OK!";
}
}
第五步,@Valid只能验证单个实体类,对List集合不生效,需要我们自己定义个ValidList类实现List的方法,并使用自定义ValidList替换List的使用
/**
* 校验List中字段属性
*
* @param <E>
*/
@Data
public class ValidList<E> implements List<E> {
@Valid
private List<E> list = new ArrayList<>();
@Override
public int size() {
return list.size();
}
@Override
public boolean isEmpty() {
return list.isEmpty();
}
@Override
public boolean contains(Object o) {
return list.contains(o);
}
@Override
public Iterator<E> iterator() {
return list.iterator();
}
@Override
public Object[] toArray() {
return list.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return list.toArray(a);
}
@Override
public boolean add(E e) {
return list.add(e);
}
@Override
public boolean remove(Object o) {
return list.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return list.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) {
return list.addAll(c);
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
return list.addAll(index, c);
}
@Override
public boolean removeAll(Collection<?> c) {
return list.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return list.retainAll(c);
}
@Override
public void clear() {
list.clear();
}
@Override
public E get(int index) {
return list.get(index);
}
@Override
public E set(int index, E element) {
return list.set(index, element);
}
@Override
public void add(int index, E element) {
list.add(index, element);
}
@Override
public E remove(int index) {
return list.remove(index);
}
@Override
public int indexOf(Object o) {
return list.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return list.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return list.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
return list.listIterator(index);
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return list.subList(fromIndex, toIndex);
}
}
第六步,Postman发送请求验证
数据正确
数据失败
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了