目录

前言

1. 依赖引入

2. 参数形式

3. 常用到的约束注解

4. 参数基础校验

4.1 @RequestBody参数

4.2 @RequestParam参数/@PathVariable参数

4.3 异常统一处理

5. 嵌套校验

6. 分组校验


前言

在后端的接口开发过程,实际上每一个接口都或多或少有不同规则的参数校验,有一些是基础校验,如非空校验、长度校验、大小校验、格式校验;也有一些校验是业务校验,如学号不能重重复、手机号不能重复注册等;对于业务校验,是需要和数据库交互才能知道校验结果;对于参数的基础校验,是有一些共有特征可以抽象出来,可以做成一个通用模板(java就是一种面向对象的编程语言,还记得天天快要说烂问烂的面向对象的三大特性吗?)。基于实际场景的需要,java API中定义了一些Bean校验的规范标准(JSR303:validation-api),但是没有具体实现,不过hibernate validation和spring validation都提供了一些比较优秀的实现。如果在项目里,你还是像类似这样的方式来进行参数校验就太low了,活该加班到天亮(当然如果你所在公司目前仍然用统计代码量来考核你的工作,就算我没说,你可以继续使用这种方式)。

@PostMapping("/add")
public String add(Student student) {if (null == student) {throw new RuntimeException("学生不为空");}if ("".equals(student.getStuCode())) {throw new RuntimeException("学号不能为空");}if ("".equals(student.getStuName())) {throw new RuntimeException("学生姓名不能为空");}if (null == student.getTeacher()) {throw new RuntimeException("学生的老师的不能为空");}if ("".equals(student.getTeacher().getTecName())) {throw new RuntimeException("学生的老师的姓名不能为空");}if ("".equals(student.getTeacher().getSubject())) {throw new RuntimeException("学生的老师的所授科目不为能空");}return "success";
}

1. 依赖引入

分享的这篇文章里的校验参数注解使用方法,我是在一个springboot项目里亲自重新测试验证过的,springboot的版本是2.3.9.RELEASE,另外也引入了关于参数校验的starter包,这样就不用额外去引关于参数校验的其他包了;

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId><version>2.3.9.RELEASE</version>
</dependency>

2. 参数形式

在java项目中,前端请求后端的接口中,常用的请求类型主要是post和get。

在post请求中,通常使用requestBody传递参数,即前端以json报文的格式传递到后端controller层,spring会把json报文自动映射到@RequestBody修饰的形参实例;

在get请求中,通常使用requestParam/PathVariable传递参数,其中requestParam是指前端以key-value的形式把参数传递到后端,spring会把参数自动映射到@RequestParam修饰的形参数实例对象(@RequestParam可以,也可以没有,只要参数key与controller层方法内形参类型的属性名称可以对应的上);@PathVariable是指spring可以将请求URL中占位符参数绑定到controller层方法的形参上;

3. 常用到的约束注解

@Null

被注释的元素必须为 null

@NotNull

被注释的元素必须不为 null

@AssertTrue

被注释的元素必须为 true

@AssertFalse

被注释的元素必须为 false

@Min(value)

被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@Max(value)

被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@DecimalMin(value)

被注释的元素必须是一个数字,其值必须大于等于指定的最小值

@DecimalMax(value)

被注释的元素必须是一个数字,其值必须小于等于指定的最大值

@Size(max, min)

被注释的元素的大小必须在指定的范围内

@Digits (integer, fraction)

被注释的元素必须是一个数字,其值必须在可接受的范围内

@Past

被注释的元素必须是一个过去的日期

@Future

被注释的元素必须是一个将来的日期

@Pattern(value)

被注释的元素必须符合指定的正则表达式

Hibernate Validator 附加的 constraint

注解

作用

@Email

被注释的元素必须是电子邮箱地址

@Length(min=, max=)

被注释的字符串的大小必须在指定的范围内

@NotEmpty

被注释的字符串的必须非空

@Range(min=, max=)

被注释的元素必须在合适的范围内

4. 参数基础校验

参数的基础校验,通常是指的非空、长度、最大值、最小值、格式(数字、邮箱、正则)等这些场景的校验。

4.1 @RequestBody参数

