1. 分组

有的时候,我们对一个实体类需要有多中验证方式,在不同的情况下使用不同验证方式,比如说对于一个实体类来的id来说,保存的时候是不需要的,对于更新时是必须的,可以如下配置:

  1. public class UserModel {
  2. @NotNull(message = "{id.empty}", groups = { First.class })
  3. private int id;
  4. @NotNull(message = "{username.empty}", groups = { First.class, Second.class })
  5. private String username;
  6. @NotNull(message = "{content.empty}", groups = { First.class, Second.class })
  7. private String content;
  8. public int getId() {
  9. return id;
  10. }
  11. public void setId(int id) {
  12. this.id = id;
  13. }
  14. public String getUsername() {
  15. return username;
  16. }
  17. public void setUsername(String username) {
  18. this.username = username;
  19. }
  20. public String getContent() {
  21. return content;
  22. }
  23. public void setContent(String content) {
  24. this.content = content;
  25. }
  26. }
  27. public interface First {
  28. }
  29. public interface Second {
  30. }

通过 groups 对验证进行分组

在controler中的代码如下:

  1. @RequestMapping(value = "/save.action", method = RequestMethod.POST)
  2. public String save(@Validated( { Second.class }) UserModel userModel, BindingResult result) {
  3. if (result.hasErrors()) {
  4. return "validate/error";
  5. }
  6. return "redirect:/success";
  7. }
  8. @RequestMapping(value = "/update.action", method = RequestMethod.POST)
  9. public String update(@Validated( { First.class, Second.class }) UserModel user, BindingResult result) {
  10. if (result.hasErrors()) {
  11. return "validate/error";
  12. }
  13. return "redirect:/success";
  14. }

2. 组序列

默认情况下,不同组别的约束验证是无序的,然而在某些情况下,约束验证的顺序却很重要,如下面两个例子:(1)第二个组中的约束验证依赖于一个稳定状态来运行,而这个稳定状态是由第一个组来进行验证的。(2)某个组的验证比较耗时,CPU 和内存的使用率相对比较大,最优的选择是将其放在最后进行验证。因此,在进行组验证的时候尚需提供一种有序的验证方式,这就提出了组序列的概念。

一个组可以定义为其他组的序列,使用它进行验证的时候必须符合该序列规定的顺序。在使用组序列验证的时候,如果序列前边的组验证失败,则后面的组将不再给予验证。

下例中声明了组 GroupA.class,GroupB.class 和 Group.class,其中 default,GroupA,GroupB 均为 Group 的序列。

  1. public interface GroupA {
  2. }
  3. public interface GroupB {
  4. }
  5. @GroupSequence( { Default.class, GroupA.class, GroupB.class })
  6. public interface Group {
  7. }
  8. public class User {
  9. @NotEmpty(message = "firstname may be empty")
  10. private String firstname;
  11. @NotEmpty(message = "middlename may be empty", groups = Default.class)
  12. private String middlename;
  13. @NotEmpty(message = "lastname may be empty", groups = GroupA.class)
  14. private String lastname;
  15. @NotEmpty(message = "country may be empty", groups = GroupB.class)
  16. private String country;
  17. }
  1. @RequestMapping(value = "/update.action", method = RequestMethod.POST)
  2. public String register(@Validated(Group.class) User user, BindingResult result) {
  3. if (result.hasErrors()) {
  4. return "validate/error";
  5. }
  6. return "redirect:/success";
  7. }

3. 验证多个对象

当我们在一个功能处理方法上需要验证多个模型对象时,需要通过如下形式来获取验证结果:

  1. @RequestMapping("/validate/multi")
  2. public String multi(@Valid @ModelAttribute("a") A a, BindingResult aErrors, @Valid @ModelAttribute("b") B b, BindingResult bErrors) {
  3. if (aErrors.hasErrors()) { //如果a模型对象验证失败
  4. return "validate/error";
  5. }
  6. if (bErrors.hasErrors()) { //如果a模型对象验证失败
  7. return "validate/error";
  8. }
  9. return "redirect:/success";
  10. }

每一个模型对象后边都需要跟一个Errors或BindingResult对象来保存验证结果,其方法体内部可以使用这两个验证结果对象来选择出错时跳转的页面或处理的逻辑。

4. Junit测试

当自定义拓展Validation时,可以使用如下方法进行测试:

  1. @Test
  2. public void testValidate() {
  3. AnnotationDescriptor<EqualsAny> descriptor = new AnnotationDescriptor<EqualsAny>(EqualsAny.class);
  4. EqualsAny equalsAny = AnnotationFactory.create(descriptor);
  5. EqualsAnyValidator equalsAnyValidator = new EqualsAnyValidator();
  6. equalsAnyValidator.initialize(equalsAny);
  7. Assert.assertTrue(equalsAnyValidator.isValid("123", null));
  8. }

