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. codeforces 478A.Initial Bet 解题报告

    题目链接:http://codeforces.com/problemset/problem/478/A 题目意思:简单来说,就是初始化的时候,五个人的值都是 b,现在给出每个人最终的状态:就是经过互相 ...

  2. 元素查找(codevs 1230)

    1230 元素查找  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解       题目描述 Description 给出n个正整数,然后有m个询问,每 ...

  3. python基础——函数的参数

    python基础——函数的参数 定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了.对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复 ...

  4. Rap 安装和配置

    本机环境 系统:CentOS 6.7 64 位 MySQL 5.6 JDK 1.8 Tomcat 8 Redis 3.0.7 Rap 0.14.1 Rap 说明 官网:https://github.c ...

  5. Android中获取蓝牙log

    1.蓝牙的snoop log存放位置 /etc/bluetooth/bt_stack.conf   2.修改方法 #关闭蓝牙 修改bt_stack.conf文件中打印log的等级 adb root a ...

  6. app后端架构设计(转)

    (1)Restful设计原则 Restful风格:RESTfu设计原则,它被Roy Felding提出(在他的”基于网络的软件架构“论文中第五章).而REST的核心原则是将你的API拆分为逻辑上的资源 ...

  7. 操作JNI函数以及复杂对象传递

    转自:http://blog.csdn.net/qinjuning/article/details/7607214 在掌握了JNI函数的使用和相关类型的映射后,以及知晓何利用javah工具生成对应的j ...

  8. MyEclipse导入Maven项目

    转自:http://blog.csdn.net/xuelu198708/article/details/8561115 导入分两种方法: 1.使用MyEclipse的普通工程导入,步骤如下: 1> ...

  9. 关于Android开发中的证书和密钥等问题

    关于Android开发中的证书和密钥等问题 引言 除了Android发布应用签名时需要用到证书外,在进行google Map Api开发和Facebook SDK API开发等时都需要申请API Ke ...

  10. SharedPreferences(转)

    [功能] 大家在android开发中 一点有这样的需求 就是需要保存一下与该程序有关的属性设置的问题 比如:window xp 中 <假设系统盘为 C:/> 的位置为: C:\Progra ...