创建自己的约束规则

尽管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的更多相关文章

随机推荐

  1. Qt入门(14)——父窗口部件和子窗口部件

    这个例子演示了如何创建一个父窗口部件和子窗口部件.我们下面使用一个单一的父窗口部件和一个独立的子窗口部件编写界面.    #include <qvbox.h>我们添加了一个头文件qvbox ...

  2. 实战weblogic集群之安装weblogic

    一.系统及软件版本 OS版本:Red Hat Enterprise Linux Server release 6.6WebLogic Server 版本: 10.3.3.0JDK版本:1.7.0_79 ...

  3. excel时会弹出向程序发送命令时出现问题的提示框

    出现此问题需要做两个操作来解决: 1.在开始所有程序中找到Microsoft Excel 2007的运行程序,右键选择属性,在兼容性标签将“以管理员身份运行此程序”的勾去掉. 2.在打开的Excel程 ...

  4. 常考的算法及Java知识总结

    算法 1 字符串模式匹配问题 2 排列组合问题 3 查找排序问题 数据结构 B树(B,B*,B+,红黑树)和二叉树的区别,MAP,hashmap, JAVA: 线程sleep,wait,wake(), ...

  5. Keywords Search - HDU 2222(AC自动机模板)

    题目大意:输入几个子串,然后输入一个母串,问在母串里面包含几个子串.   分析:刚学习的AC自动机,据说这是个最基础的模板题,所以也是用了最基本的写法来完成的,当然也借鉴了别人的代码思想,确实是个很神 ...

  6. Spring 3.x企业应用开发实战(9-1)----依赖注入

    Spring中的依赖注入方式:属性注入.构造函数注入和工厂方式注入. 1.属性注入 属性注入即通过setXxx()方法注入Bean的属性值或依赖对象. 属性注入要求Bean提供一个默认的构造函数,在J ...

  7. HDU1700:Points on Cycle

    Problem Description There is a cycle with its center on the origin. Now give you a point on the cycl ...

  8. 1.1GTK+ 的简单程序HelloWorld

    1.1GTK+ 的简单程序HelloWorld 编译执行如图所看到的:

  9. Swift-Dictionary

    1.字典写法 Dictionary<KeyType,ValueType>,KeyType是你想要储存的键,ValueType是你想要储存的值. 唯一的限制就是KeyType必须是可哈希的, ...

  10. 严苛模式(StrictMode)

    Android 2.3提供一个称为严苛模式(StrictMode)的调试特性,Google称该特性已经使数百个Android上的Google应用程序受益.那它都做什么呢?它将报告与线程及虚拟机相关的策 ...