1.在controller层的方法的形参数前面加一个@Valid或@Validated的注解;

2.在用@RequestBody修饰的类的属性上加上约束注解,如@NotNull、@Length、@NotBlank;

3.@RequestBody参数在触发校验规则时,会抛出MethodArgumentNotValidException,这里使用统一的异常处理机制来处理异常;

总结:第1步的valid的作用就是一个标记,标明这个参数需要进行校验;第2步的约束注解的上注明校验的规则;第3步的统一校验机制是前后台请求后台接口时,如果校验参数的校验规则后会抛出异常,异常附带有约束注解上的提示信息,那么通过异常统一处理机制就可以统一处理异常信息,并以合适的方式返回给前台(所谓合适的方式是指异常信息的格式可以自行制定)。

@PostMapping("/add")
public Student add( @Valid@RequestBody Student student){System.out.println(student.getStuName());return student;
}
@Data
public class Student  {@NotNull(message = "学号不能为空")@Length(min = 2, max = 4, message = "学号的长度范围是(2,4)")private String stuCode;@NotNull(message = "姓名不能为空")@Length(min = 2, max = 3, message = "姓名的长度范围是(2,3)")private String stuName;
}

4.2 @RequestParam参数/@PathVariable参数

1.在controller层的控制类上添加@Validated注解;

2.在controller层方法的校验参数上添加约束注解,如@NotNull、@Pattern;

3.@RequestParam参数/@PathVariable参数在触发校验规则时,会抛出ConstraintViolationException类型的异常,所以在统一异常处理机制中添加对这种类型异常的处理机制;

@RestController
@RequestMapping("/student")
@Validated
public class StudentController {@GetMapping("/{sex}/info")public String getBySex(@PathVariable("sex") @Pattern(regexp = "boy||girl",message = "学生性别只能是boy或girl") String sex) {System.out.println("学生性别:" + sex);return "success";}@GetMapping("/getOne")public String getOne(@NotNull(message = "学生姓名不能为空") String stuName, @NotNull(message = "学生学号不能为空") String stuCode) {System.out.println("stuName:" + stuName + ",stuCode:" + stuCode);return "success";}
}

4.3 异常统一处理

@RestControllerAdvice
public class CommonExceptionHandler {/*** 用于捕获@RequestBody类型参数触发校验规则抛出的异常** @param e* @return*/@ExceptionHandler(value = MethodArgumentNotValidException.class)public String handleValidException(MethodArgumentNotValidException e) {StringBuilder sb = new StringBuilder();List<ObjectError> allErrors = e.getBindingResult().getAllErrors();if (!CollectionUtils.isEmpty(allErrors)) {for (ObjectError error : allErrors) {sb.append(error.getDefaultMessage()).append(";");}}return sb.toString();}/*** 用于捕获@RequestParam/@PathVariable参数触发校验规则抛出的异常** @param e* @return*/@ExceptionHandler(value = ConstraintViolationException.class)public String handleConstraintViolationException(ConstraintViolationException e) {StringBuilder sb = new StringBuilder();Set<ConstraintViolation<?>> conSet = e.getConstraintViolations();for (ConstraintViolation<?> con : conSet) {String message = con.getMessage();sb.append(message).append(";");}return sb.toString();}
}

5. 嵌套校验

在实际项目中有这样一种场景,用来接收参数的类的属性字段也是一个对象,属性对象的字段也需要进行必要的参数校验,这个时候可以使用嵌套校验来解决这个问题,hibernate-validator提供了具体的解决方式。

1.在controller层方法的形参数前添加@Validated注解,如果有分组校验的场景,则注明分组信息;如果校验不需要分组,可以不注明分组信息;

2.在接收参数的类的属性是对象的字段上添加@Valide注解,这里需要注意的是一定是@Valid,不是@Validated,因为@Valid的实现是由hibernate-validator提供,有嵌套校验的能力,而@Validated是由spring-validation提供的具体实现方式,@Validated有分组校验的能力,但是没有嵌套校验的能力;(java API规范(JSR303)定义了Bean的校验标准validation-api,但是没有具体的实现,所以各有各的实现,在功能上也是有区别的)

