目录

  • 前言
  • `Controller` 中方法参数校验示例
    • 使用 `@Valid` 或 `@Validated` 注解
      • `Maven` 依赖
      • 实体类字段加上相关注解
      • `Controller` 方法参数加上 `@Valid` 或 `@Validated` 注解
        • 单个参数校验
        • 多个参数校验
      • 接口测试
        • 参数合法结果
        • `name` 字段为空的结果
        • 年龄不合法的结果
    • `@Validated` 注解特有的功能
      • 参数分组校验
        • 分组接口(空接口)
          • 实体类
        • `Controller` 控制类
        • 参数分组校验测试
          • 新增时传入参数 `id`
          • 更新时不传入参数 `id`
      • 嵌套校验
        • 实体类
        • `Controller` 控制类
        • 嵌套校验测试
          • `Teacher` 和 `Student` 都校验不通过
          • `Student` 都校验不通过
      • 控制分组校验顺序
  • 手动校验
    • 使用 `Hibernate Validation` 提供 `Validator`
    • 使用 `Spring Validation` 的 `Validator`
  • 参数校验常用注解

前言

数据的校验是网站一个不可或缺的功能,前端的 js 校验可以涵盖大部分的校验职责,如用户名唯一性,生日格式,邮箱格式校验等等常用的校验。但是为了避免用户绕过浏览器,使用 http 工具直接向后端请求一些违法数据,服务端的数据校验也是必要的

Controller 中方法参数校验示例

使用 @Valid@Validated 注解

Maven 依赖

  • @Valid:新版本的 springBoot 需要手动引入下面的依赖,老版本只需引入 spring-boot-starter-web 即可,里面集成了 Hibernate-Validator
<dependency><groupId>org.hibernate.validator</groupId><artifactId>hibernate-validator</artifactId><version>6.0.13.Final</version>
</dependency>
  • @Validated:是对 hibernate-validator 的封装,是 spring 提供的校验机制,只要引入 spring-context 依赖即可

实体类字段加上相关注解

public class User implements Serializable {@NotBlank(message = "姓名不能为空")private String name;@NotNull(message = "年龄不能为空")@Range(min = 0, max = 200, message = "年龄不合法")private Integer age;public User(String name, Integer age) {this.name = name;this.age = age;}// setter,getter 方法省略......
}
  • @NotBlank:只用于字符串,字符串不能为 null,并且去除两端空白字符后的长度大于 0,例:""," "
  • @NotEmpty:只用于字符串、集合、map、数组,且不能为 null,并且长度或者大小大于 1
  • @NotNull:适用于所有类型,且不能为 null
  • @AssertTrue:被注释的元素必须为 true
  • @AssertFalse:被注释的元素必须为 false
  • @Min(value):被注释的元素必须是一个数字,其值必须大于等于指定的最小值
  • @Max(value):被注释的元素必须是一个数字,其值必须小于等于指定的最大值
  • @Size(max,min):被注释的元素的大小必须在指定的范围内
  • @Email:被注释的元素必须是电子邮件地址
  • @Length:被注释的字符串的大小必须在指定的范围内
  • @Range:被注释的元素必须在合适的范围内

Controller 方法参数加上 @Valid@Validated 注解

单个参数校验

@Controller
public class UserController {@RequestMapping(path = "validatorUser", method = RequestMethod.POST)@ResponseBodypublic ResponseResult validatorUser(@Valid User user, BindingResult bindingResult) {if (bindingResult.hasErrors()) {// 用于获取相应字段上添加的 message 中的内容String message = bindingResult.getFieldError().getDefaultMessage();return new ResponseResult(500, message, null);}return new ResponseResult(200, "成功", user);}
}

多个参数校验

public Objet test(@Validated Object param1, BindingResult result1 ,@Validated Object param2, BindingResult Result2) {// ......
}

接口测试

参数合法结果

name 字段为空的结果

年龄不合法的结果

@Validated 注解特有的功能

@Valid 不具备的功能,而注解 @Validated 注解特有的功能。源码分别如下

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {Class<?>[] value() default {};
}@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
public @interface Valid {}

参数分组校验

当一个实体类需要多种验证方式时,例如:对于一个实体类的 id 来说,新增的时候是不需要的,对于更新时是必须的。可以通过 groups 对验证进行分组

分组接口(空接口)

通过向 groups 分配不同类的 class 对象,达到分组目的

public interface UserServiceInsert {}public interface UserServiceUpdate {}
实体类
public class UserInfo implements Serializable {@Null(message = "新增时id必须为空", groups = {UserServiceInsert.class})@NotNull(message = "更新时id不能为空", groups = {UserServiceUpdate.class})private Integer id;@NotBlank(message = "姓名不能为空")private String name;@NotNull(message = "年龄不能为空")@Range(min = 0, max = 200, message = "年龄不合法")private Integer age;public UserInfo(Integer id, String name, Integer age) {this.id = id;this.name = name;this.age = age;}// setter,getter 方法省略......
}

Controller 控制类

@Controller
public class UserController {@RequestMapping(path = "insertUser", method = RequestMethod.POST)@ResponseBodypublic ResponseResult insertUser(@Validated(value = UserServiceInsert.class) UserInfo userInfo, @NotNull BindingResult bindingResult) {if (bindingResult.hasErrors()) {String message = bindingResult.getFieldError().getDefaultMessage();return new ResponseResult(500, message, null);}return new ResponseResult(200, "成功", userInfo);}@RequestMapping(path = "updateUser", method = RequestMethod.POST)@ResponseBodypublic ResponseResult updateUser(@Validated(value = UserServiceUpdate.class) UserInfo userInfo, @NotNull BindingResult bindingResult) {if (bindingResult.hasErrors()) {String message = bindingResult.getFieldError().getDefaultMessage();return new ResponseResult(500, message, null);}return new ResponseResult(200, "成功", userInfo);}
}

参数分组校验测试

新增时传入参数 id

更新时不传入参数 id

