您的位置:首页 > 编程语言 > Java开发

springboot使用hibernate validator校验

2018-02-07 16:43 471 查看

一、参数校验

在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码个人感觉有两个麻烦:

验证代码繁琐,重复劳动

方法内代码显得冗长

每次要看哪些参数验证是否完整,需要去翻阅验证逻辑代码

hibernate validator(官方文档)提供了一套比较完善、便捷的验证实现方式。

spring-boot-starter-web
包里面有
hibernate-validator
包,不需要引用hibernate validator依赖。

二、hibernate validator校验demo

先来看一个简单的demo,添加了Validator的注解:


import org.hibernate.validator.constraints.NotBlank;

import javax.validation.constraints.AssertFalse;
import javax.validation.constraints.Pattern;



View Code
如上Person所示,3个分组分别验证字段如下:

GroupA验证字段userId;

GroupB验证字段userName、sex;

Default验证字段age(Default是Validator自带的默认分组)

a、分组

只验证GroupA、GroupB标记的分组:

@RequestMapping("/demo5")
public void demo5(){
Person p = new Person();
/**GroupA验证不通过*/
p.setUserId(-12);
/**GroupA验证通过*/
//p.setUserId(12);
p.setUserName("a");
p.setAge(110);
p.setSex(5);
Set<ConstraintViolation<Person>> validate = validator.validate(p, GroupA.class, GroupB.class);
for (ConstraintViolation<Person> item : validate) {
System.out.println(item);
}
}




@RequestMapping("/demo6")
public void demo6(@Validated({GroupA.class, GroupB.class}) Person p, BindingResult result){
if(result.hasErrors()){
List<ObjectError> allErrors = result.getAllErrors();
for (ObjectError error : allErrors) {
System.out.println(error);
}
}
}


GroupA、GroupB、Default都验证不通过的情况:

验证信息如下所示:


ConstraintViolationImpl{interpolatedMessage='必须在[4,20]', propertyPath=userName, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必须在[4,20]'}
ConstraintViolationImpl{interpolatedMessage='必须大于0',
propertyPath=userId, rootBeanClass=class
validator.demo.project.model.Person, messageTemplate='必须大于0'}
ConstraintViolationImpl{interpolatedMessage='性别必须在[0,2]',
propertyPath=sex, rootBeanClass=class
validator.demo.project.model.Person, messageTemplate='性别必须在[0,2]'}


GroupA验证通过、GroupB、Default验证不通过的情况:

验证信息如下所示:


ConstraintViolationImpl{interpolatedMessage='必须在[4,20]',
propertyPath=userName, rootBeanClass=class
validator.demo.project.model.Person, messageTemplate='必须在[4,20]'}
ConstraintViolationImpl{interpolatedMessage='性别必须在[0,2]',
propertyPath=sex, rootBeanClass=class
validator.demo.project.model.Person, messageTemplate='性别必须在[0,2]'}


b、组序列

除了按组指定是否验证之外,还可以指定组的验证顺序,前面组验证不通过的,后面组不进行验证:

指定组的序列(GroupA》GroupB》Default):

@GroupSequence({GroupA.class, GroupB.class, Default.class})
public interface GroupOrder {
}


测试demo:

@RequestMapping("/demo7")
public void demo7(){
Person p = new Person();
/**GroupA验证不通过*/
//p.setUserId(-12);
/**GroupA验证通过*/
p.setUserId(12);
p.setUserName("a");
p.setAge(110);
p.setSex(5);
Set<ConstraintViolation<Person>> validate = validator.validate(p, GroupOrder.class);
for (ConstraintViolation<Person> item : validate) {
System.out.println(item);
}
}




@RequestMapping("/demo8")
public void demo8(@Validated({GroupOrder.class}) Person p, BindingResult result){
if(result.hasErrors()){
List<ObjectError> allErrors = result.getAllErrors();
for (ObjectError error : allErrors) {
System.out.println(error);
}
}
}


GroupA、GroupB、Default都验证不通过的情况:

验证信息如下所示:


ConstraintViolationImpl{interpolatedMessage='必须大于0', propertyPath=userId, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必须大于0'}


GroupA验证通过、GroupB、Default验证不通过的情况:

验证信息如下所示:


ConstraintViolationImpl{interpolatedMessage='必须在[4,20]', propertyPath=userName, rootBeanClass=class validator.demo.project.model.Person, messageTemplate='必须在[4,20]'}
ConstraintViolationImpl{interpolatedMessage='性别必须在[0,2]',
propertyPath=sex, rootBeanClass=class
validator.demo.project.model.Person, messageTemplate='性别必须在[0,2]'}


结论:分组顺序校验时,按指定的分组先后顺序进行验证,前面的验证不通过,后面的分组就不行验证。

五、自定义验证器

一般情况,自定义验证可以解决很多问题。但也有无法满足情况的时候,此时,我们可以实现validator的接口,自定义自己需要的验证器。

如下所示,实现了一个自定义的大小写验证器:

public enum CaseMode {
UPPER,
LOWER;
}

@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
public @interface CheckCase {
String message() default "";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

CaseMode value();
}

public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
private CaseMode caseMode;
public void initialize(CheckCase checkCase) {
this.caseMode = checkCase.value();
}

public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if (s == null) {
return true;
}

if (caseMode == CaseMode.UPPER) {
return s.equals(s.toUpperCase());
} else {
return s.equals(s.toLowerCase());
}
}
}


要验证的Model:

public class Demo{
@CheckCase(value = CaseMode.LOWER,message = "userName必须是小写")
private String userName;

public String getUserName() {
return userName;
}

public void setUserName(String userName) {
this.userName = userName;
}
}


validator配置:

@Bean
public Validator validator(){
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();

return validator;
}


验证测试:

@RequestMapping("/demo4")
public void demo4(){
Demo demo = new Demo();
demo.setUserName("userName");
Set<ConstraintViolation<Demo>> validate = validator.validate(demo);
for (ConstraintViolation<Demo> dem : validate) {
System.out.println(dem.getMessage());
}
}


输出结果:


userName必须是小写


六、常见的注解

Bean Validation 中内置的 constraint
@Null 被注释的元素必须为 null
@NotNull 被注释的元素必须不为 null
@AssertTrue 被注释的元素必须为 true
@AssertFalse 被注释的元素必须为 false
@Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=) 被注释的元素的大小必须在指定的范围内
@Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past 被注释的元素必须是一个过去的日期
@Future 被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
Hibernate Validator 附加的 constraint
@NotBlank(message =) 验证字符串非null,且长度必须大于0
@Email 被注释的元素必须是电子邮箱地址
@Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内


//大于0.01,不包含0.01
@NotNull
@DecimalMin(value = "0.01", inclusive = false)
private Integer greaterThan;

//大于等于0.01
@NotNull
@DecimalMin(value = "0.01", inclusive = true)
private BigDecimal greatOrEqualThan;

@Length(min = 1, max = 20, message = "message不能为空")
//不能将Length错用成Range
//@Range(min = 1, max = 20, message = "message不能为空")
private String message;


七、参考资料

参考资料:

http://docs.jboss.org/hibernate/validator/4.2/reference/zh-CN/html_single/#validator-gettingstarted

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: