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. Servlet、JSP选择题(2)

    Java EE软件工程师认证考试 试题库-选择题 一.    选择题(包括单选和双选) 1.B 编写一个Filter,需要(  ) A. 继承Filter 类 B. 实现Filter 接口 C. 继承 ...

  2. IE的安全性设定增加“我的电脑”的安全性设定

    HKEY_CURRE-NT_USER\Software\Microsoft\Windows\CurrentVersion\InternetSettings\Zones\,在右边窗口中找到DWORD值“ ...

  3. 删除自带OpenJDK

    1:rpm -qa|grep jdk 查看当前的jdk情况. 2:yum -y remove java java-1.7.0-openjdk* 卸载openjdk,这个过程中因为依赖原因可能会卸载一些 ...

  4. Oracle Undo与脏读解析

    Undo就是用来记录保存事务操作过程中的数据,如果事务发生错误,可以之前的数据进行填补. Undo segment 是保存在表空间上的.Undo 大小是固定的,既然是固定的也就是有限的.如果保存的记录 ...

  5. ML 03、机器学习的三要素

    机器学习算法原理.实现与实践——机器学习的三要素 1 模型 在监督学习中,模型就是所要学习的条件概率分布或决策函数.模型的假设空间包含所有可能的条件概率分布或决策函数.例如,假设决策函数是输入变量的线 ...

  6. android开发时,finish()跟System.exit(0)的区别

      这两天在弄Android,遇到一个问题:所开发的小游戏中有背景音乐,玩的过程中始终有音乐在放着,然后在我退出游戏后,音乐还在播放! 我看了一下我最开始写的退出游戏的代码,就是简单的finish() ...

  7. radioButton

    布局: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tool ...

  8. poj 1611 The Suspects 并查集

    The Suspects Time Limit: 1000MS   Memory Limit: 20000K Total Submissions: 30522   Accepted: 14836 De ...

  9. ember.js:使用笔记5 使用view

    在已经设置route的情况下,以table为例,可以如下设置,范围为对应的模版: App.TableView = Em.View.extend({ }); App.TableIndexView = E ...

  10. 人见人爱A^B

    求A^B的最后三位数表示的整数.说明:A^B的含义是“A的B次方”   Input 输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A= ...