当前位置:首页 > 科技  > 软件

优雅的springboot参数校验,你学会了吗?

来源: 责编: 时间:2023-11-30 09:30:18 366观看
导读前言在后端的接口开发过程,实际上每一个接口都或多或少有不同规则的参数校验,有一些是基础校验,如非空校验、长度校验、大小校验、格式校验;也有一些校验是业务校验,如学号不能重重复、手机号不能重复注册等;对于业务校验,是

前言

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

@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";}

依赖引入

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

<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>

参数形式

在java项目中,前端请求后端的接口中,常用的请求类型主要是post和get。Tal28资讯网——每日最新资讯28at.com

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

常用到的约束注解

@ValidTal28资讯网——每日最新资讯28at.com

被注释的元素是一个对象,需要检查此对象的所有字段值Tal28资讯网——每日最新资讯28at.com

@NullTal28资讯网——每日最新资讯28at.com

被注释的元素必须为 nullTal28资讯网——每日最新资讯28at.com

@NotNullTal28资讯网——每日最新资讯28at.com

被注释的元素必须不为 nullTal28资讯网——每日最新资讯28at.com

@AssertTrueTal28资讯网——每日最新资讯28at.com

被注释的元素必须为 trueTal28资讯网——每日最新资讯28at.com

@AssertFalseTal28资讯网——每日最新资讯28at.com

被注释的元素必须为 falseTal28资讯网——每日最新资讯28at.com

@Min(value)Tal28资讯网——每日最新资讯28at.com

被注释的元素必须是一个数字,其值必须大于等于指定的最小值Tal28资讯网——每日最新资讯28at.com

@Max(value)Tal28资讯网——每日最新资讯28at.com

被注释的元素必须是一个数字,其值必须小于等于指定的最大值Tal28资讯网——每日最新资讯28at.com

@DecimalMin(value)Tal28资讯网——每日最新资讯28at.com

被注释的元素必须是一个数字,其值必须大于等于指定的最小值Tal28资讯网——每日最新资讯28at.com

@DecimalMax(value)Tal28资讯网——每日最新资讯28at.com

被注释的元素必须是一个数字,其值必须小于等于指定的最大值Tal28资讯网——每日最新资讯28at.com

@Size(max, min)Tal28资讯网——每日最新资讯28at.com

被注释的元素的大小必须在指定的范围内Tal28资讯网——每日最新资讯28at.com

@Digits (integer, fraction)Tal28资讯网——每日最新资讯28at.com

被注释的元素必须是一个数字,其值必须在可接受的范围内Tal28资讯网——每日最新资讯28at.com

@PastTal28资讯网——每日最新资讯28at.com

被注释的元素必须是一个过去的日期Tal28资讯网——每日最新资讯28at.com

@FutureTal28资讯网——每日最新资讯28at.com

被注释的元素必须是一个将来的日期Tal28资讯网——每日最新资讯28at.com

@Pattern(value)Tal28资讯网——每日最新资讯28at.com

被注释的元素必须符合指定的正则表达式Tal28资讯网——每日最新资讯28at.com

Hibernate Validator 附加的 constraintTal28资讯网——每日最新资讯28at.com

注解Tal28资讯网——每日最新资讯28at.com

作用Tal28资讯网——每日最新资讯28at.com

@EmailTal28资讯网——每日最新资讯28at.com

被注释的元素必须是电子邮箱地址Tal28资讯网——每日最新资讯28at.com

@Length(min=, max=)Tal28资讯网——每日最新资讯28at.com

被注释的字符串的大小必须在指定的范围内Tal28资讯网——每日最新资讯28at.com

@NotEmptyTal28资讯网——每日最新资讯28at.com

被注释的字符串的必须非空Tal28资讯网——每日最新资讯28at.com

@Range(min=, max=)Tal28资讯网——每日最新资讯28at.com

被注释的元素必须在合适的范围内Tal28资讯网——每日最新资讯28at.com

