Coder Social home page Coder Social logo

houbb / validator Goto Github PK

View Code? Open in Web Editor NEW
45.0 4.0 9.0 270 KB

🚥Fluent-validation framework for java extend from hibernate-validator.(java 对象属性流式验证框架,下一代校验框架。兼容实现 jakarta bean validation、jsr 303、hibernate-validator)

License: Other

Batchfile 0.64% Shell 0.95% Java 98.41%
hibernate-validator parameter validator jakartaee jsr303-bean-validation valid

validator's Introduction

项目介绍

java 开发中,参数校验是非常常见的需求。但是 hibernate-validator 在使用过程中,依然会存在一些问题。

validator 在 hibernate-validator 等校验工具之上,做了一些改进,使其使用更加便捷优雅,进一步提升工作效率。

Maven Central Open Source Love Build Status Coverage Status

变更日志

变更日志

特性

  • 兼容实现 jakarta bean validation(jsr-303)内置注解

  • 兼容实现 hibernate-validation

  • 支持 i18n

  • 支持用户自定义策略

  • 支持用户自定义注解

  • 支持针对属性的校验

  • 支持过程式编程与注解式编程

  • 支持指定校验生效的条件

创作目的

hibernate-validator 无法满足的场景

如今 java 最流行的 hibernate-validator 框架,但是有些场景是无法满足的。

比如:

  1. 验证新密码和确认密码是否相同。(同一对象下的不同属性之间关系)

  2. 当一个属性值满足某个条件时,才进行其他值的参数校验。

  3. 多个属性值,至少有一个不能为 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.7.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 全部验证后返回-未通过抛出异常
4 failFastThrow(Object object) void 快速验证后返回-未通过抛出异常
5 failOver(Object object, IConstraint Constraint) IResult 全部验证后返回,属性校验
6 failFast(Object object, IConstraint Constraint) IResult 快速验证后返回,属性校验
7 failOverThrow(Object object, IConstraint Constraint) void 全部验证后返回-未通过抛出异常,属性校验
8 failFastThrow(Object object, IConstraint Constraint) void 快速验证后返回-未通过抛出异常,属性校验
9 failOver(Object object, IConstraint Constraint, String message) IResult 全部验证后返回,属性校验,message 为报错信息
10 failFast(Object object, IConstraint Constraint, String message) IResult 快速验证后返回,属性校验,message 为报错信息
11 failOverThrow(Object object, IConstraint Constraint, String message) void 全部验证后返回-未通过抛出异常,属性校验,message 为报错信息
12 failFastThrow(Object object, IConstraint Constraint, String message) void 快速验证后返回-未通过抛出异常,属性校验,message 为报错信息

使用起来很简单,我们以 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[] 当前字段必须在指定的范围内
4 @Ranges String[] 当前字段必须在指定的范围内
5 @ChinaPhone **手机号校验
6 @ChinaIdNo **身份证校验

JSR-303 / jakarta bean validation 约束注解支持

jakarta-bean-validation-spec-3.0

序号 注解 说明
1 @AssertTrue 为 true 约束条件
2 @AssertFalse 为 false 约束条件
3 @Null 为 null 约束条件
4 @NotNull 不为 null 约束条件
5 @Past 是否在当前时间之前约束条件
6 @PastOrPresent 是否在当前时间之前约束条件,包含当前
7 @Future 是否在当前时间之后约束条件
8 @FutureOrPresent 是否在当前时间之后约束条件,包含当前
9 @Pattern 正则表达式约束条件
10 @Size 在指定范围内的约束条件
11 @Digits 数字位数的约束条件
12 @DecimalMax 最大数字的约束条件
13 @DecimalMin 最小数字的约束条件
14 @Min 最小的约束条件
15 @Max 最大的约束条件
16 @NotBlank 不能为空格的约束条件
17 @NotEmpty 不能为空的约束条件
18 @Email Email 约束条件
19 @Negative 指定值必须为负数约束条件
20 @NegativeOrZero 指定值必须为负数约束条件,包含0
21 @Positive 指定值必须为正数约束条件
22 @PositiveOrZero 指定值必须为正数约束条件,包含0

hibernate-validator 约束注解支持

hibernate-validator 内置注解