另外再讲一点Spring对自定义JSR-303限制类型支持的新特性,那就是Spring支持往ConstraintValidator里面注入bean对象。例如在EqualsAnyValidator中利用@Resource注解注入其他Bean对象。

 

在使用Validation时,传递参数到国际化资源文件properties

  1. @NotEmpty(message="{password.empty.error}")
  2. private String password;

资源文件validation_zh_CN.properties中为

  1. password.empty.error=password不能为空

实际开发中,很多参数都是要验证非空的,如果每个参数都单独加个错误描述,是很麻烦的。properties虽支持“{}”的写法传递参数,但使用JSR-303注解无法实现传递参数。我想了个办法可通过自定义注解方式实现。

首先,建立个自定义的@NotEmpty注解:

  1. package com.itkt.payment.core.annotation;
  2. import java.lang.annotation.ElementType;
  3. import java.lang.annotation.Retention;
  4. import java.lang.annotation.RetentionPolicy;
  5. import java.lang.annotation.Target;
  6. import javax.validation.Constraint;
  7. import javax.validation.Payload;
  8. import com.itkt.payment.core.handler.NotEmptyValidator;
  9. @Retention(RetentionPolicy.RUNTIME)
  10. @Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
  11. @Constraint(validatedBy = { NotEmptyValidator.class })
  12. public @interface NotEmpty {
  13. String field() default "";
  14. String message() default "{com.itkt.payment.core.handler.NotEmpty.message}";
  15. Class<?>[] groups() default {};
  16. Class<? extends Payload>[] payload() default {};
  17. }

自定义的NotEmpty注解中,我们新加了field字段,用于标识字段名称。

然后,建立NotNullValidator实现类:

  1. package com.itkt.payment.core.handler;
  2. import javax.validation.ConstraintValidator;
  3. import javax.validation.ConstraintValidatorContext;
  4. import com.itkt.payment.core.annotation.NotNull;
  5. public class NotNullValidator implements ConstraintValidator<NotNull, Object> {
  6. @Override
  7. public void initialize(NotNull annotation) {
  8. }
  9. @Override
  10. public boolean isValid(Object str, ConstraintValidatorContext constraintValidatorContext) {
  11. return str != null;
  12. }
  13. }

之后,在资源文件validation_zh_CN.properties中,改变写法:

  1. password.empty.error={field}不能为空

最后,我们就可以在User类中使用自定义的NotEmpty注解:

  1. @NotEmpty(field = "password", message = "{password.empty.error}")
  2. private String password;

实际上,国际化资源文件本身支持从JSR-303注解中获取属性的参数值的,例如从@Length注解中,获取min和max属性的值:

  1. username.length.error=用户名长度必须在{min}-{max}之间

之所以自带的@NotEmpty注解无法实现,是因为没有一个属性能传递字段名,所以通过自定义@NotEmpty注解来拓展个field字段。

 
 
@AssertTrue   //用于boolean字段,该字段只能为true   
@AssertFalse //该字段的值只能为false   
@CreditCardNumber //对信用卡号进行一个大致的验证   
@DecimalMax //只能小于或等于该值   
@DecimalMin //只能大于或等于该值   
@Digits (integer= 2 ,fraction= 20 ) //检查是否是一种数字的整数、分数,小数位数的数字。   
@Email //检查是否是一个有效的email地址   
@Future //检查该字段的日期是否是属于将来的日期   
@Length (min=,max=) //检查所属的字段的长度是否在min和max之间,只能用于字符串   
@Max //该字段的值只能小于或等于该值   
@Min //该字段的值只能大于或等于该值   
@NotNull //不能为null   
@NotBlank //不能为空,检查时会将空格忽略   
@NotEmpty //不能为空,这里的空是指空字符串   
@Null //检查该字段为空   
@Past //检查该字段的日期是在过去   
@Size (min=, max=) //检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等   
@URL (protocol=,host,port) //检查是否是一个有效的URL,如果提供了protocol,host等,则该URL还需满足提供的条件   
@Valid //该注解只要用于字段为一个包含其他对象的集合或map或数组的字段,或该字段直接为一个其他对象的引用,   
       //这样在检查当前对象的同时也会检查该字段所引用的对象

以下是分类
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=)     被注释的元素必须在合适的范围内