@NotBlankTal28资讯网——每日最新资讯28at.com

被注释的字符串的必须非空Tal28资讯网——每日最新资讯28at.com

@URL(protocol=,Tal28资讯网——每日最新资讯28at.com

host=,    port=, Tal28资讯网——每日最新资讯28at.com

regexp=, flags=)Tal28资讯网——每日最新资讯28at.com

被注释的字符串必须是一个有效的urlTal28资讯网——每日最新资讯28at.com

@CreditCardNumberTal28资讯网——每日最新资讯28at.com

被注释的字符串必须通过Luhn校验算法,Tal28资讯网——每日最新资讯28at.com

银行卡,信用卡等号码一般都用LuhnTal28资讯网——每日最新资讯28at.com

计算合法性Tal28资讯网——每日最新资讯28at.com

@ScriptAssertTal28资讯网——每日最新资讯28at.com

(lang=, script=, alias=)Tal28资讯网——每日最新资讯28at.com

要有Java Scripting API 即JSR 223 Tal28资讯网——每日最新资讯28at.com

("Scripting for the JavaTM Platform")的实现Tal28资讯网——每日最新资讯28at.com

@SafeHtmlTal28资讯网——每日最新资讯28at.com

(whitelistType=, Tal28资讯网——每日最新资讯28at.com

additionalTags=)Tal28资讯网——每日最新资讯28at.com

classpath中要有jsoup包Tal28资讯网——每日最新资讯28at.com

参数基础校验

参数的基础校验,通常是指的非空、长度、最大值、最小值、格式(数字、邮箱、正则)等这些场景的校验。Tal28资讯网——每日最新资讯28at.com

@RequestBody参数

1.在controller层的方法的形参数前面加一个@Valid或@Validated的注解;Tal28资讯网——每日最新资讯28at.com

2.在用@RequestBody修饰的类的属性上加上约束注解,如@NotNull、@Length、@NotBlank;Tal28资讯网——每日最新资讯28at.com

3.@RequestBody参数在触发校验规则时,会抛出MethodArgumentNotValidException,这里使用统一的异常处理机制来处理异常;Tal28资讯网——每日最新资讯28at.com

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

@PostMapping("/add")public Student add( @Valid@RequestBody Student student){    System.out.println(student.getStuName());    return student;}@Datapublic 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;}

@RequestParam参数/@PathVariable参数Tal28资讯网——每日最新资讯28at.com

1.在controller层的控制类上添加@Validated注解;Tal28资讯网——每日最新资讯28at.com

2.在controller层方法的校验参数上添加约束注解,如@NotNull、@Pattern;Tal28资讯网——每日最新资讯28at.com

3.@RequestParam参数/@PathVariable参数在触发校验规则时,会抛出ConstraintViolationException类型的异常,所以在统一异常处理机制中添加对这种类型异常的处理机制;Tal28资讯网——每日最新资讯28at.com

@RestController@RequestMapping("/student")@Validatedpublic 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";    }}

异常统一处理

@RestControllerAdvicepublic 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();    }}

嵌套校验

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

1.在controller层方法的形参数前添加@Validated注解,如果有分组校验的场景,则注明分组信息;如果校验不需要分组,可以不注明分组信息;Tal28资讯网——每日最新资讯28at.com

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

3.嵌套属性类上的约束注解的用法,与用来接收参数的对象属性上的约束注解的用法是一样的;Tal28资讯网——每日最新资讯28at.com

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

@PostMapping("/addStuaAndTeach")public String addStuaAndTeach(@Validated(AddStuAndTeach.class) @RequestBody Student student){    System.out.println("学生的工号:"+student.getStuCode()+",学生的老师的姓名:"+student.getTeacher().getTecName());    return "success";}
@Datapublic class Teacher {    @NotNull(message = "学生的老师姓名不能为空",groups = AddStuAndTeach.class)    private String tecName;    @NotNull(message = "学生的老师教授科目不能为空",groups = AddStuAndTeach.class)    private String subject;}public interface AddStuAndTeach {}
@Datapublic 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;}