实现了常见的几个,后续将陆续完善:

序号 注解 说明
1 @NotBlank 不能为空格的约束条件
2 @NotEmpty 不能为空的约束条件
3 @Length 长度的约束条件
4 @URL URL 约束条件
5 @Email Email 约束条件
6 @UniqueElements 元素唯一约束条件
7 @Range 指定范围元素约束条件

条件注解

说明

有时候我们需要根据不同的参数,进行不同的限制条件。

比如新建时用户 id 不需要传入,但是修改时 id 必填。

如果是传统的 hibernate-validator 处理就会比较麻烦,此处引入条件注解。

内置注解

序号 注解 说明
1 @EqualsCondition 等于指定值的条件
2 @NotEqualsCondition 不等于指定值的条件
3 @AlwaysTrueCondition 永远生效的条件
4 @AlwaysFalseCondition 永远不生效的条件

使用

使用起来也不难,下面的效果如下:

  1. operType == 'create' 时,name 的校验才会生效。
  2. 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.notEmpty());

IConstraint 对应关系

注解和常见的接口方法一一对应,所有的约束方法在 Constraints 工具类中。

JSR-303 / jakarta bean validation 约束注解支持

序号 注解 说明 对应方法
1 @AssertTrue 为 true 约束条件 assertTrue()
2 @AssertFalse 为 false 约束条件 assertFalse()
3 @Null 为 null 约束条件 nulls()
4 @NotNull 不为 null 约束条件 notNulls()
5 @Past 是否在当前时间之前约束条件 past()
6 @PastOrPresent 是否在当前时间之前约束条件,包含当前 pastOrPresent()
7 @Future 是否在当前时间之后约束条件 future()
8 @FutureOrPresent 是否在当前时间之后约束条件,包含当前 futureOrPresent()
9 @Pattern 正则表达式约束条件 pattern()
10 @Size 在指定范围内的约束条件 size()
11 @Digits 数字位数的约束条件 digits()
12 @DecimalMax 最大数字的约束条件 decimalMax()
13 @DecimalMin 最小数字的约束条件 decimalMin()
14 @Min 最小的约束条件 min()
15 @Max 最大的约束条件 max()
16 @NotBlank 不能为空格的约束条件 notBlank()
17 @NotEmpty 不能为空的约束条件 notEmpty()
18 @Email Email 约束条件 email()
19 @Negative 指定值必须为负数约束条件 negative()
20 @NegativeOrZero 指定值必须为负数约束条件,包含0 negativeOrZero()
21 @Positive 指定值必须为正数约束条件 positive()
22 @PositiveOrZero 指定值必须为正数约束条件,包含0 positiveOrZero()

## hibernate-validator 约束注解支持

实现了常见的几个,后续将陆续完善:

序号 注解 说明 对应方法
1 @NotBlank 不能为空格的约束条件 notBlank()
2 @NotEmpty 不能为空的约束条件 notEmpty()
5 @Email Email 约束条件 email()
3 @Length 长度的约束条件 length()
4 @URL URL 约束条件 url()
6 @UniqueElements 元素唯一约束条件 uniqueElements()
7 @Range 指定范围元素约束条件 range()

条件注解

注解和常见的接口方法一一对应,所有的约束方法在 Conditions 工具类中。

序号 注解 说明 对应方法
1 @EqualsCondition 等于指定值的条件 equals()
2 @NotEqualsCondition 不等于指定值的条件 notEquals()
3 @AlwaysTrueCondition 永远生效的条件 alwaysTrue()
4 @AlwaysFalseCondition 永远不生效的条件 alwaysFalse()

注解自定义

说明

内置的注解,自然无法满足所有的场景。

本项目中,约束和条件注解都是支持自定义的。

约束注解 @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.allEquals(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.alwaysTrue();
    }

}

开源地址

为了便于大家学习使用,目前校验框架已开源。

欢迎大家 fork+star,鼓励一下老马~

validator

ROAD-MAP

  • 优化提示信息

  • springboot 整合

  • i18N 對應的描述信息

  • 更多约束条件

phone

idNo

银行卡

validator's People

Contributors

houbb avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

validator's Issues

单纯使用ValidHelper,如何处理原始的注解,例如@NotNull?

