介绍

几乎每个web网站都会对用户提交的参数进行校验,前端要做,后端也要做。防止用户直接通过接口调用的方式来请求或保存数据,从而导致产生脏数据等其他严重的后果。

因为有些校验的逻辑也很繁琐,为了减轻开发者的负担,Java发布了 JSR303/JSR-349数据校验规范

JSR303 是一项标准,JSR-349 是其的升级版本,添加了一些新特性,他们规定一些校验规范即校验注解,如 @Null,@NotNull,@Pattern,他们位于 javax.validation.constraints 包下,只提供规范不提供实现。

而 hibernate validation 是对这个规范的实践(不要将 hibernate 和数据库 orm 框架联系在一起),他提供了相应的实现,并增加了一些其他校验注解,如 @Length,@Range 等等,他们位于 org.hibernate.validator.constraints 包下。

而万能的 spring 为了给开发者提供便捷,对 hibernate validation 进行了二次封装,显示校验 validated bean 时,你可以使用 spring validation 或者 hibernate validation,而 spring validation 另一个特性,便是其在 springmvc 模块中添加了自动校验,并将校验信息封装进了特定的类中。这无疑便捷了我们的 web 开发

在spring boot项目中只要加入如下依赖即可使用校验注解

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>

查看子依赖会发现有如下依赖

<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-validator</artifactId>
</dependency>

JSR提供的部分校验注解如下

注解 解释
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Pattern 被注释的元素必须符合指定的正则表达式
@Email 被注释的元素必须是电子邮箱地址

经常被搞混的3个注解

注解 解释
@NotNull 不能为null,但可以为empty
@NotEmpty 不能为null,而且长度必须大于0
@NotBlank 只能作用在String上,不能为null,而且调用trim()后,长度必须大于0

我来举一个org.apache.commons.lang3.StringUtils中的例子,你就能理解NotBlank的意思了,如下断言都能测试通过

assertEquals(true, StringUtils.isBlank(null));
assertEquals(true, StringUtils.isBlank(""));
// 空格
assertEquals(true, StringUtils.isBlank(" "));
// 回车
assertEquals(true, StringUtils.isBlank("    "));

改造一个注册的接口

先定义一下状态枚举类

public enum ResponseCode {SUCCESS(0, "成功"),ERROR(1, "失败"),ILLEGAL_ARGUMENT(2, "参数错误"),EMPTY_RESULT(3, "结果为空"),NEED_LOGIN(10, "需要登录");private final int code;private final String desc;ResponseCode(int code, String desc) {this.code = code;this.desc = desc;}public int getCode() {return code;}public String getDesc() {return desc;}
}

定义项目的返回对象

@Data
/** 注解的作用是序列化json时,如果是null对象,key也会消失 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ServerResponse implements Serializable {/** 状态值 **/private int status;/** 描述 **/private String msg;/** 数据 **/private Object data;public ServerResponse(int status, String msg) {this.status = status;this.msg = msg;}public static ServerResponse success() {return new ServerResponse(ResponseCode.SUCCESS.getCode(), ResponseCode.SUCCESS.getDesc());}public static ServerResponse illegalArgument(String msg) {return new ServerResponse(ResponseCode.ILLEGAL_ARGUMENT.getCode(), msg);}
}

注册接口,这里省略了一部分校验

@RequestMapping("regist")
public ServerResponse regist(@RequestParam("name") String name,@RequestParam("phone") String phone,@RequestParam("phone") String email) {if (StringUtils.isBlank(name)) {return ServerResponse.illegalArgument("用户名不能为空");}// 其他一堆校验过程,调用servicereturn ServerResponse.success();
}

当不满足条件时返回如下

{"status": 2,"msg": "用户名不能为空"
}

当参数较多,校验的逻辑也越来越多,这时可以直接将前端传过来参数直接转为对象

@Data
public class Student {@NotBlank(message = "用户名不能为空")private String name;@NotBlank(message = "手机号不能为空")@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "手机号码格式错误")private String phone;@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式错误")private String email;
}

