优雅的参数校验(JSR-303的实现Hibernate-Validator)
一、背景
在我们平时开发中,经常会对前台传给我们的参数进行校验,如:
@GetMapping("test")
public String test(String id) {
if (id != null && id.trim() != "") {
throw new RuntimeException("id不能为空");
}
//TODO some method
return "haha";
}
单独一个还行,但要说来个十个八个需要校验的,而且还有邮箱什么的格式验证,又繁琐又重复。我心态就炸了。。。
那么怎么才能简单灵活而又不重复且优雅的解决这个问题呢?
二、方案
其实Java为我们提供了很多的Java规范提案(JSR),如我们接下来要使用的JSR-303。
JSR-303 是JAVA EE 6 中的一项子规范,叫做Bean Validation,用来对参数的校验。但是这只是一个规范,我们不能直接使用。在规范的实现中我们常用的就是:Hibernate-Validator。接下来我们来体验一下。
三、Hibernate-Validator配合注解使用
1)引入依赖
<!-- springboot下web启动器已经依赖了这个包 -->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
</dependency>
2)使用
注解分为两类(先介绍一个简单实用,更多注解介绍见:4)注解):
一种,加在字段上如:
@Data
public class TestBean {
private int id;
/**
* 这个注解保证name不为null且不为空格字符串,否则抛出异常
*/
@NotBlank(message = "name不能为空")
private String name;
}
这样就可以校验了吗?No,这样还不行哦,还要配合第二种注解@Valid/@Validated,加在接口参数对象上,如:
/**
* 这里的@Valid也可以换成@Validated效果是一样的
* @param testBean
* @return
*/
@GetMapping("test")
public String test(@Valid TestBean testBean) {
//TODO 自己的逻辑
return "success";
}
如果这里的name为null或者空格字符串(如:"")那么就会抛出异常:org.springframework.validation.BindException
Field error in object 'testBean' on field 'name': rejected value []; codes [NotBlank.testBean.name,NotBlank.name,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [testBean.name,name]; arguments []; default message [name]]; default message [name不能为空]]
3)场景
下面总结几种能够起到校验作用的使用场景:
-
接口方法形参采用JavaBean形式(就像上面的那个例子一样)如:
@GetMapping("test") public String test(@Valid TestBean testBean) { //TODO 自己的逻辑 return "success"; }
这里的接口形式适合GET或Content-Type设置成application/x-www-form-urlencoded的Post的接口;
这里的@Valid也可以换成@Validated效果是一样的;
-
接口方法形参采用JavaBean形式(@RequestBody)如:
@GetMapping("test") public String test(@Valid @RequestBody TestBean testBean) { //TODO 自己的逻辑 return "success"; }
这里的接口形式适合Content-Type设置成application/json的Post的接口;
这里的@Valid也可以换成@Validated效果是一样的;
-
接口方法形参采用非JavaBean形式,如:
@GetMapping("test") public String test(@NotBlank(message = "name不能为空")String name) { //TODO 自己的逻辑 return "success"; }
注意这种形式在参数前使用@Valid/@Validated经测试起不到校验作用,这种情况只能只能使用@Validated并注释在此方法所在的Controller类上才能起到作用。
4)注解
下面介绍下常用注解的如下:
-
加载需要校验的字段上的(javax.validation提供)
注解 含义(用法) @AssertTrue 用于boolean字段,该字段只能为true @AssertFalse 该字段的值只能为false @CreditCardNumber 对信用卡号进行一个大致的验证 @DecimalMax(value) 只能小于或等于该值(必须是数字) @DecimalMin(value) 只能大于或等于该值(必须是数字) @Digits(integer=,fraction=) 验证是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。 @Email 检查是否是一个有效的email地址 @Future 检查该字段的日期是否是属于将来的日期 @Length(min=,max=) 检查所属的字段的长度是否在min和max之间(只能用于字符串) @Max(value) 该字段的值只能小于或等于该值(必须是数字) @Min(value) 该字段的值只能大于或等于该值(必须是数字) @NotNull 不能为null(字符串) @NotBlank trim()之后不能为empty(字符串) @NotEmpty 不能为null和empty,这里的空是指空字符串也可集合 @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内 @Null 被注释的元素必须为 null @Past 检查该字段的日期是在过去 @Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式 @Range(min=,max=) 被注释的元素必须在合适的范围内 @Size(min=, max=) 检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等 @URL(protocol=,host,port) 检查是否是一个有效的URL,如果提供了protocol,host等,则该URL还需满足提供的条件
上面注解都包含message这个属性,在满足条件时异常输出的提醒就是message设置的值
-
要想上面的字段必须在参数对象上加上
注解 注意 @Valid javax.validation提供 @Validated spring提供(在上面的基础上做了扩展) 下面讲下两者的区别:
-
@Validated:作用在类上、方法、参数
-
@Valid:方法、构造方法、参数、成员属性上
-
@Validated支持分组:在接口形参上加上@Validated({A.class})(A是定义的一个分接口)则只会对相对应的XX类型的group起校验作用其他的分组则不会:
- @NotBlank(group={A.class},message = “name不能为空”)
- @NotBlank(group={B.class,C.class},message = “name不能为空”)
-
@Valid可做嵌套:
@Data public class TestBean { /** * 姓名 notblank */ @NotBlank(message = "name不能为空") private String name; @Valid private List<TestBean2> beans; } @Data public class TestBean2 { @NotNull(message = "age不能为null") private Integer age; }
在接口形参上要校验TestBean且还要校验TestBean下对象成员变量TestBean2下的成员变量,那就只能使用@Valid标注在TestBean下成员变量beans上,才能实现嵌套校验。
-
四、最后
至此你就可以优雅灵活的完成对参数的校验了。
那校验过未通过抛出异常呢,异常信息那么长怎么处理呢,不要着急,敬请期待下期,《统一异常处理》。
更多资源:其实是白羊(https://gitee.com/zhanglinlu)
欢迎star
日常求赞
- 如果你认为本文对你有帮助,还请「在看/转发/赞/star」,多谢
- 如果你还发现了更好或不同的想法,还请在留言区不吝赐教,一起探讨交流修改,万分感谢
共同学习,写下你的评论
评论加载中...
作者其他优质文章