3.嵌套属性类上的约束注解的用法,与用来接收参数的对象属性上的约束注解的用法是一样的;

总结:@Valid的实现是由hibernate-validator提供,有嵌套校验的能力,但是没有分组校验的能力,@Validated是由spring-validation提供的具体实现方式,@Validated有分组校验的能力,但是没有嵌套校验的能力,在使用的过程须特别注意,要根据实际需要进行剪裁。

@PostMapping("/addStuaAndTeach")
public String addStuaAndTeach(@Validated(AddStuAndTeach.class) @RequestBody Student student){System.out.println("学生的工号:"+student.getStuCode()+",学生的老师的姓名:"+student.getTeacher().getTecName());return "success";
}
@Data
public class Student {@NotNull(message = "学生id不能为空",groups = QueryDetail.class)private Integer id;@NotNull(message = "学号不能为空",groups = AddStudent.class)@Length(min = 2, max = 4, message = "学号的长度范围是(2,4)")private String stuCode;@NotNull(message = "姓名不能为空",groups = AddStudent.class)@Length(min = 2, max = 3, message = "姓名的长度范围是(2,3)",groups = AddStudent.class)private String stuName;@Valid@NotNull(message = "学生的老师不能为空",groups = AddStuAndTeach.class)private Teacher teacher;
}
@Data
public class Teacher {@NotNull(message = "学生的老师姓名不能为空",groups = AddStuAndTeach.class)private String tecName;@NotNull(message = "学生的老师教授科目不能为空",groups = AddStuAndTeach.class)private String subject;
}
public interface AddStuAndTeach {
}

6. 分组校验

在实际的项目中,可能多个方法使用同一个类来接收参数,但是不同的方法的校验规则又是不同的,这个时候就可以使用分组校验的方式来解决这个问题了,spring-validation提供了具体的实现方式。

1.声明分组用的接口,比如添加和查询详情的时候,校验的规则肯定是不一样的,添加的时候一般不用传id,由后台自增长生成,查询详情的时候id是必须传的;

2.在controller层方法的校验参数上添加@Validated参数,同时注解里要注明校验参数的分组信息;

3.在校验参数的类上的线束注解上,也要注明校验参数的分组信息;

总结:在接口的入口方法参数上、校验参数上都注明了分组的信息,那么接口被用的时候,就可以根据不同的分组信息执行不同约束注解的校验逻辑了,这个能力是spring-validation提供的,所以这种场景下,controller层方法的上注解要用@Validated,@Valid注解没有这种能力。

//用于添加场景参数校验分组
public interface AddStudent {
}
//用于查询详情场景参数校验分组
public interface QueryDetail {
}
@PostMapping("/add")
public Student add(@Validated(AddStudent.class) @RequestBody Student student) {System.out.println(student.getStuName());return student;
}@PostMapping("/detail")
public String detail(@Validated(QueryDetail.class)@RequestBody Student student){System.out.println("学生id:"+student.getId());return "success";
}
@Data
public class Student {@NotNull(message = "学生id不能为空",groups = QueryDetail.class)private Integer id;@NotNull(message = "学号不能为空",groups = AddStudent.class)@Length(min = 2, max = 4, message = "学号的长度范围是(2,4)")private String stuCode;@NotNull(message = "姓名不能为空",groups = AddStudent.class)@Length(min = 2, max = 3, message = "姓名的长度范围是(2,3)",groups = AddStudent.class)private String stuName;

Springboot扩展点系列实现方式、工作原理集合:

Springboot扩展点之ApplicationContextInitializer

Springboot扩展点之BeanDefinitionRegistryPostProcessor

Springboot扩展点之BeanFactoryPostProcessor

Springboot扩展点之BeanPostProcessor

Springboot扩展点之InstantiationAwareBeanPostProcessor

Springboot扩展点之SmartInstantiationAwareBeanPostProcessor

Springboot扩展点之ApplicationContextAwareProcessor

Springboot扩展点之@PostConstruct

Springboot扩展点之InitializingBean

Springboot扩展点之DisposableBean

Springboot扩展点之SmartInitializingSingleton

Springboot核心功能工作原理:

Springboot实现调度任务的工作原理

Springboot事件监听机制的工作原理

Springboot优雅的参数校验(一)相关推荐

