别再乱用了,这才是 @Validated 和 @Valid 的真正区别和用法!

前言

在平时写接口的时候,需要进行参数的校验,如果参数少的话,使用if else还可以,但是参数多的时候,要写一大堆if else校验,敲的太累也不优雅。

所以今天将介绍使用注解来进行参数校验,既方便,还优雅。

关注公众号:臻大虾,分享更多java干货

@valid和@Validated区别

@Validation@Valid进行了二次封装

区别 @valid @validate
提供者 spring-boot-starter-web里面,springboot 项目自带 Spring 做得一个自定义注解,增强了分组功能
是否支持分组 不支持 支持,参数校验时,根据不同的分组采取不同的校验
使用位置 构造函数、方法、方法参数、成员属性 类、方法、方法参数,不能用于成员属性
嵌套校验 支持,因为可以在成员属性上使用 不支持

常用注解

  • 除了@Null,@ NotNull,@ NotBlank,@NotEmpty这四个外,其他所有的注解,传 null 时都会被当作有效处理
  • 注解常用参数值:message(校验不通过反馈的信息)
注解 验证的数据类型 备注
Null 任意类型 参数值必须是 Null
NotNull 任意类型 参数值必须不是 Null
NotBlank 只能作用于字符串 字符串不能为 null,而且字符串长度必须大于0,至少包含一个非空字符串
NotEmpty CharSequence Collection Map Array 参数值不能为null,且不能为空 (字符串长度必须大于0,空字符串(" ")可以通过校验)
Size(min,max ) CharSequence Collection Map Array 字符串:字符串长度必须在指定的范围内 Collection:集合大小必须在指定的范围内 Map:map的大小必须在指定的范围内 Array:数组长度必须在指定的范围内
Pattern(regexp) 字符串类型 验证字符串是否符合正则表达式
Min(value) 整型类型 参数值必须大于等于 最小值
Max(value) 整型类型 参数值必须小于等于 最大值
DecimalMin(value) 整型类型 参数值必须大于等于 最小值
DecimalMax(value) 整型类型 参数值必须小于等于 最大值
Positive 数字类型 参数值为正数
PositiveOrZero 数字类型 参数值为正数或0
Negative 数字类型 参数值为负数
NegativeOrZero 数字类型 参数值为负数或0
Digits(integer,fraction) 数字类型 参数值为数字,且最大长度不超过integer位,整数部分最高位不超过fraction位
AssertTrue 布尔类型 参数值必须为 true
AssertFalse 布尔类型 参数值必须为 false
Past 时间类型(Date) 参数值为时间,且必须小于 当前时间
PastOrPresent 时间类型(Date) 参数值为时间,且必须小于或等于 当前时间
Future 时间类型(Date) 参数值为时间,且必须大于 当前时间
FutureOrPresent 时间类型(Date) 参数值为时间,且必须大于或等于 当前日期
Email 字符串类型 被注释的元素必须是电子邮箱地址

校验场景

post请求校验

对象属性校验

  • 在入参对象的字段上添加校验注解,比如@Min
  • 在请求对象前面添加注解@Valid
less 复制代码
@Data
public class User {
    @Min(value = 10,message = "年龄必须大于10岁")
    private Integer age;
}
​
@PostMapping("checkBodyParam")
public String checkBodyParam(@RequestBody @Valid User user){
  return "ok";
}

当age=2时,校验不通过,提示年龄必须大于10岁

嵌套属性校验

  • 在嵌套对象上添加注解valid
  • 在请求对象前面添加注解valid
less 复制代码
@Data
public class UserClass {
    private String className;
    @Valid
    private User user;
}
​
@PostMapping("checkBodyMultilevelParam")
public String checkBodyMultilevelParam(@RequestBody @Valid UserClass userClass){
  return "ok";
}

当age=2时,校验不通过,提示年龄必须大于10岁

集合参数校验

  • 类上添加@Validated
  • 在请求对象前面添加注解@valid,用@validate没有效果
less 复制代码
@RestController
@RequestMapping("/paramTest")
@Validated
public class ParamTestController {
  @PostMapping("checkList")
  public String checkList(@RequestBody @Valid List<User> users) {
    return "ok";
  }
}

但是如果要分组校验呢,只能用validate,但是validate又没有效果,怎么办呢。

方法一:

新建对象,将list当做属性

缺点:这样修改的话,请求的参数结构就会改变.

方法二:

  • 实现list
  • 在list属性上添加valid注解

这样ValidList与java.util.List的对外功能完全一致,无需改变集合结构

typescript 复制代码
@Data
public class ValidList<E> implements List<E> {
​
    @Valid
    private List<E> list = new LinkedList<>();
    @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);
    }
}
​
  @PostMapping("checkValidList")
  public String checkValidList(@RequestBody @Valid ValidList<User> users) {
    return "ok";
  }

get请求参数校验

  • 在类上使用@Validated注解
  • 在参数前面添加参数校验的注解
less 复制代码
@RestController
@RequestMapping("/paramTest")
@Validated
public class ParamTestController {
  @GetMapping("checkParam")
  public String checkParam(@RequestParam  @Max(value = 99, message = "不能大于99岁") Integer age) {
    return "ok";
  }
  
  @GetMapping("checkPath/{id}")
  public String checkPath(@PathVariable  @Pattern(regexp = "^[0-9]*$", message = "id参数值必须是正整数") String id)   {
    return "ok";
  }
}
相关推荐
青梅主码12 小时前
麦肯锡最新发布报告《想打破生产力天花板吗?重新思考完成工作的方式》:与其一味调整组织结构,不如从根本上简化工作流程,释放更大价值
后端
Python私教12 小时前
源滚滚Rust全栈班v1.02 无符号整数详解
开发语言·后端·rust
绝无仅有12 小时前
面试总结之Nginx 经验常见问题汇总第二篇
后端·面试·github
这里有鱼汤13 小时前
分享7种常见的量化交易策略
后端
绝无仅有13 小时前
面试实战总结之Nginx配置经验第一篇
后端·面试·github
袁煦丞13 小时前
群晖NAS FTP远程文件仓库全球访问:cpolar内网穿透实验室第524个成功挑战
前端·程序员·远程工作
shark_chili13 小时前
CPU性能优化三剑客:分支预测、并行运算与超线程技术深度解析
后端
小蒜学长13 小时前
基于Spring Boot的火灾报警系统的设计与实现(代码+数据库+LW)
java·数据库·spring boot·后端
Victor35613 小时前
Redis(53)如何优化Redis的性能?
后端
武昌库里写JAVA13 小时前
基于Spring Boot + Vue3的办公用品申领管理系统
java·spring boot·后端