分组校验

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

1.声明分组用的接口,比如添加和查询详情的时候,校验的规则肯定是不一样的,添加的时候一般不用传id,由后台自增长生成,查询详情的时候id是必须传的;Tal28资讯网——每日最新资讯28at.com

2.在controller层方法的校验参数上添加@Validated参数,同时注解里要注明校验参数的分组信息;Tal28资讯网——每日最新资讯28at.com

3.在校验参数的类上的线束注解上,也要注明校验参数的分组信息;Tal28资讯网——每日最新资讯28at.com

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

//用于添加场景参数校验分组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";}
@Datapublic 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;    }


Tal28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-35335-0.html优雅的springboot参数校验,你学会了吗?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: Solid 作者从 React 中学到最重要的是什么?

下一篇: 我们一起聊聊Python协程和异步编程

标签:
  • 热门焦点
  • 6月iOS设备性能榜:M2稳居榜首 A系列只能等一手3nm来救

    没有新品发布,自然iOS设备性能榜的上榜设备就没有什么更替,仅仅只有跑分变化而产生的排名变动,毕竟苹果新品的发布节奏就是这样的,一年下来也就几个移动端新品,不会像安卓厂商,一
  • 5月iOS设备性能榜:M1 M2依旧是榜单前五

    和上个月一样,没有新品发布的iOS设备性能榜的上榜设备并没有什么更替,仅仅只有跑分变化而产生的排名变动,刚刚开始的苹果WWDC2023,推出的产品也依旧是新款Mac Pro、新款Mac Stu
  • 分享六款相见恨晚的PPT模版网站, 祝你做出精美的PPT!

    1、OfficePLUSOfficePLUS网站旨在为全球Office用户提供丰富的高品质原创PPT模板、实用文档、数据图表及个性化定制服务。优点:OfficePLUS是微软官方网站,囊括PPT模板、Word模
  • 微信语音大揭秘:为什么禁止转发?

    大家好,我是你们的小米。今天,我要和大家聊一个有趣的话题:为什么微信语音不可以转发?这是一个我们经常在日常使用中遇到的问题,也是一个让很多人好奇的问题。让我们一起来揭开这
  • 虚拟键盘 API 的妙用

    你是否在遇到过这样的问题:移动设备上有一个固定元素,当激活虚拟键盘时,该元素被隐藏在了键盘下方?多年来,这一直是 Web 上的默认行为,在本文中,我们将探讨这个问题、为什么会发生
  • 为什么你不应该使用Div作为可点击元素

    按钮是为任何网络应用程序提供交互性的最常见方式。但我们经常倾向于使用其他HTML元素,如 div span 等作为 clickable 元素。但通过这样做,我们错过了许多内置浏览器的功能。
  • 腾讯VS网易,最卷游戏暑期档,谁能笑到最后?

    作者:无锈钵来源:财经无忌7月16日晚,上海1862时尚艺术中心。伴随着幻象的精准命中,硕大的荧幕之上,比分被定格在了14:12,被寄予厚望的EDG战队以绝对的优势战胜了BLG战队,拿下了总决
  • 一条抖音4亿人围观 ! 这家MCN比无忧传媒还野

    作者:Hiu 来源:互联网品牌官01 擦边少女空降热搜,幕后推手曝光被网友誉为&ldquo;纯欲天花板&rdquo;的女网红井川里予,近期因为一组哥特风照片登上热搜,引发了一场互联网世界关于
  • 小米MIX Fold 3配置细节曝光:搭载领先版骁龙8 Gen2+罕见5倍长焦

    这段时间以来,包括三星、一加、荣耀等等有不少品牌旗下的最新折叠屏旗舰都得到了不少爆料,而小米新一代折叠屏旗舰——小米MIX Fold 3此前也屡屡被传
Top