  1. springboot 优雅的参数校验_SpringBoot 2.x 开发案例之优雅的校验参数

    前言 参数如何校验?撸主很久很久之前的项目都是在前端页面一个个 if else 的,后来就用了一系列的前端校验框架,比如 layui iview 等等,几个样式属性就可以轻松搞定,的确是美滋滋. 后端 ...

  2. SpringBoot Validation优雅的参数校验

    前言:大多数项目中都需要后台对传过来的对象进行校验,所以经常需要写一些字段校验的代码,比如特殊字段非空.字段长度限制和邮箱格式验证等等.之前我们可能都是使用if-else-,写这些与业务逻辑关系不大的 ...

  3. postmapping注解参数说明_从零搭建后端框架:优雅的参数校验Validator

    前两天项目群里发生了关于参数校验的问题讨论,很多开发团队没有对这些做硬性规范时,还是有很多童鞋本着"不多事"的原则,产品文档里没有特别说明就不写.对于2B的产品经理来说,因为一次新 ...

  4. SpringBoot 如何进行参数校验,老鸟们都这么玩的!

    大家好,我是飘渺. 前几天写了一篇 SpringBoot如何统一后端返回格式?老鸟们都是这样玩的! 阅读效果还不错,而且被很多号主都转载过,今天我们继续第二篇,来聊聊在SprinBoot中如何集成参数 ...

  5. boot spring 对参数检测_【springboot】@Valid参数校验

    转自: https://blog.csdn.net/cp026la/article/details/86495659 扯淡: 刚开始写代码的时候对参数的校验要么不做.要么写很多类似 if( xx == ...

  6. SpringBoot 优雅的参数效验!

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

  7. Springboot中请求参数校验

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

  8. SpringBoot 实现统一参数校验

    一.业务需求 与第三方平台对接,第三方调用接口实现数据上报.由于接口传参较多,要对每一个参数做校验,如果写工具类对每个参数校验会很麻烦,因为,使用springboot自带的校验功能实现对参数的统一校验 ...

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

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

最新文章

  1. 新风向标:学术界开始从 Python 转向 Rust
  2. Java开发需掌握的常用Linux命令(持续更新)
  3. 【Android 逆向】整体加固脱壳 ( DEX 优化流程分析 | dvmDexFileOpenPartial | dexFileParse | 脱壳点 | 获取 dex 文件在内存中的首地址 )
  4. 数据结构排序法之插入法
  5. Python内置函数any()、map()组合运用案例一则
  6. JS小技巧 ----- 将类数组 / 字符串转为数组的几种方式
  7. linux的manual手册不存在,在 Linux 命令行下使用“原力”
  8. python调用指定浏览器打开网页
  9. 你真的要收下这份大礼包!!
  10. 363.矩形区域不超过K的最大数值和
  11. wxpython列表控件listctrl设置某行颜色_改变ListCtrl某行的背景色或者字体颜色
  12. “猜猜红桃A在哪里”——android小游戏(入门学习必备)
  13. DICOM医学图像处理:基于DCMTK工具包学习和分析worklist
  14. [管理新思维]社会化管理和开放式创新|裂变式创业
  15. css html文字淡入淡出,Css淡入淡出
  16. ctc center-loss在字符识别形近字分类中的使用
  17. IntelliJ IDEA 配置Jetty启动项目
  18. 中国移动大数据推进“精准扶贫”
  19. CCF系列题解--2017年12月第三题 Crontab
  20. 在linux下安装配置Initiator

热门文章

  1. 勘智K210人头人形模型操作步骤
  2. Matlab 7 (R14) 注册码
  3. 免费高清!N个无/少版权限制的大图特供网站
  4. Linux极速版学习!
  5. vi8超级版Android 6,vi8超级版怎么切换到安卓
  6. 成为FSD(全栈工程师)
  7. BCM-BCP-DRP-运维管理之故障管理——故障的分类与处理流程
  8. 怎样做一个更有魅力的人 (摘自 开复学生网)
  9. codeforces_652C. Foe Pairs
  10. 电子病历质控系列-三级医师质控