上一文我通过传递不合法参数触发异常,进行了统一拦截,那么这篇文章主要介绍JSR303,Hibernate Validator详细讲解及如何优雅的对参数进行校验,使用和技巧。
JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了,笔者还是基于springboot(1.5.8.RELEASE)。
直接上干货,带你们一起实验是使用org.hibernate.validator.constraints包下的注解。
首先定义一个实体类,属性分别用了校验注解,分别进行触发。
import org.hibernate.validator.constraints.NotBlank;
import org.hibernate.validator.constraints.NotEmpty;
import javax.validation.constraints.*;
import java.io.Serializable;
import java.util.List;
/**
* @author yanlin
* @version v1.3
* @date 2018-10-18 下午3:16
* @since v8.0
**/
public class Student implements Serializable {
private static final long serialVersionUID = 7003907324788760110L;
@NotBlank(message = "姓名不能为空")
private String name;
@Min(value = 2, message = "不能小于2")
@Max(value = 5, message = "不能大于5")
private Integer age;
@NotEmpty(message = "集合不能为空")
private List stringList;
@AssertTrue(message = "bool必须为true")
private Boolean bool;
@NotNull(message = "对象不能为空")
private Student student;
//省略getter setter
这是一个controller,
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.hibernate.validator.constraints.NotBlank;
import javax.validation.Valid;
/**
* @author yanlin
* @version v1.2
* @date 2018-08-16 下午2:21
* @since v8.0
**/
@SpringBootApplication
@EnableDiscoveryClient
@RestController
//@Validated
public class EurekaClientApp {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApp.class, args);
}
@RequestMapping(value = "/ClientService/body", method = RequestMethod.POST)
public void testBodyE(@Valid @RequestBody Student student) {
System.out.println(student.toString());
}
我利用postman发送五次请求,每一次我都更改了部分参数以便触发校验注解,下面是我操作的过程
从上面的操作过程可以发现,其实不同类型的注解校验是有顺序的,并不是实体类里属性自上而下的顺序,最后一张图可以发现,我名字是空,但是断言bool是true时,他优先触发了断言,所以小伙伴们在使用的时候要主意哦,同类型的注解是有顺序的,切记,不同类型的不是越靠前越先触发哦!
下面介绍一下直接校验方法参数体中的基本数据类型,这是笔者在做这个实验前由于好奇心无意发现的,先贴两个注解的代码,你们会发现我上面写的代码,如果是JavaBean校验,我都会在参数前加@Valid,当然加@Validated效果也是一样的(这两个注解往下看我会有介绍),但是他俩最重要的区别是@Validated可以注释在类上,这个我当时很好奇,所以我实验了一下,结论是:当@Validated使用在类上时,会触发当前类所有写在方法参数上的参数校验注解的生效。
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Validated {
/**
* Specify one or more validation groups to apply to the validation step
* kicked off by this annotation.
* JSR-303 defines validation groups as custom annotations which an application declares
* for the sole purpose of using them as type-safe group arguments, as implemented in
* {@link org.springframework.validation.beanvalidation.SpringValidatorAdapter}.
*
Other {@link org.springframework.validation.SmartValidator} implementations may
* support class arguments in other ways as well.
*/
Class>[] value() default {};
}
@Target({ METHOD, FIELD, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface Valid {
}
例如:test方法的name参数前加参数校验注解(@NotBlank),但是类上必须加@Validated,否则你在基本数据类型前加的参数校验注解是不生效的,这点笔者已经实验了,大家直接当结论就可以。
/**
* @author yanlin
* @version v1.2
* @date 2018-08-16 下午2:21
* @since v8.0
**/
@SpringBootApplication
@EnableDiscoveryClient
@Validated
public class EurekaClientApp {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApp.class, args);
}
@RequestMapping(value = "/ClientService/body", method = RequestMethod.POST)
public void testBodyE(@Valid @RequestBody Student student) {
System.out.println(student.toString());
}
@GetMapping("/ClientService/name")
public String test(@NotBlank(message = "name 不能为空") @RequestParam("name") String name) {
if (name.equals("1")) {
throw new ParameterServiceException("这里填写错误代码,规范应是一个枚举", "描述当前错误原因");
}
return name;
}
1.该注解表示对该对象进行验证需要在实体类内配合其他注解使用
2.使用@Validated或者@Valid在基本验证功能上没有太多区别。但是在分组、注解地方、嵌套验证等功能上两个有所不同
3.@Validated是@Valid 的一次封装,是Spring提供的校验机制使用。@Valid不提供分组功能
4.@Validated:提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
5.@Validated不能用在成员属性(字段)上,但是@Valid能加在成员属性(字段)上,而且@Valid类注解上也说明了它支持嵌套验证功能
6.如果一个bean中包含第二个bean,这时要检验第二个bean中某个字段,即嵌套校验,必须要在第一个bean对象中使用@Valid标注到表示第二个bean对象的字段上,然后再第二个bean对象里面的字段上加上校验类型.
7.@Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上
8.@Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
@Null 验证对象是否为null
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.
@AssertTrue 验证 Boolean 对象是否为 true
@AssertFalse 验证 Boolean 对象是否为 false
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内
@Length(min=, max=) Validates that the annotated string is between min and max included.
@Past 验证 Date 和 Calendar 对象是否在当前时间之前
@Future 验证 Date 和 Calendar 对象是否在当前时间之后
@Pattern 验证 String 对象是否符合正则表达式的规则
建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null
@Min 验证 Number 和 String 对象是否大等于指定的值
@Max 验证 Number 和 String 对象是否小等于指定的值
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度
@Digits 验证 Number 和 String 的构成是否合法
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。 @Range(min=, max=) Checks whether the annotated value lies between (inclusive) the specified minimum and maximum. @Range(min=10000,max=50000,message="range.bean.wage") private BigDecimal wage;
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)
@CreditCardNumber信用卡验证
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。
@ScriptAssert(lang= ,script=, alias=)
@URL(protocol=,host=, port=,regexp=, flags=)
本篇依赖了我上篇文章的异常拦截处理,类图如下
类的代码在上篇文章已经贴出来了,大家自行拷贝。
注:对本文有异议或不明白的地方微信探讨,wx:15524579896