@RequestMapping("regist")
public ServerResponse regist(@Valid Student student, BindingResult bindingResult) {if (bindingResult.hasErrors()) {List<FieldError> errorList = bindingResult.getFieldErrors();// list不为空if (CollectionUtils.isNotEmpty(errorList)) {return ServerResponse.illegalArgument(errorList.get(0).getDefaultMessage());}}// 调用servicereturn ServerResponse.success();
}

代码将不满足条件的字段的描述取一个出来返回,类似如下。当都满足时才会返回成功

{"status": 2,"msg": "用户名不能为空"
}

需要注意的地方如下

参数 Student 前需要加上@Valid或@Validated 注解(下文说这2个注解的区别),表明需要 spring 对其进行校验,而校验的信息会存放到其后的 BindingResult 中。注意,必须相邻,如果有多个参数需要校验,形式可以如下。foo(@Validated Student student, BindingResult studentBindingResult ,@Validated Bar bar, BindingResult barBindingResult); 即一个校验类对应一个校验结果。

@Validated比@Valid的功能更强大

@Validated比@Valid的功能更强大,主要体现在@Validated可以进行分组校验和嵌套校验。

假如我们还要求学生填写父亲和母亲的名字(并且不能为空),而后端的设计中父亲和母亲的名字被放在另一个类Relation中,这就要求我们能进行嵌套校验。

我们要做如下2个事情

@Data
public class Student {@NotBlank(message = "用户名不能为空")private String name;@NotBlank(message = "手机号不能为空")@Pattern(regexp = "^1(3|4|5|7|8)\\d{9}$", message = "手机号码格式错误")private String phone;@NotBlank(message = "邮箱不能为空")@Email(message = "邮箱格式错误")private String email;@NotNull(message = "父母名字不能为空")@Validprivate Relation relation;
}

@Data
public class Relation {@NotBlank(message = "父亲的姓名不能为空")private String fatherName;@NotBlank(message = "父亲的姓名不能为空")private String motherName;
}

那Relation类的fatherName属性如何被赋值呢?

xxxx?relation.fatherName=li&relation.motherName=liu

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

帮你少写一大半参数校验代码的小技巧相关推荐

  1. 程序员写好技术文章的几点小技巧

    简介:其我本身并不喜欢写字,之前写的几篇文章,涉及的话题自带流量,所以阅读量多了一些,谈不上有多擅长.不过我还是分享一下我自己写文章时用到的一些小技巧吧,希望对大家有帮助. 作者 | 门柳 来源 | ...

  2. php get 传循环出来的参数_PHP性能优化小技巧

    PHP性能优化小技巧: 1. foreach效率更高,尽量用foreach代替while和for循环. 2. 循环内部不要声明变量,尤其是对象这样的变量. 3. 在多重嵌套循环中,如有可能,应当将最长 ...

  3. 程序员写好技术文章的几点小技巧,简述java内存模型面试

    开头 该文档在Github上收获5K+star的Java核心神技(这参数,质量多高就不用我多说了吧)非常全面,包含基础知识.Java集合.JVM.多线程并发.spring原理.微服务.Netty 与R ...

  4. 提升matlab效率,科学网—写Matlab程序,提高运算速度的小技巧 - 吴景鹏的博文

    同样的算法和思路,不同的人写出来的程序,执行效率可能有成倍的差别.主要原因就是写代码的习惯,这里介绍点个人的小体会. 1. 向量化,少用for.很多人写Matlab代码,会沿用C语言的思路,经常用fo ...

  5. mybatisgenerator使用_MyBatis Generator,帮你少写50%代码的自动化工具,你用过吗?

    GitHub地址 https://github.com/erlieStar/mybatis-generator-demo 介绍 MyBatis Generator的作用就是根据数据库中的表结构,帮我们 ...

  6. 用好idea这几款插件,可以帮你少写30%的代码!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者 | HeloWxl 来源 | jianshu.com/p/e ...

  7. 这个IDEA插件可以帮你少写30%的代码

    Easycode是idea的一个插件,可以直接对数据的表生成entity,controller,service,dao,mapper,无需任何编码,简单而强大. * 1.安装(EasyCode) 建议 ...

  8. 『设计模式』写代码偷懒小技巧,程序开发大智慧--享元模式

    23种设计模式+额外常用设计模式汇总 (持续更新) 享元模式 享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能.这种类型的设计模式属于结构型模式,它提 ...

  9. echarts里面的参数解释_Echarts适用小技巧:适用参数详细说明及示例-TS文件

    点击右上方红色按钮关注"web秀",让你真正秀起来 前言 前面有文章,讲述了Vue中封装Echarts组件,但都是直接上代码,没有具体对代码进行讲述.今天我们就来看看,如何使Ech ...

最新文章

  1. 全球及中国健康保险市场运作模式与需求潜力预测报告2022版
  2. 基于springboot断点续传或分片上传
  3. 微软高性能计算服务器pdf,微软高性能计算HPCserver2008技术概览.pdf
  4. ben we_惊!WE辅助选手Ben离开WE,大舅子还能再有这么默契的辅助吗?
  5. python常用代码入门-Python基础总结成千行代码,让Python入门更简单!
  6. XManager连接CentOS6.5
  7. java的if判读_java if判断
  8. u盘虚拟启动cd linux,CDlinux系统用U盘搭建启动盘
  9. 手机定位浅析 AGPS定位 LBS基站定位 卫星定位
  10. Hdu--5064(DP)
  11. Unity中获取AnimationClip的关键帧信息
  12. 2021-07-17 随笔
  13. 软件工程 实践者的研究方法 第12章答案
  14. 实训4——RFID刷卡开锁
  15. GIT 中如何打标签(git tag)
  16. Graham-Scan算法计算凸包的Python代码实现
  17. 微软为什么能转型成功?
  18. 如何用 Java 对 PDF 文件进行电子签章
  19. 浏览器中的data类型的Url格式,data:image/png,data:image/jpeg!
  20. PNP与NPN两种三极管使用方法

热门文章

  1. vb net的定时循环_.NET工具ReSharper:如何帮助Visual Studio用户?
  2. 向后转动作要领_跆拳道腿法之转身侧踢动作要领
  3. jackson驼峰转下划线注解_jackson序列化与反序列化的应用实践
  4. loadrunner工具的组成
  5. 操作系统之进程管理:7、进程同步、进程互斥
  6. (计算机组成原理)第七章输入和输出系统-第四节1:I/O方式之程序查询方式
  7. poj3616 基础的动态规划算法 《挑战程序设计竞赛》
  8. centos 修改开机画面
  9. Docker 的4种网络模式
  10. Python数据存储:pickle模块的使用讲解(测试代码)