首页 文章资讯内容详情

Hibernate validation 注解 springmvc 验证 分组

2026-06-01 2 花语

本文内容纲要:

-SpringMVC验证框架Validation特殊用法

SpringMVC验证框架Validation特殊用法

分组

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

[java]viewplaincopy

publicclassUserModel{ @NotNull(message="{id.empty}",groups={First.class}) privateintid; @NotNull(message="{username.empty}",groups={First.class,Second.class}) privateStringusername; @NotNull(message="{content.empty}",groups={First.class,Second.class}) privateStringcontent; publicintgetId(){ returnid; } publicvoidsetId(intid){ this.id=id; } publicStringgetUsername(){ returnusername; } publicvoidsetUsername(Stringusername){ this.username=username; } publicStringgetContent(){ returncontent; } publicvoidsetContent(Stringcontent){ this.content=content; } } publicinterfaceFirst{ } publicinterfaceSecond{ }

通过groups对验证进行分组

在controler中的代码如下:

[java]viewplaincopy

@RequestMapping(value="/save.action",method=RequestMethod.POST)

publicStringsave(@Validated({Second.class})UserModeluserModel,BindingResultresult){

if(result.hasErrors()){

return"validate/error";

}

return"redirect:/success";

}

@RequestMapping(value="/update.action",method=RequestMethod.POST)

publicStringupdate(@Validated({First.class,Second.class})UserModeluser,BindingResultresult){

if(result.hasErrors()){

return"validate/error";

}

return"redirect:/success";

}

组序列

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

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

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

[java]viewplaincopy

publicinterfaceGroupA{ } publicinterfaceGroupB{ } @GroupSequence({Default.class,GroupA.class,GroupB.class}) publicinterfaceGroup{ } publicclassUser{ @NotEmpty(message="firstnamemaybeempty") privateStringfirstname; @NotEmpty(message="middlenamemaybeempty",groups=Default.class) privateStringmiddlename; @NotEmpty(message="lastnamemaybeempty",groups=GroupA.class) privateStringlastname; @NotEmpty(message="countrymaybeempty",groups=GroupB.class) privateStringcountry; }

[java]viewplaincopy

@RequestMapping(value="/update.action",method=RequestMethod.POST)

publicStringregister(@Validated(Group.class)Useruser,BindingResultresult){

if(result.hasErrors()){

return"validate/error";

}

return"redirect:/success";

}

验证多个对象

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

[java]viewplaincopy

@RequestMapping("/validate/multi") publicStringmulti(@Valid@ModelAttribute("a")Aa,BindingResultaErrors,@Valid@ModelAttribute("b")Bb,BindingResultbErrors){ if(aErrors.hasErrors()){//如果a模型对象验证失败 return"validate/error"; } if(bErrors.hasErrors()){//如果a模型对象验证失败 return"validate/error"; } return"redirect:/success"; }

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

Junit测试

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

[java]viewplaincopy

@Test publicvoidtestValidate(){ AnnotationDescriptordescriptor=newAnnotationDescriptor(EqualsAny.class); EqualsAnyequalsAny=AnnotationFactory.create(descriptor); EqualsAnyValidatorequalsAnyValidator=newEqualsAnyValidator(); equalsAnyValidator.initialize(equalsAny); Assert.assertTrue(equalsAnyValidator.isValid("123",null)); }

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

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

@NotEmpty(message="{password.empty.error}") privateStringpassword;

资源文件validation_zh_CN.properties中为

[plain]viewplaincopy

password.empty.error=password不能为空

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

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

[java]viewplaincopy

packagecom.itkt.payment.core.annotation; importjava.lang.annotation.ElementType; importjava.lang.annotation.Retention; importjava.lang.annotation.RetentionPolicy; importjava.lang.annotation.Target; importjavax.validation.Constraint; importjavax.validation.Payload; importcom.itkt.payment.core.handler.NotEmptyValidator; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE,ElementType.CONSTRUCTOR,ElementType.PARAMETER}) @Constraint(validatedBy={NotEmptyValidator.class}) public@interfaceNotEmpty{ Stringfield()default""; Stringmessage()default"{com.itkt.payment.core.handler.NotEmpty.message}"; Class<?>[]groups()default{}; Class<?extendsPayload>[]payload()default{}; }

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

然后,建立NotNullValidator实现类:

[java]viewplaincopy

packagecom.itkt.payment.core.handler; importjavax.validation.ConstraintValidator; importjavax.validation.ConstraintValidatorContext; importcom.itkt.payment.core.annotation.NotNull; publicclassNotNullValidatorimplementsConstraintValidator<NotNull,Object>{ @Override publicvoidinitialize(NotNullannotation){ } @Override publicbooleanisValid(Objectstr,ConstraintValidatorContextconstraintValidatorContext){ returnstr!=null; } }

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

[plain]viewplaincopy

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

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

[java]viewplaincopy

@NotEmpty(field="password",message="{password.empty.error}") privateStringpassword;

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

[plain]viewplaincopy

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或数组的字段,或该字段直接为一个其他对象的引用,

//这样在检查当前对象的同时也会检查该字段所引用的对象

以下是分类

BeanValidation中内置的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=)被注释的元素必须符合指定的正则表达式

HibernateValidator附加的constraint

@NotBlank(message=)验证字符串非null,且长度必须大于0

@Email被注释的元素必须是电子邮箱地址

@Length(min=,max=)被注释的字符串的大小必须在指定的范围内

@NotEmpty被注释的字符串的必须非空

@Range(min=,max=,message=)被注释的元素必须在合适的范围内

本文内容总结:SpringMVC验证框架Validation特殊用法,

原文链接:https://www.cnblogs.com/hujihon/p/5357481.html