Hibernate validation 注解 springmvc 验证 分组的更多相关文章

  1. Hibernate Validation注解列表

    下面是主要的验证注解及说明: 注解 适用的数据类型 说明 @AssertFalse Boolean, boolean 验证注解的元素值是false @AssertTrue Boolean, boole ...

  2. [译]SpringMVC自定义验证注解(SpringMVC custom validation annotations)

    在基于SpringMVC框架的开发中,我们经常要对用户提交的字段进行合法性验证,比如整数类型的字段有个范围约束,我们会用@Range(min=1, max=4).在实际应用开发中,我们经常碰到一些自己 ...

  3. Spring Boot 系列教程19-后台验证-Hibernate Validation

    后台验证 开发项目过程中,后台在很多地方需要进行校验操作,比如:前台表单提交,调用系统接口,数据传输等.而现在多数项目都采用MVC分层式设计,每层都需要进行相应地校验. 针对这个问题, JCP 出台一 ...

  4. SSH(Struts,Spring,Hibernate)和SSM(SpringMVC,Spring,MyBatis)的区别

    SSH 通常指的是 Struts2 做前端控制器,Spring 管理各层的组件,Hibernate 负责持久化层. SSM 则指的是 SpringMVC 做前端控制器,Spring 管理各层的组件,M ...

  5. spring-boot 使用hibernate validation对参数进行优雅的校验

    springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验,不仅难看,使用起来还很不方便: if(StringUtil ...

  6. Hibernate Validation使用示例及讲解

    Hibernate Validation使用示例及讲解 时间 -- :: ITeye-博客 原文 http://wdmcygah.iteye.com/blog/2174680 主题 Java 在项目开 ...

  7. Spring Boot Validation,既有注解不满足,我是怎么暴力扩展validation注解的

    前言 昨天,我开发的代码,又收获了一个bug,说是界面上列表查询时,正常情况下,可以根据某个关键字keyword模糊查询,后台会去数据库 %keyword%查询(非互联网项目,没有使用es,只能这样了 ...

  8. JSR303/JSR-349,hibernate validation,spring validation 之间的关系

    JSR303是一项标准,JSR-349是其的升级版本,添加了一些新特性,他们规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,他们位于javax.validation.co ...

  9. Hibernate中用注解配置一对多双向关联和多对一单向关联

    Hibernate中用注解配置一对多双向关联和多对一单向关联 Hibernate提供了Hibernate Annotations扩展包,使用注解完成映射.在Hibernate3.3之前,需单独下载注解 ...

随机推荐

  1. percona-xtrabackup备份mysql

    title: 1.percona-xtrabackup备份mysql date: 2016-04-10 23:19:12 tags: mysql categories: mysql --- 一.per ...

  2. 用mtrace检查内存泄漏

    http://blog.csdn.net/ixidof/article/details/6638066内存泄漏检查方法(for Linux) 如果你更想读原始文档, 请参考glibc info的&qu ...

  3. Zabbix利用msmtp+mutt发送邮件报警(公告:这文章有问题,还没有修改,2016-08-25)

    [root@86 ~]# wget http://jaist.dl.sourceforge.net/project/msmtp/msmtp/1.4.32/msmtp-1.4.32.tar.bz2 百度 ...

  4. C# Winform ListView使用

    以下内容均来自网上,个人收集整理,具体出处也难确认了,就没写出处了: 一.基本使用: listView.View = View.Details;//设置视图 listView.SmallImageLi ...

  5. hdu 2255 二分图最大权匹配 *

    题意:说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房 ...

  6. hdu 1011 树形dp

    题意:是有n个洞组成一棵树,你有m个士兵,你从1号房间开始攻打,每个洞有a个"bugs"和b的价值.你的一个士兵可以打20 个"bugs",为了拿到这个洞的价值 ...

  7. Codeforces Round #350 (Div. 2) F. Restore a Number 模拟构造题

    F. Restore a Number   Vasya decided to pass a very large integer n to Kate. First, he wrote that num ...

  8. nmon性能监控工具总结

    一.nmon工具介绍 nmon 是一个分析aix和linux性能的免费工具(主要是ibm为自己的aix操作系统开发的,但是也可以用在linux操作系统),而nmon_analyser是nmon的一个工 ...

  9. 一个DIV三列布局100%高度自适应的好例子(国外)

    <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W ...

  10. Comon.Logging与Log4net联合使用

    1.摘要 Common.Logging定义了一种接口的公共接口,尤其在Quartz.net中作为接口型的组件,而具体则使用log4net,nlog等组件. 2.使用步骤 Install-Package ...