项目介绍
java 开发中,参数校验对错常常见的需求。可是 hibernate-validator 在运用过程中,仍然会存在一些问题。
validator 在 hibernate-validator 等校验东西之上,做了一些改进,使其运用愈加便捷优雅,进一步提高工作效率。
改变日志
改变日志
特性
-
支撑 fluent-validation
-
支撑 jsr-303 注解
-
支撑 i18n
-
支撑用户自界说战略
-
支撑用户自界说注解
-
支撑针对特点的校验
-
支撑过程式编程与注解式编程
-
支撑指定校验收效的条件
创造目的
hibernate-validator 无法满意的场景
现在 java 最盛行的 hibernate-validator 结构,可是有些场景是无法满意的。
比如:
-
验证新暗码和承认暗码是否相同。(同一目标下的不同特点之间联系)
-
当一个特点值满意某个条件时,才进行其他值的参数校验。
-
多个特点值,至少有一个不能为 null
其实,在关于多个字段的关联联系处理时,hibernate-validator 就会比较弱。
本项目结合原有的长处,进行这一点的功用强化。
validation-api 过于杂乱
validation-api 供给了丰厚的特性界说,也同时带来了一个问题。
完成起来,特别杂乱。
可是咱们实际运用中,常常不需要这么杂乱的完成。
validator-api 供给了一套简化很多的 api,便于用户自行完成。
自界说缺少灵敏性
hibernate-validator 在运用中,自界说束缚完成是根据注解的,针对单个特点校验不够灵敏。
本项目中,将特点校验束缚和注解束缚区分开,便于复用和拓宽。
过程式编程 vs 注解式编程
hibernate-validator 中心支撑的是注解式编程,根据 bean 的校验。
一个问题是针对特点校验不灵敏,有时候针对 bean 的校验,还是要自己写判别。
本项目支撑 fluent-api 进行过程式编程,同时支撑注解式编程。
尽可能兼顾灵敏性与便利性。
快速开端
准备工作
JDK1.7+
Maven 3.X+
maven 引进
<dependency>
<groupId>com.github.houbb</groupId>
<artifactId>validator-core</artifactId>
<version>0.4.0</version>
</dependency>
快速入门
界说目标
第一步,咱们界说一个常见的 java bean 目标,可以指定内置的注解。
支撑 jsr-303 注解和 hibernate-validator 的注解。
public class User {
/**
* 称号
*/
@HasNotNull({"nickName"})
private String name;
/**
* 昵称
*/
private String nickName;
/**
* 原始暗码
*/
@AllEquals("password2")
private String password;
/**
* 新暗码
*/
private String password2;
/**
* 性别
*/
@Ranges({"boy", "girl"})
private String sex;
/**
* 失败类型枚举
*/
@EnumRanges(FailTypeEnum.class)
private String failType;
//getter & setter
}
ValidHelper 东西办法
ValidHelper 作为一致封装的东西类,供给了 java bean 校验常见的办法。
办法列表:
序号 | 办法 | 回来值 | 阐明 |
---|---|---|---|
1 | failOver(Object object) | IResult | 悉数验证后回来 |
2 | failFast(Object object) | IResult | 快速验证后回来 |
3 | failOverThrow(Object object) | void | 悉数验证后回来-未经过抛出 ValidRuntimeException 反常 |
4 | failFastThrow(Object object) | void | 快速验证后回来-未经过抛出 ValidRuntimeException 反常 |
运用起来很简单,咱们以 failFast 为例:
// 目标界说
User user = new User();
user.sex("what").password("old").password2("new");
// 调用办法
IResult result = ValidHelper.failFast(user);
成果:
DefaultResult{pass=false, notPassList=[DefaultConstraintResult{pass=false, message='name: 值 <null> 不是预期值', value=null, constraint='HasNotNullConstraint', expectValue='', fieldName='name'}], allList=null}
- IResult 办法阐明
回来值完成默认为 DefaultResult,接口 IResult 特点如下:
public interface IResult {
/**
* 是否悉数经过验证
* @return 是否
* @since 0.1.0
*/
boolean pass();
/**
* 未经过的列表信息
* @return 验证成果
* @since 0.1.0
*/
List<IConstraintResult> notPassList();
/**
* 一切的验证成果列表
* @return 一切的验证成果
* @since 0.1.0
*/
List<IConstraintResult> allList();
/**
* 输出信息到控台
* (1)主要是为了便利调整
* (2)该功用其实可以做增强,比如输出到文件/数据库等等。
* @return this
* @since 0.0.6
*/
IResult print();
/**
* 关于未经过的信息,
* (1)未经过的界定。
* {@link IConstraintResult#pass()} 为 false
*
* (2)内容信息
* 抛出运行时反常 {@link com.github.houbb.validator.api.exception.ValidRuntimeException},反常信息为 {@link IConstraintResult#message()} 音讯
* (3)内容限定
* 为了防止反常内容过多,只抛出第一条即可。
* (4)改办法的增强空间
* 4.1 可以指定什么情况下抛出反常
* 4.2 抛出反常的信息和类别
*
* @return this
* @since 0.0.6
*/
IResult throwsEx();
}
注解阐明
java bean 的校验,根据注解是比较便利的。和 hibernate-validator 运用相似,这里介绍下常见的注解。
内置束缚注解
内置注解如下:
序号 | 注解 | value() | 阐明 |
---|---|---|---|
1 | @AllEquals |
String[] |
当时字段及其指定的字段 悉数持平 |
2 | @EnumRanges |
Class<? extends Enum> |
当时字段必须在枚举值指定的范围内 |
3 | @HasNotNull |
String[] |
当时字段及其指定的字段 至少有一个不为 null |
4 | @Ranges |
String[] |
当时字段必须在指定的范围内 |
JSR-303 + hibernate-validator 束缚注解支撑
序号 | 注解 | 阐明 |
---|---|---|
1 | @AssertTrue |
为 true 束缚条件 |
2 | @AssertFalse |
为 false 束缚条件 |
3 | @Null |
为 null 束缚条件 |
4 | @NotNull |
不为 null 束缚条件 |
5 | @Past |
是否在当时时刻之前束缚条件 |
6 | @Future |
是否在当时时刻之后束缚条件 |
7 | @Pattern |
正则表达式束缚条件 |
8 | @Size |
在指定范围内的束缚条件 |
9 | @Digits |
数字位数的束缚条件 |
10 | @DecimalMax |
最大数字的束缚条件 |
11 | @DecimalMin |
最小数字的束缚条件 |
12 | @Min |
最小的束缚条件 |
13 | @Max |
最大的束缚条件 |
13 | @NotBlank |
不能为空格的束缚条件 |
14 | @NotEmpty |
不能为空的束缚条件 |
15 | @Length |
长度的束缚条件 |
16 | @CNPJ |
CNPJ 束缚条件 |
17 | @CPF |
CPF 束缚条件 |
18 | @URL |
URL 束缚条件 |
18 | @Email |
Email 束缚条件 |
19 | @UniqueElements |
元素仅有束缚条件 |
20 | @Range |
指定范围元素束缚条件 |
条件注解
阐明
有时候咱们需要根据不同的参数,进行不同的束缚条件。
比如新建时用户 id 不需要传入,可是修改时 id 必填。
如果是传统的 hibernate-validator 处理就会比较麻烦,此处引进条件注解。
内置注解
序号 | 注解 | 阐明 |
---|---|---|
1 | @EqualsCondition |
等于指定值的条件 |
2 | @NotEqualsCondition |
不等于指定值的条件 |
3 | @AlwaysTrueCondition |
永久收效的条件 |
4 | @AlwaysFalseCondition |
永久不收效的条件 |
运用
运用起来也不难,下面的作用如下:
- operType == ‘create’ 时,name 的校验才会收效。
- operType != ‘create’ 时,id 的校验才会收效。
其他运用方式保持不变。
public class ConditionUser {
/**
* 操作类型
*/
@Ranges({"create", "edit"})
private String operType;
/**
* 新建时,name 必填
*/
@EqualsCondition(value = "create", fieldName = "operType")
@Size(min = 3)
@NotNull
private String name;
/**
* 不是新建时, id 字段必填
*/
@NotEqualsCondition(value = "create", fieldName = "operType")
@Size(min = 16)
private String id;
//getter & setter
}
过程式接口
阐明
日常开发中,咱们都很喜爱运用注解对 java bean 进行校验。
可是这回导致咱们界说的单个特点校验无法复用。
所以项目中的单个特点校验和注解是一一对应的,为了便于复用。
ValidHelper 办法
ValidHelper 作为一致封装的东西类,供给单个办法校验常见的办法。
和 java bean 相似,办法列表:
序号 | 办法 | 回来值 | 阐明 |
---|---|---|---|
1 | failOver(Object object, IConstraint constraint) | IResult | 悉数验证后回来 |
2 | failFast(Object object, IConstraint constraint) | IResult | 快速验证后回来 |
3 | failOverThrow(Object object, IConstraint constraint) | void | 悉数验证后回来-未经过抛出 ValidRuntimeException 反常 |
4 | failFastThrow(Object object, IConstraint constraint) | void | 快速验证后回来-未经过抛出 ValidRuntimeException 反常 |
运用比如
用法和 bean 的相似,只是入参多了第二个束缚条件。
IResult result = ValidHelper.failFast("", Constraints.notEmptyConstraint());
IConstraint 对应联系
注解和常见的接口办法一一对应,一切的束缚办法在 Constraints
东西类中。
序号 | 注解 | 阐明 | 对应办法 |
---|---|---|---|
1 | @AssertTrue |
为 true 束缚条件 | assertTrueConstraint |
2 | @AssertFalse |
为 false 束缚条件 | assertFalseConstraint |
3 | @Null |
为 null 束缚条件 | nullConstraint |
4 | @NotNull |
不为 null 束缚条件 | notNullConstraint |
5 | @Past |
是否在当时时刻之前束缚条件 | pastConstraint |
6 | @Future |
是否在当时时刻之后束缚条件 | futureConstraint |
7 | @Pattern |
正则表达式束缚条件 | patternConstraint |
8 | @Size |
在指定范围内的束缚条件 | sizeConstraint |
9 | @Digits |
数字位数的束缚条件 | digitsConstraint |
10 | @DecimalMax |
最大数字的束缚条件 | decimalMaxConstraint |
11 | @DecimalMin |
最小数字的束缚条件 | decimalMinConstraint |
12 | @Min |
最小的束缚条件 | minConstraint |
13 | @Max |
最大的束缚条件 | maxConstraint |
13 | @NotBlank |
不能为空格的束缚条件 | notBlankConstraint |
14 | @NotEmpty |
不能为空的束缚条件 | notEmptyConstraint |
15 | @Length |
长度的束缚条件 | lengthConstraint |
16 | @CNPJ |
CNPJ 束缚条件 | cnpjConstraint |
17 | @CPF |
CPF 束缚条件 | cpfConstraint |
18 | @URL |
URL 束缚条件 | urlConstraint |
18 | @Email |
Email 束缚条件 | emailConstraint |
19 | @UniqueElements |
元素仅有束缚条件 | uniqueElementsConstraint |
20 | @Range |
指定范围元素束缚条件 | rangeConstraint |
21 | @AllEquals |
当时字段及其指定的字段 悉数持平 | allEqualsConstraint |
22 | @EnumRanges |
当时字段必须在枚举值指定的范围内 | enumRangesConstraint |
23 | @HasNotNull |
当时字段及其指定的字段 至少有一个不为 null | hasNotNullConstraint |
24 | @Ranges |
当时字段必须在指定的范围内 | rangesConstraint |
条件注解
注解和常见的接口办法一一对应,一切的束缚办法在 Conditions
东西类中。
序号 | 注解 | 阐明 | 对应办法 |
---|---|---|---|
1 | @EqualsCondition |
等于指定值的条件 | equalsCondition |
2 | @NotEqualsCondition |
不等于指定值的条件 | notEqualsCondition |
3 | @AlwaysTrueCondition |
永久收效的条件 | alwaysTrueCondition |
4 | @AlwaysFalseCondition |
永久不收效的条件 | alwaysFalseCondition |
注解自界说
阐明
内置的注解,天然无法满意一切的场景。
本项目中,束缚和条件注解都是支撑自界说的。
束缚注解 @Constraint
一切体系的内置注解都可以作为学习的比如。
界说注解
以 @AllEquals
为例,中心的部分在 @Constraint(AtAllEqualsConstraint.class)
。
咱们在 AtAllEqualsConstraint 中完成详细的束缚逻辑。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(AtAllEqualsConstraint.class)
public @interface AllEquals {
/**
* 当时字段及其指定的字段 悉数持平
* 1. 字段类型及其他字段相同
* @return 指定的字段列表
*/
String[] value();
/**
* 提示音讯
* @return 过错提示
*/
String message() default "";
/**
* 分组信息
* @return 分组类
* @since 0.1.2
*/
Class[] group() default {};
}
完成逻辑
引荐直接承继 AbstractAnnotationConstraint<A>
,完成对应的逻辑即可。
public class AtAllEqualsConstraint extends AbstractAnnotationConstraint<AllEquals> {
@Override
protected IConstraint buildConstraint(AllEquals annotation) {
return Constraints.allEqualsConstraint(annotation.value());
}
}
条件注解 @Condition
一切体系的内置注解都可以作为学习的比如。
界说注解
以 @AlwaysTrueCondition
为例,中心的部分在 @Condition(AtAlwaysTrueCondition.class)
。
咱们在 AtAlwaysTrueCondition 中完成详细的束缚逻辑。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Condition(AtAlwaysTrueCondition.class)
public @interface AlwaysTrueCondition {
}
完成逻辑
引荐直接承继 AbstractAnnotationCondition<A>
,完成对应的逻辑即可。
public class AtAlwaysTrueCondition extends AbstractAnnotationCondition<AlwaysTrueCondition> {
@Override
protected ICondition buildCondition(AlwaysTrueCondition annotation) {
return Conditions.alwaysTrueCondition();
}
}
开源地址
为了便于我们学习运用,现在校验结构已开源。
欢迎我们 fork+star,鼓舞一下老马~
validator