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的更多相关文章
随机推荐
- HTML入门教程(全套)
http://www.rm5u.com/html_html.html http://learn.shayhowe.com/ moe.mwulu.com http://www.w3school.co ...
- delphi XML 原来可以玩接口
以下代码旨在 脱离TXMLDocument 操作 xml unit Unit3; interface uses Windows, Messages, SysUtils, Variants, Class ...
- 两个div之间有空隙
加句*{ margin:0; padding:0;} 最近在做网页时发现,在IE7下(FF没试过),div与div之间有时会出20个像素左右的空隙,除非把margin设成负值,否则空隙无法去除.我在 ...
- 如何使用json在前后台进行数据传输
上一篇博客写到用javascript生成多组文本,可以让数据的输入不受显示,现在我们需要把这些输入写入数据库,这里就用到json传入. 首先,我们来写一下后台如何生成要传输的数据 function g ...
- 【HDOJ】2364 Escape
bfs.题目做的不细心,好多小错误.尤其注意起始点就是边界的情况.wa了八次. #include <iostream> #include <cstdio> #include & ...
- awk文本处理--二维数组使用一例
群友出的题: 原始文件: $ cat fileBJ30 26BJ30 24BJ30 63BJ30 70SH41 21SH41 30SH41 25SH41 25SH41 29SD15 34SD15 46 ...
- 数据结构(堆):POJ 1442 Black Box
Black Box Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 10658 Accepted: 4390 Descri ...
- Evaluate Reverse Polish Notation——LeetCode
Evaluate the value of an arithmetic expression in Reverse Polish Notation. Valid operators are +, -, ...
- poj 2031 Building a Space Station【最小生成树prime】【模板题】
Building a Space Station Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 5699 Accepte ...
- Beautiful Numbers
http://codeforces.com/problemset/problem/300/C 题意:给你三个数a,b,n;求满足由a,b组成的n位的个数,且每个位置上的数之和也是用a,b组成; 解析: ...