我在hibernate validate基本示例即自定义验证使用中已经简单举例说明了hibernate validate的基本使用。但日常系统中对于不同模块可能对于同一字段合法性校验也会不同,例如用户(User)在注册时可能对于是否邮件填写敏感,而用户添加课程学习列表时也只对用户当前添加课程关心,这样我们之前统一的校验就不起作用了,而hibernate提供的分组功能就能帮助我们实现.直接上代码。
public class User {
@NotBlank(message = "用户名不能为空",groups = FirstGroup.class)
private String userName;
@NotBlank(message = "密码不能为空",groups = FirstGroup.class)
@Size(min = 6, max = 16,message = "密码需在{min}到{max}之间",groups = FirstGroup.class)
private String password;
@Min(1)
@Max(120)
private Integer age;
@Email(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$", message = "邮件格式错误",groups = FirstGroup.class)
private String email;
@Size(min = 11, max = 11)
private String mobile;
//是否VIP 0否 1是 空默认否
private Integer vipFlag;
//VIP授权码 vipFlag为是必填
private String vipLicenseKey;
//学习科目
@ListGtOne(message = "用户学习科目至少为2",groups = SecondGroup.class)
List<Subject> subjectList;
}
/**对应get、set方法**/
我们只看email和subjectList字段即可,他们对应的group分别是FirstGroup.class,SecondGroup.class,这两个都是接口,名称随便定义也不需要实现,只是能做区分分组就行;当然不写时它会有个默认的分组Default.class,所有不填写的都会划入这个分组。
package com.yh.tbb.hibernate.validate.group;
public interface FirstGroup {
}
对于FirstGroup.class举个例子,上面是我定义的接口。下面是对应的测试类
package com.yh.tbb.hibernate.validate;
import com.yh.tbb.hibernate.validate.domain.Subject;
import com.yh.tbb.hibernate.validate.domain.User;
import com.yh.tbb.hibernate.validate.group.FirstGroup;
import com.yh.tbb.hibernate.validate.group.SecondGroup;
import com.yh.tbb.hibernate.validate.util.ValidateUtil;
import javax.validation.ConstraintViolation;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
public class Test {
public static void main(String args[]) {
User user = new User();
user.setUserName("zhao");
user.setPassword("123456");
user.setEmail("123456@qq.@com");
List<Subject> subjectList = new ArrayList<Subject>();
Subject subject = new Subject();
subject.setSubjectCode("A001");
subjectList.add(subject);
user.setSubjectList(subjectList);
Set<ConstraintViolation<User>> result = ValidateUtil.validate(user,FirstGroup.class);
// 抛出检验异常
if (result.size() > 0) {
Iterator<ConstraintViolation<User>> it = result.iterator();
while (it.hasNext()) {
ConstraintViolation<User> str = it.next();
System.out.println(str.getMessage() + "\n");
}
}
}
}
注:ValidateUtil工具类可去我最上面的链接文章查找,这里不再写!
代码校验ValidateUtil.validate(user,FirstGroup.class);加了分组FirstGroup(),这样虽然subjectList的长度不满足条件但也不会校验。
结果:
注:validate方法FirstGroup.class不传时会调用默认的Default.class分组,当然validate也可以传多个分组,例:ValidateUtil.validate(user,FirstGroup.class,SecondGroup.class),这样
添加这两个分组注释的字段会都校验。
2.
还有一个问题是关于分组优先级,例如当用户还没有用户名密码时,对于用户所学科目列表是多余的,要保证用户存在时再查询学习科目。有童鞋可能会考虑用上面的ValidateUtil.validate(user,FirstGroup.class,SecondGroup.class)方法,但是此方法不一定按照分组入参顺序输出,即便通过Set<ConstraintViolation> result = ValidateUtil.validate(user,FirstGroup.class);返回set我们也可以看出。
hibernate validate注释GroupSequence可以满足我们的需求,定义到类级别上。
@GroupSequence({FirstGroup.class,SecondGroup.class,User.class})
public class User {
@NotBlank(message = "用户名不能为空",groups = FirstGroup.class)
private String userName;
@NotBlank(message = "密码不能为空",groups = FirstGroup.class)
@Size(min = 6, max = 16,message = "密码需在{min}到{max}之间",groups = FirstGroup.class)
private String password;
@Min(1)
@Max(120)
private Integer age;
@Email(regexp = "^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.[a-zA-Z0-9]{2,6}$", message = "邮件格式错误",groups = FirstGroup.class)
private String email;
@Size(min = 11, max = 11)
private String mobile;
//是否VIP 0否 1是 空默认否
private Integer vipFlag;
//VIP授权码 vipFlag为是必填
private String vipLicenseKey;
//学习科目
@ListGtOne(message = "用户学习科目至少为2",groups = SecondGroup.class)
List<Subject> subjectList;
}
/**对应get、set方法**/
@GroupSequence({FirstGroup.class,SecondGroup.class,User.class})表示分组由高到低输出顺序,如果这个校验组序列中有一个约束条件没有通过验证的话, 那么此约束条件后面的都不会再继续被校验了.所以加了这个注释后首先就会校验用户信息,FirstGroup存在未通过子段就不会显示SecondGroup错误信息。
注:在这需要注意一下当类中加入GroupSequence时,ValidateUtil.validate(user)调用时此时不会只调用Default.class分组校验,而是按照GroupSequence里面分组优先级进行校验,但是如果自定义了分组那也只按照分组校验,例ValidateUtil.validate(user,SecondGroup.class),这样只能校验SecondGroup.class对应字段了。