User 就是validator-test中的User类,做了如下改动:
//@HasNotNull({"nickName"})
private String name;
@NotNull
private String nickName;

User user = new User();

IResult iResult = ValidHelper.failFast(user);

//返回:{javax.validation.constraints.NotNull.message}
String message = iResult.notPassList().get(0).message();

返回是@NotNull的message信息,不是处理后的

有没有考虑过这玩 类似json schema不过是用注解的表述方式

`import java.lang.annotation.Annotation;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;

public class ValidX {

public interface IValidator {
	/**
	 * 
	 * @param root
	 * @param ruleIdent 通过外部规则文件处理
	 * @param groups
	 */
	void valid(Object root, String ruleIdent, Class<?> ... groups);
	/**
	 * 
	 * @param root
	 * @param equityClass  对等规则类型  如果第三方类不方便修改 可以自己定义一个对等的
	 * @param class2
	 */
	void valid(Object root, Class<A> equityClass,  Class<?> ... groups);
}

public interface IValidMetaDataProvider {

	 List<ValidMetaData> getTopValidMetaData(String rootRuleIdent, Class<?> ... groups)  ;
	 
	 List<ValidMetaData> getAttrValidMetaData(String rootRuleIdent,String attrPath, Class<?> ... groups)  ;
	 //通过指定注释名称 和属性值 构建一个注解对象实例 
	 //让通过配置配置的规则和直接写在类上的注解一致
	 <A extends Annotation > A  pretendAnnotation(Class<A> annotationType,Map<String,Object> annotationValues);
}

public interface ValidMetaData {

	Annotation getRuleAnnotation();

}
public interface ValidGroupA {
	
}
public interface ValidGroupB {
	
}
class Cxt{
	
}

 
class IValidatorImpl implements IValidator{
	IValidMetaDataProvider validMetaDataProvider;
	
	@Override
	public void valid(Object root, String ruleIdent, Class<?>... groups) {
		 //定级规则  对应 class 上的验证规则
		 Cxt  cxt = new Cxt();
		 List<ValidMetaData>  topRules = validMetaDataProvider.getTopValidMetaData(ruleIdent, groups);
		 for (ValidMetaData validMetaData : topRules) {
			  exec(root,validMetaData,cxt);
		 }
		 //对应属性上的规则
		 List<String > attrs = getAttrs(root);
		 for (String attrPath : attrs) {
			 Object value = getAttrValue(root,attrPath);
			 List<ValidMetaData>  lis= validMetaDataProvider.getAttrValidMetaData(  ruleIdent,  attrPath,   groups)  ;
			 for (ValidMetaData validMetaData : lis) {
				  exec(root,attrPath,value,validMetaData,cxt);
			 }
		}
	}
	private void exec(Object root, String attrPath, Object value, ValidMetaData validMetaData, Cxt cxt) {
		 
		
	}
	private Object getAttrValue(Object object, String attrPath) {
		 
		return null;
	}
	private void exec(Object object, ValidMetaData validMetaData, Cxt cxt) {
		java.lang.annotation.Annotation annotation = validMetaData.getRuleAnnotation();
		 
		
	}
	@Override
	public void valid(Object root, Class<A> equityClass, Class<?>... groups) {
		// TODO Auto-generated method stub
		
	}
	
}

 
   
  
   class A{
		  @Min(value = 1L)
		  @Max(value = 100L)
		  Integer intVal;
	  }
   
void valid() {
	 IValidator validator  =newValidator();
	 IValidMetaDataProvider validMetaDataProvider = null ;
     Map<String,Object> obj  = new HashMap<String, Object>();
     obj.put("intVal", 1);
     /*
      * 验证规则标识 :{
	        intVal:[
	        { 
	            ann:"jakarta.validation.constraints.Min",
	             attrs:{value:1L}
	        },{
	          ann:"jakarta.validation.constraints.Max",
	           attrs:{value:100L}
	         }
	         ]
         }
      * 
      */
     validator.valid(obj,"验证规则标识",ValidGroupA.class);
    
     validator.valid(obj,A.class,ValidGroupA.class);
     
}
public List<String> getAttrs(Object object) {
	 
	return null;
}
private IValidator newValidator() {
	 
	return null;
}

}
`

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.