帮你少写一大半参数校验代码的小技巧
介绍
几乎每个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 | 被注释的元素必须符合指定的正则表达式 |
被注释的元素必须是电子邮箱地址 |
经常被搞混的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("用户名不能为空"); } // 其他一堆校验过程,调用service return 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()); } } // 调用service return 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个事情
1.将方法中的@Valid注解改为@Validated
2.在relation属性上加@Valid注解
@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 = "父母名字不能为空") @Valid private 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
欢迎关注
其他
@RequestParam("id") Integer id
不传报错
?url=则id的值为0
参考博客
[1]https://www.cnkirito.moe/spring-validation/
各种注解
[2]https://juejin.im/post/5d3fbeb46fb9a06b317b3c48
@Valid和@Validated的区别
[3]https://blog.csdn.net/youanyyou/article/details/86570214
- 点赞
- 收藏
- 分享
- 文章举报
- 个人认为不错的代码结构:利用switch case语句进行参数的取值校验
- SpringMVC集成Hibernate Validator进行注解式的参数校验——让代码更少、更加专注于业务逻辑
- 手工代码校验请求参数,XML配置方式数据校验(企业主流校验)
- struts2_请求参数_手动校验(代码校验)
- SpingBoot整合AOP,Web层AOP方式进行参数校验
- C语言版的单位法人代码校验函数
- Spring MVC代码实例系列-06:Spring MVC配置Hibernate-Validator以及自定义校验注解
- Struts2学习第二天——获取参数与数据校验
- 程序开发小技巧——格式化代码
- 网页代码常用小技巧(禁止"另存为")
- 代码校验工具 SublimeLinter 的安装与使用
- <C#>_使用代码编辑控件属性的一些小技巧
- IOS 界面间传递参数 代码示例
- spring boot 基础学习 - 请求参数映射与参数j校验
- 水晶报表参数字段在代码中赋值
- golang实战使用gin+xorm搭建go语言web框架restgo详解5.6 控制器参数校验
- 对接支付宝沙箱测试代码参数设置
- 通过双击ALV中的字段名判断调用的事物代码和传入的参数
- CRC32和CRC8校验代码,C语言版
- python代码运行显示PC参数