  • @Validated 添加了 groups 属性时,其只会校验实体分组的属性。如只会校验 UserInfo 中的 id 属性,而不会校验 name,age 属性

嵌套校验

@Valid 加在方法参数时,不会自动进行嵌套验证,而是用在需要嵌套验证类内的相应字段上,来配合方法参数上 @Validated@Valid 来进行嵌套验证

实体类

public class Teacher implements Serializable {@NotEmpty(message = "Teacher 姓名不能为空")private String teacher_name;@NotNull(message = "Teacher 年龄不能为空")@Range(min = 0, max = 200, message = "Teacher 年龄不合法")private Integer teacher_age;@Valid@Size(min = 1, max = 10, message = "列表中的元素数量为1~10")private List<Student> students;public Teacher(String teacher_name, Integer teacher_age, List<Student> students) {this.teacher_name = teacher_name;this.teacher_age = teacher_age;this.students = students;}// setter,getter 方法省略......
}public class Student implements Serializable {@Valid@NotEmpty(message = "Student 姓名不能为空")private String name;@Valid@NotNull(message = "Student 年龄不能为空")@Range(min = 0, max = 200, message = "Student 年龄不合法")private Integer age;public Student(String name, Integer age) {this.age = age;this.name = name;}// setter,getter 方法省略......
}

Controller 控制类

@Controller
public class UserController {@RequestMapping(path = "nestValid", method = RequestMethod.POST)@ResponseBodypublic ResponseResult nestValid(@Validated @RequestBody Teacher teacher, @NotNull BindingResult bindingResult) {if (bindingResult.hasErrors()) {String message = bindingResult.getFieldError().getDefaultMessage();return new ResponseResult(500, message, null);}return new ResponseResult(200, "成功", teacher);}
}

嵌套校验测试

TeacherStudent 都校验不通过

Student 都校验不通过


控制分组校验顺序

@GroupSequence 它是 JSR 标准提供的注解,可以按指定的分组先后顺序进行验证;前面的分组校验不通过,后面的分组校验就不执行

  • 如:@GroupSequence({One.class, Two.class, Three.class}) 先执行 One 分组校验,然后执行 Two 分组校验。如果 One 分组校验失败了,则不会进行 Two 分组的校验。即必须第一个组校验正确了,才执行第二组校验

控制分组校验顺序示例:https://blog.csdn.net/qq877728715/article/details/113795082

手动校验

在某些场景下需要我们手动校验 bean,用校验器对需要被校验的 bean 发起 validate 获得校验结果

  • 既可以使用 Hibernate Validation 提供 Validator,也可以使用 Spring ValidationValidator

使用 Hibernate Validation 提供 Validator

public class ValidationTest {public static void main(String[] args) {Foo foo = new Foo();foo.setUsername(null);foo.setPassword(null);foo.setUserType("");// 构建ValidatorValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();Validator validator = validatorFactory.getValidator();// 使用Validator校验beanSet<ConstraintViolation<Foo>> set = validator.validate(foo);for (ConstraintViolation<Foo> constraintViolation : set) {System.out.println(constraintViolation.getMessage());}}@Datapublic static class Foo {@NotNull(message = "username不能为空")private String username;@NotNull(message = "password不能为空")private String password;@NotBlank(message = "userType不能为空")private String userType;}
}

使用 Spring ValidationValidator

@Component
@Configuration
public class GlobalWebConfig {@Beanpublic Validator validator() {return new LocalValidatorFactoryBean();}
}

如果使用 springBootLocalValidatorFactoryBean 已经成为了 Validator 的默认实现,使用时只需要自动注入即可

@Autowired
Validator globalValidator;

参数校验常用注解

注解 说明
@Null 限制只能为null
@NotNull 限制必须不为null
@NotEmpty 验证注解的元素值不为null且不为空字符串长度不为0、集合大小不为0)(主要用于:String,Collection,Map,array)
@NotBlank 只支持字符串类型字段,验证注解的元素值不为空不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串,且在比较时会去除字符串的空格
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间,(主要用于: String, Collection, Map and array)
@Range(min, max) 被注释的元素必须在合适的范围内 (主要用于 : BigDecimal, BigInteger, String, byte, short, int, long ,原始类型的包装类 )
@Length(min, max) 被注解的对象必须是字符串,大小必须在制定的范围内
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@Future 限制必须是一个将来的日期
@Past 验证注解的元素值(日期类型)比当前时间早
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

Spring实现Controller中方法参数校验相关推荐

