hibernate_validator_09
创建自己的约束规则
尽管Bean Validation API定义了一大堆标准的约束条件, 但是肯定还是有这些约束不能满足我们
需求的时候, 在这种情况下, 你可以根据你的特定的校验需求来创建自己的约束条件.
一.创建一个简单的约束条件
按照以下三个步骤来创建一个自定义的约束条件
•创建约束标注
•实现一个验证器
•定义默认的验证错误信息
1. 约束标注---让我们来创建一个新的用来判断一个给定字符串是否全是大写或者小写字符的约束标注.
首先,我们需要一种方法来表示这两种模式( 译注: 大写或小写), 我们可以使用 String 常量, 但是
在Java 5中, 枚举类型是个更好的选择:
package test02;
public enum CaseMode {
UPPER,
LOWER;
}
2.现在我们可以来定义真正的约束标注了. 如果你以前没有创建过标注(annotation)的话参考
http://www.cnblogs.com/wangyang108/p/5668388.html
package test02; import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target({METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
public @interface CheckCase {
String message() default "{com.mycompany.constraints.checkcase}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
CaseMode value(); }
一个标注(annotation) 是通过 @interface 关键字来定义的. 这个标注中的属性是声明成类似方法
的样式的. 根据Bean Validation API 规范的要求
•message属性, 这个属性被用来定义默认得消息模版, 当这个约束条件被验证失败的时候,通过
此属性来输出错误信息.
•groups 属性, 用于指定这个约束条件属于哪(些)个校验组.这
个的默认值必须是 Class<?> 类型到空到数组.
• payload 属性, Bean Validation API 的使用者可以通过此属性来给约束条件指定严重级别. 这
个属性并不被API自身所使用.
提示:通过payload属性来指定默认错误严重级别的示例
public class Severity {
public static class Info extends Payload {};
public static class Error extends Payload {};
}
public class ContactDetails {
@NotNull(message="Name is mandatory", payload=Severity.Error.class)
private String name;
@NotNull(message="Phone number not specified, but not mandatory", payload=Severity.Info.class)
private String phoneNumber;
// ...
}
这样, 在校验完一个ContactDetails 的示例之后, 你就可以通过调用ConstraintViolation.getConstraintDescriptor().getPayload()来得到之前指定到错误级别了,并且可以根据这个信息来决定接下来到行为.
除了这三个强制性要求的属性(message, groups 和 payload) 之外, 我们还添
加了一个属性用来指定所要求到字符串模式. 此属性的名称value在annotation的定义中比较特
殊, 如果只有这个属性被赋值了的话, 那么, 在使用此annotation到时候可以忽略此属性名称,
即 @CheckCase(CaseMode.UPPER) .
另外, 我们还给这个annotation标注了一些(所谓的) 元标注( 译注: 或"元模型信息"?, "meta
annotatioins"):
• @Target({ METHOD, FIELD, ANNOTATION_TYPE }) : 表示@CheckCase 可以被用在方法, 字段或者
annotation声明上.
• @Retention(RUNTIME) : 表示这个标注信息是在运行期通过反射被读取的.
• @Constraint(validatedBy = CheckCaseValidator.class) : 指明使用那个校验器(类) 去校验使用了
此标注的元素.
• @Documented : 表示在对使用了 @CheckCase 的类进行javadoc操作到时候, 这个标注会被添加到
javadoc当中.
提示:Hibernate Validator对方法的参数上使用约束注释也提供的支持.
为了使用自定义的参数认证的注释,ElementType.PARAMETER一定要被指定成@Target annotation
3.创建一个验证器以让我们的注释生效--实现ConstraintValidator接口
package test02; import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
private CaseMode caseMode; public void initialize(CheckCase constraintAnnotation) {
this.caseMode = constraintAnnotation.value();
} public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
if (object == null)
return true;
if (caseMode == CaseMode.UPPER)
return object.equals(object.toUpperCase());
else
return object.equals(object.toLowerCase());
}
}
ConstraintValidator 定义了两个泛型参数, 第一个是这个校验器所服务到标注类型(在我们的例子
中即 CheckCase ), 第二个这个校验器所支持到被校验元素到类型 (即 String ).
如果一个约束标注支持多种类型到被校验元素的话, 那么需要为每个所支持的类型定义一
个 ConstraintValidator ,并且注册到约束标注中.
这个验证器的实现就很平常了, initialize() 方法传进来一个所要验证的标注类型的实例, 在本
例中, 我们通过此实例来获取其value属性的值,并将其保存为 CaseMode 类型的成员变量供下一步使
用.
isValid() 是实现真正的校验逻辑的地方, 判断一个给定的 String 对于 @CheckCase 这个约束条件来说
是否是合法的, 同时这还要取决于在 initialize() 中获得的大小写模式. 根据Bean Validation中所
推荐的做法, 我们认为 null 是合法的值. 如果 null 对于这个元素来说是不合法的话,那么它应该使
用 @NotNull 来标注.
4.现在来验证一下
先建一个Po
package test02;
public class User {
@CheckCase(CaseMode.UPPER)
private String name="wangyang";
}
然后进行验证
package test02; import java.util.Set; import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory; import org.junit.BeforeClass;
import org.junit.Test; public class MyTest {
private static Validator validator; /**
* 获取一个验证器
*/
@BeforeClass
public static void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
public void test01(){
User u=new User();
Set<ConstraintViolation<User>> validate = validator.validate(u);
System.out.println(validate.size());
System.out.println(validate.iterator().next());
//ConstraintViolationImpl{interpolatedMessage='{com.mycompany.constraints.checkcase}', propertyPath=name, rootBeanClass=class test02.User, messageTemplate='{com.mycompany.constraints.checkcase}'}
}
}
4.ConstraintValidatorContext
上面的例子中的 isValid 使用了约束条件中定义的错误消息模板, 然
后返回一个 true 或者 false . 通过使用传入的 ConstraintValidatorContext 对象, 我们还可以给约束
条件中定义的错误信息模板来添加额外的信息或者完全创建一个新的错误信息模板.
下面我们修改上述代码
package test02; import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
private CaseMode caseMode; public void initialize(CheckCase constraintAnnotation) {
this.caseMode = constraintAnnotation.value();
} public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
if (object == null)
return true;
boolean isValid;
if (caseMode == CaseMode.UPPER) {
isValid = object.equals(object.toUpperCase());
} else {
isValid = object.equals(object.toLowerCase());
}
if (!isValid) {
constraintContext.disableDefaultConstraintViolation();
constraintContext.buildConstraintViolationWithTemplate("{com.mycompany.constraints.CheckCase.message}")
.addConstraintViolation();
}
return isValid;
}
}
再进行验证:
package test02; import java.util.Set; import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory; import org.junit.BeforeClass;
import org.junit.Test; public class MyTest {
private static Validator validator; /**
* 获取一个验证器
*/
@BeforeClass
public static void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
public void test01(){
User u=new User();
Set<ConstraintViolation<User>> validate = validator.validate(u);
System.out.println(validate.size());
System.out.println(validate.iterator().next());
//ConstraintViolationImpl{interpolatedMessage='{com.mycompany.constraints.CheckCase.message}', propertyPath=name, rootBeanClass=class test02.User, messageTemplate='{com.mycompany.constraints.CheckCase.message}'}
}
}
5.Adding new ConstraintViolation with custom property path(这一块的东西真没懂,暂不知道有什么用)
6.校验错误信息
最后, 我们还需要指定如果 @CheckCase 这个约束条件验证的时候,没有通过的话的校验错误信息.
我们可以添加下面的内容到我们项目自定义的 ValidationMessages.properties
例:
package test02; import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
@Target({METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
public @interface CheckCase {
String message() default "{test02.CheckCase.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
CaseMode value(); }
再定义一个ValidationMessages.properties

该文件中
test02.CheckCase.message = must be false {value}
运行测试结果:
package test02; import java.util.Set; import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory; import org.junit.BeforeClass;
import org.junit.Test; public class MyTest {
private static Validator validator; /**
* 获取一个验证器
*/
@BeforeClass
public static void setUp() {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
validator = factory.getValidator();
}
@Test
public void test01(){
User u=new User();
Set<ConstraintViolation<User>> validate = validator.validate(u);
System.out.println(validate.size());
//
System.out.println(validate);
//[ConstraintViolationImpl{interpolatedMessage='must be false UPPER', propertyPath=name, rootBeanClass=class test02.User, messageTemplate='{test02.CheckCase.message}'}]
}
}
hibernate_validator_09的更多相关文章
随机推荐
- java学习面向对象构造函数
在java当中目前我们学到的一个比较特殊的函数就是main函数,他是JVM执行的入口,所以书写的格式是固定的,现在我们来介绍java中另一个比较特殊的函数: 构造函数:构造对象的时候调用的函数,作用, ...
- HDU 5889 Barricade 【BFS+最小割 网络流】(2016 ACM/ICPC Asia Regional Qingdao Online)
Barricade Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total S ...
- Subsets —— LeetCode
Given a set of distinct integers, nums, return all possible subsets. Note: Elements in a subset must ...
- VSTS负载测试——如何:使用 SQL 创建结果存储区
原文地址:http://www.cnblogs.com/chenxizhang/archive/2009/06/01/1493939.html 原文参见:http://msdn.microsoft.c ...
- 6种GET和POST请求发送方法
我试过了畅言和多说两种社会化评论框,后来还是抛弃了畅言,不安全. 无论是畅言还是多说,我都需要从远程抓取文章的评论数,然后存入本地数据库.对于多说,请求的格式如下: // 获取评论次数,参数是文章ID ...
- 菜鸟成长日记之新手备忘录-IOS开发第一个项目总结
2013年5月3号,开始找IOS开发工作(自学了大半年,做了一个功能不全的Demo,该出去见见世面了!),5月4号面试了第一家公司(是家刚成立一段时间的外包公司),5月5号第一家公司已二轮电话面试,5 ...
- SunTlsRsaPremasterSecret KeyGenerator not available问题解决
本地Idea测试可以,部署到开发环境遇到下面的问题: javax.net.ssl.SSLKeyException: RSA premaster secret error at com.sun.net. ...
- 二维码开源库zbar、zxing使用心得
首先说明我的测试场景是“识别打印在纸上的二维码”,在扫描结果中寻找二维码并进行识别,而不是直接让摄像头对着二维码扫描. zbar和zxing用的都是自己从github上clone的c++源码/接口编译 ...
- Java里的IO流里的 ObjectInputStream 的读取\写入!
各位好!!我又来了!!今天遇见了一个小问题!! IO流里的对象读取总是出错!各种报错!!神烦啊!!百思不得其解啊!然后就上网百度!找了好久终于让我找到了!下面就让我来说一说! 当你用IO流里的对象流写 ...
- Java里的IO流里的FileInputStream 的读取并在前打印行数!
大家好!!新人求罩! import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException ...