创建自己的约束规则

尽管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. GitHub超详细图文攻略 - Git客户端下载安装 GitHub提交修改源码工作流程 Git分支 标签 过滤 Git版本工作流

    最近听同事说他都在使用GitHub,GitHub是程序员的社区,在里面可以学到很多书上学不到的东西,所以最近在准备入手这方面的知识去尝试学习,正好碰到这么详细完整的文章,就转载了,希望对自己和大家有帮 ...

  2. WordPress Duplicator 0.4.4 Cross Site Scripting

    测试方法: 提供程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负! Advisory ID: HTB23162 Product:DuplicatorWordPressPlugin Vend ...

  3. SVN服务器搭建(与apache整合)

    一.SVN介绍 SVN是一个版本控制工具,Subversion的版本库(repository),就是位于服务器,统一管理和储存数据的地方. 二.SVN数据存储方式 在Subversion中,版本库的数 ...

  4. 【树形动规】HDU 5834 Magic boy Bi Luo with his excited tree

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5834 题目大意: 一棵N个点的有根树,每个节点有价值ci,每条树边有费用di,节点的值只能取一次,边 ...

  5. HDOJ(HDU) 2503 a/b + c/d(最大公约数问题)

    Problem Description 给你2个分数,求他们的和,并要求和为最简形式. Input 输入首先包含一个正整数T(T<=1000),表示有T组测试数据,然后是T行数据,每行包含四个正 ...

  6. 【模拟】Class 解题报告

    [问题描述] 信息班这期的课将要结束了,老师要从现在班上的同学中选出比较优秀的同学进入下一期的学习.而录取标准则是将平时作业和考试一起考虑,综合成绩排在前面的则录取.经过一番思考,老师作了以下的筛选计 ...

  7. 【数学】【NOIp2012】同余方程 题解 以及 关于扩展欧几里得与同余方程

    什么是GCD? GCD是最大公约数的简称(当然理解为我们伟大的党也未尝不可).在开头,我们先下几个定义: ①a|b表示a能整除b(a是b的约数) ②a mod b表示a-[a/b]b([a/b]在Pa ...

  8. Threading Module源码概述(一)

    Python的Threading模块是建立在thread module基础上的一个模块,在threading模块中,暴露着许多thread模块的属性.比如threading._get_ident实际上 ...

  9. Docker网络模式

    [编者的话] 本文是<Docker网络及服务发现>一书的一个章节,介绍了搭建Docker单主机网络的基础内容.关于Docker网络的更多内容,包括多主机的网络,请参考该书的其他章节. @C ...

  10. 【.NET调用Python脚本】C#调用python requests类库报错 'module' object has no attribute '_getframe' - IronPython 2.7

    最近在开发微信公众号,有一个自定义消息回复的需求 比如用户:麻烦帮我查询一下北京的天气? 系统回复:北京天气,晴,-℃... 这时候需要根据关键字[北京][天气],分词匹配需要执行的操作,然后去调用天 ...