  1. java注解返回不同消息,Spring MVC Controller中的一个读入和返回都是JSON的方法如何获取javax.validation注解的异常信息...

    Spring MVC Controller中的一个读入和返回都是JSON的方法怎么获取javax.validation注解的错误信息? 本帖最后由 LonelyCoder2012 于 2014-03- ...

  2. 使用 Spring Validation 优雅地进行参数校验

    引言 不知道大家平时的业务开发过程中 controller 层的参数校验都是怎么写的?是否也存在下面这样的直接判断? public String add(UserVO userVO) {if(user ...

  3. 头信息_如何在 Spring REST Controller 中获取 HTTP 头信息

    介绍 在本篇文章中,我们将研究如何在 Spring Rest Controller 中访问 HTTP 头信息. 首先,我们将使用 @RequestHeader 注解分别或同时读取 HTTP 头信息. ...

  4. python @classmethod 和 @staticmethod区别,以及类中方法参数cls和self的区别

    一.@classmethod 和 @staticmethod 1.staticmethod 作用:让类中的方法变成一个普通函数(普通函数没有绑定在任何一个特定的类或者实例上.所以与不需要对象实例化就可 ...

  5. Java中方法参数的传递

    Java中方法参数的传递: 众所周知,Java语言中只有值传递,看起来很好理解的一句话,那么来看一个例子: 输出结果: 这是一个经典问题,我想说说自己的理解: 首先,变量sa和sb分别包含一个字符串对 ...

  6. numpy中方法参数axis取值理解

    numpy中方法参数axis取值理解 首先不要使用什么横纵轴去理解,因为时间长了就忘记了,而且如果a是一个三维数组就没法解释了. axis等于0时,在shape中表示的是二维数组.那么np.amin( ...

  7. 中value大小_如何在Spring/SpringBoot 中做参数校验?你需要了解的都在这里!

    数据的校验的重要性就不用说了,即使在前端对数据进行校验的情况下,我们还是要对传入后端的数据再进行一遍校验,避免用户绕过浏览器直接通过一些 HTTP 工具直接向后端请求一些违法数据. 本文结合自己在项目 ...

  8. 面试官 | 如何在 Spring Boot 中进行参数校验?

    作者 | 狂乱的贵公子 来源 | cnblogs.com/cjsblog/p/8946768.html 开发过程中,后台的参数校验是必不可少的,所以经常会看到类似下面这样的代码 这样写并没有什么错,还 ...

  9. Springboot中请求参数校验

    1.添加依赖 <!-- 参数校验 --> <dependency><groupId>org.springframework.boot</groupId> ...

  10. Spring MVC Controller中返回json数据中文乱码处理

    问题 在使用spring MVC Controller的过程中,发现返回到客户端的的中文出现乱码.后台Java代码: @RequestMapping(value = "/upload&quo ...

最新文章

  1. 【驱动】内核打印级别设置
  2. “人脸识别”是一柄双刃剑 如何趋利避害?
  3. 大脑简史(2)-研究大脑的手段
  4. servlet config 初始化参数
  5. ROS Indigo下安装测试Xtion Pro
  6. linux条件表达式例子,Linux的Iptables命令的基本知识(三)-常用匹配条件示例和执行动作...
  7. 你认为手机会取代个人电脑吗?
  8. 求正整数N(N1)的质因数的个数,相同的质因数需要重复计算(java)
  9. linux文件测试操作
  10. PHP学习总结(4)——PHP入门篇之PHP计算表达式
  11. linux-unit1
  12. PHP专家陪练营试听课程下载
  13. 网络通讯协议——TCP/IP协议
  14. 世界各国1960年到2020年gdp数据抓取
  15. 自定义IDM的网页嗅探下载浮条样式
  16. 因为涉嫌歧视女性被开除的那位工程师到底在备忘录上写了什么?
  17. 万众瞩目--腾讯云数据库TDSQL第一届征文正式大赛开启
  18. 家装产业的数字化,正在成为越来越多人的新共识
  19. matlab中magy是什么意思,MATLAB入门基本知识——音频处理
  20. python 手机自动化交易股票_通达信转python,机智股票自动交易手机版

热门文章

  1. python3 读取文件夹的文件标题,提取小数,并计算数字和
  2. 【易实战】Spring Cloud Greenwich Ribbon:负载均衡的服务调用
  3. TypeError: 'list' object is not callable
  4. 深度学习笔记(二):简单神经网络,后向传播算法及实现
  5. 数据分析中会常犯哪些错误,如何解决? 五
  6. 基于IDEA使用Spark API开放Spark程序(1)
  7. 算法笔记-差分和前缀和
  8. 《Web漏洞防护》读书笔记——第6章,XXE防护
  9. window下开启mysql慢查询和分割慢查询日志
  10. Oracle 存储过程笔记.