Hibernate validation 注解 springmvc 验证 分组
1. 分组
有的时候,我们对一个实体类需要有多中验证方式,在不同的情况下使用不同验证方式,比如说对于一个实体类来的id来说,保存的时候是不需要的,对于更新时是必须的,可以如下配置:
- public class UserModel {
- @NotNull(message = "{id.empty}", groups = { First.class })
- private int id;
- @NotNull(message = "{username.empty}", groups = { First.class, Second.class })
- private String username;
- @NotNull(message = "{content.empty}", groups = { First.class, Second.class })
- private String content;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- }
- public interface First {
- }
- public interface Second {
- }
通过 groups 对验证进行分组
在controler中的代码如下:
- @RequestMapping(value = "/save.action", method = RequestMethod.POST)
- public String save(@Validated( { Second.class }) UserModel userModel, BindingResult result) {
- if (result.hasErrors()) {
- return "validate/error";
- }
- return "redirect:/success";
- }
- @RequestMapping(value = "/update.action", method = RequestMethod.POST)
- public String update(@Validated( { First.class, Second.class }) UserModel user, BindingResult result) {
- if (result.hasErrors()) {
- return "validate/error";
- }
- return "redirect:/success";
- }
2. 组序列
默认情况下,不同组别的约束验证是无序的,然而在某些情况下,约束验证的顺序却很重要,如下面两个例子:(1)第二个组中的约束验证依赖于一个稳定状态来运行,而这个稳定状态是由第一个组来进行验证的。(2)某个组的验证比较耗时,CPU 和内存的使用率相对比较大,最优的选择是将其放在最后进行验证。因此,在进行组验证的时候尚需提供一种有序的验证方式,这就提出了组序列的概念。
一个组可以定义为其他组的序列,使用它进行验证的时候必须符合该序列规定的顺序。在使用组序列验证的时候,如果序列前边的组验证失败,则后面的组将不再给予验证。
下例中声明了组 GroupA.class,GroupB.class 和 Group.class,其中 default,GroupA,GroupB 均为 Group 的序列。
- public interface GroupA {
- }
- public interface GroupB {
- }
- @GroupSequence( { Default.class, GroupA.class, GroupB.class })
- public interface Group {
- }
- public class User {
- @NotEmpty(message = "firstname may be empty")
- private String firstname;
- @NotEmpty(message = "middlename may be empty", groups = Default.class)
- private String middlename;
- @NotEmpty(message = "lastname may be empty", groups = GroupA.class)
- private String lastname;
- @NotEmpty(message = "country may be empty", groups = GroupB.class)
- private String country;
- }
- @RequestMapping(value = "/update.action", method = RequestMethod.POST)
- public String register(@Validated(Group.class) User user, BindingResult result) {
- if (result.hasErrors()) {
- return "validate/error";
- }
- return "redirect:/success";
- }
3. 验证多个对象
当我们在一个功能处理方法上需要验证多个模型对象时,需要通过如下形式来获取验证结果:
- @RequestMapping("/validate/multi")
- public String multi(@Valid @ModelAttribute("a") A a, BindingResult aErrors, @Valid @ModelAttribute("b") B b, BindingResult bErrors) {
- if (aErrors.hasErrors()) { //如果a模型对象验证失败
- return "validate/error";
- }
- if (bErrors.hasErrors()) { //如果a模型对象验证失败
- return "validate/error";
- }
- return "redirect:/success";
- }
每一个模型对象后边都需要跟一个Errors或BindingResult对象来保存验证结果,其方法体内部可以使用这两个验证结果对象来选择出错时跳转的页面或处理的逻辑。
4. Junit测试
当自定义拓展Validation时,可以使用如下方法进行测试:
- @Test
- public void testValidate() {
- AnnotationDescriptor<EqualsAny> descriptor = new AnnotationDescriptor<EqualsAny>(EqualsAny.class);
- EqualsAny equalsAny = AnnotationFactory.create(descriptor);
- EqualsAnyValidator equalsAnyValidator = new EqualsAnyValidator();
- 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}")
- private String password;
资源文件validation_zh_CN.properties中为
- password.empty.error=password不能为空
实际开发中,很多参数都是要验证非空的,如果每个参数都单独加个错误描述,是很麻烦的。properties虽支持“{}”的写法传递参数,但使用JSR-303注解无法实现传递参数。我想了个办法可通过自定义注解方式实现。
首先,建立个自定义的@NotEmpty注解:
- package com.itkt.payment.core.annotation;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- import javax.validation.Constraint;
- import javax.validation.Payload;
- import com.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 @interface NotEmpty {
- String field() default "";
- String message() default "{com.itkt.payment.core.handler.NotEmpty.message}";
- Class<?>[] groups() default {};
- Class<? extends Payload>[] payload() default {};
- }
自定义的NotEmpty注解中,我们新加了field字段,用于标识字段名称。
然后,建立NotNullValidator实现类:
- package com.itkt.payment.core.handler;
- import javax.validation.ConstraintValidator;
- import javax.validation.ConstraintValidatorContext;
- import com.itkt.payment.core.annotation.NotNull;
- public class NotNullValidator implements ConstraintValidator<NotNull, Object> {
- @Override
- public void initialize(NotNull annotation) {
- }
- @Override
- public boolean isValid(Object str, ConstraintValidatorContext constraintValidatorContext) {
- return str != null;
- }
- }
之后,在资源文件validation_zh_CN.properties中,改变写法:
- password.empty.error={field}不能为空
最后,我们就可以在User类中使用自定义的NotEmpty注解:
- @NotEmpty(field = "password", message = "{password.empty.error}")
- private String password;
实际上,国际化资源文件本身支持从JSR-303注解中获取属性的参数值的,例如从@Length注解中,获取min和max属性的值:
- username.length.error=用户名长度必须在{min}-{max}之间
之所以自带的@NotEmpty注解无法实现,是因为没有一个属性能传递字段名,所以通过自定义@NotEmpty注解来拓展个field字段。
以下是分类
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 验证 分组的更多相关文章
- Hibernate Validation注解列表
下面是主要的验证注解及说明: 注解 适用的数据类型 说明 @AssertFalse Boolean, boolean 验证注解的元素值是false @AssertTrue Boolean, boole ...
- [译]SpringMVC自定义验证注解(SpringMVC custom validation annotations)
在基于SpringMVC框架的开发中,我们经常要对用户提交的字段进行合法性验证,比如整数类型的字段有个范围约束,我们会用@Range(min=1, max=4).在实际应用开发中,我们经常碰到一些自己 ...
- Spring Boot 系列教程19-后台验证-Hibernate Validation
后台验证 开发项目过程中,后台在很多地方需要进行校验操作,比如:前台表单提交,调用系统接口,数据传输等.而现在多数项目都采用MVC分层式设计,每层都需要进行相应地校验. 针对这个问题, JCP 出台一 ...
- SSH(Struts,Spring,Hibernate)和SSM(SpringMVC,Spring,MyBatis)的区别
SSH 通常指的是 Struts2 做前端控制器,Spring 管理各层的组件,Hibernate 负责持久化层. SSM 则指的是 SpringMVC 做前端控制器,Spring 管理各层的组件,M ...
- spring-boot 使用hibernate validation对参数进行优雅的校验
springboot天生支持使用hibernate validation对参数的优雅校验,如果不使用它,只能对参数挨个进行如下方式的手工校验,不仅难看,使用起来还很不方便: if(StringUtil ...
- Hibernate Validation使用示例及讲解
Hibernate Validation使用示例及讲解 时间 -- :: ITeye-博客 原文 http://wdmcygah.iteye.com/blog/2174680 主题 Java 在项目开 ...
- Spring Boot Validation,既有注解不满足,我是怎么暴力扩展validation注解的
前言 昨天,我开发的代码,又收获了一个bug,说是界面上列表查询时,正常情况下,可以根据某个关键字keyword模糊查询,后台会去数据库 %keyword%查询(非互联网项目,没有使用es,只能这样了 ...
- JSR303/JSR-349,hibernate validation,spring validation 之间的关系
JSR303是一项标准,JSR-349是其的升级版本,添加了一些新特性,他们规定一些校验规范即校验注解,如@Null,@NotNull,@Pattern,他们位于javax.validation.co ...
- Hibernate中用注解配置一对多双向关联和多对一单向关联
Hibernate中用注解配置一对多双向关联和多对一单向关联 Hibernate提供了Hibernate Annotations扩展包,使用注解完成映射.在Hibernate3.3之前,需单独下载注解 ...
随机推荐
- 使用Memory Analyzer tool(MAT)分析内存泄漏(一)
转载自:http://www.blogjava.net/rosen/archive/2010/05/21/321575.html 前言 在平时工作过程中,有时会遇到OutOfMemoryError,我 ...
- chrome 插件
SwitchySharp.crx SwitchyOmega.crx Readability_v3.0.15.crx Hackman.crx EditThisCookie_v1.4.1.crx AdBl ...
- CSS“反转”为LESS
LESS(官网在此:http://lesscss.net/)的魅力相信大家都已明了,个人认为它最大的魅力在于能够清晰的展现嵌套关系. 针对现有的项目,它的应用难点主要在于—— 何时转换为css,即是否 ...
- Android之网络编程
本文主要包括三方面内容 Httpurlconnection中doGet与doPost方法实现提交数据到服务器 HttpClient中doGet与doPost方法实现提交数据到服务器 android-a ...
- 查询MYSQL和查询HBASE速度比较
上一篇文章:我要上谷歌 Mysql,关系型数据库: HBase,NoSql数据库. 查询Mysql和查询HBase,到底哪个速度快呢? 与一些真正的大牛讨论时,他们说HBase写入速度,可以达到每秒1 ...
- hdu 4292 最大流 水题
很裸的一道最大流 格式懒得排了,注意把人拆成两份,一份连接食物,一份连接饮料 4 3 3 //4个人,3种食物,3种饮料 1 1 1 //食物每种分别为1 1 1 1 //饮料每种数目分别为1 YYN ...
- 对Android项目中的文件夹进行解释
对Android项目中的文件夹进行解释: · src:里面存放的是Activity程序,或者是以后的其他组件,在此文件夹之中建立类的时候一定要注意,包名称不能是一级. · gen:此文件夹中的内容是自 ...
- ember.js:使用笔记6 子项目的前进与后退
如下代码会根据model产生不同的table项,在进行其他设置后,一般是根据id来跳转到相应项目子项中: {{#each}} {{#link-to "tabls" this}}{{ ...
- hadoop2.2.0部署
hadoop2.2.0部署 下载安装包 hadoop-2.2.0-cdh5.0.0-beta-1.tar.gz 解压 tar zxvf hadoop-2.2.0-cdh5.0.0-beta-1.tar ...
- java.lang.RuntimeException: Invalid action class configuration that references an unknown class named [xxxAction]。
java.lang.RuntimeException: Invalid action class configuration that references an unknown class name ...