5 Star 33 Fork 5

藏经阁 / chungkui

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
README.md 17.05 KB
一键复制 编辑 原始数据 按行查看 历史
jason 提交于 2021-04-20 23:06 . commit message

钟馗

介绍

钟馗是一款java数据校验框架,支持注解式数据校验,可以对系统中的各种接口,请求进行,入参校验,流控,防重等校验。 同时支持运行时动态改变校验规则;和spring注解式数据校验的区别是,校验规则纯文本化,方便校验逻辑集中在一处进行配置管理, 更像是一种语法糖 。 目前支持的校验模式有spring mvc模式,方法单个map入参模式,方法单个json入参模式,方法列表模式等等 ; 在当下前后端分离,微服务,api接口越来越常见的背景下,希望你会喜欢这样一款校验插件;

首先我不建议你直接读文档,建议你下载下来项目,运行demo中的applicat#main 访问:127.0.0.1:8080 体验下使用钟馗的方式和效果,看看是否喜欢,然后决定是否继续读文档

一、如何使用:

可以参考demo项目

第一步:初始化

引入jar包

   <dependency>
               <groupId>com.chungkui</groupId>
               <artifactId>check</artifactId>
               <version>0.0.7.2-RELEASE</version>
    </dependency>

1.实现AbstractCheckConfigCacheService,2.继承ChungkuiCheckConfig类并把bean注入spring容器;例如注解式配置如下(xml模式同理):

public class CheckConfigCacheServiceImpl extends AbstractCheckConfigCacheService {
   
   public void change() {
           clear();
   }

   @Override
   public String remoteGet(String s, String s1) {
       return null;
   }
}
@Configuration
public class CheckConfig extends ChungkuiCheckConfig {
   @Bean
   ExpressionsCacheService expressionsCacheService() {
       return new CheckConfigCacheServiceImpl();
   }

}

第二步:配置校验规则

在方法上面加上@Check注解,配置格式为json;如下:


public class controller {
     @Check({"{rule:'long(a)+long(b)>0',msg:{fail:'不通过',error:'数据格式不正确'},code:'500'}"
	 ,"{param:'a',type:'int',min:1,max:2,msg:'int不通过'}"})
     @RequireMaping
     public Object methodName(){
         return "jason";
     }
}

二、校验规则具体配置方法

有两种配置方式:

a.通过注解配置项value

该配置项为一个数组。每个参数是数组的一个元素。方便复用校验配置

b.通过注解配置项rules

整个配置项为一个json字符串,复用性差。但是方便进行远程管理所有配置项。有问题时方便拷贝整个配置进行修改

1.表达式校验:aviator


@Check({"{condition:'str.isNotEmpty(a)',rule:'long(a)>long(b)',msg:{fail:'校验不通过',error:'数字格式不正确'},code:500}"})

配置项含义:

key 描述
type 校验类型不配置表示aviator
rule 表达式具体配置方式参考官网
min 最小长度
max 最大长度
msg 校验失败提醒
code 失败编码
condition 触发条件,当表达式为true时才会校验

提示项含义

配置方法为把msg配置为json格式,如下。

@Check({"{rule:'long(a)>long(b)',msg:{fail:'校验不通过',error:'数字格式不正确'},code:500}"})
key 描述 default
fail 校验不通过
error 数据格式不正确报错

2.非空校验:require

@Check({"{type:'require',min:1,max:2,param:'c',msg:'require不通过'}"})
 

配置项含义:

key 描述
type 校验类型
rule 校验规则
param 参数名
min 最小长度
max 最大长度
msg 校验失败提醒
code 失败编码
condition 触发条件,当表达式为true时才会校验

智能提示

配置方法为把msg配置为json格式,如下。

@Check({"{type:'require',min:1,max:2,param:'c',msg:{min:'长度不可小于1',max:'长度不可大于20',null:'不可以为空值'}}"})
key 描述 default
min 最小值不满足提示 最小值超限
max 最大值不满足提示 最大值超限
null 格式不满足提示 参数必填

3.数字校验:int/double/long

规则格式

@Check({ "{type:'int/double/long',min:1,max:2,param:'a',msg:'int不通过'}"})

配置项含义:

key 描述
min 最小值
rule 校验规则
max 最大值
msg 校验失败提醒
code 失败编码
require 是否必填,true时候校验必填,fasle如果为空则不会校验值是否合法
condition 触发条件,当表达式为true时才会校验

智能提示

配置方法为把msg配置为json格式,如下。


@Check({ "{type:'int/double/long',min:1,max:2,param:'paramName',msg:{min:'不可小于1',max:'不可大于20',fai:'数字不合法'}}"})
key 描述 default
min 最小值不满足提示 最小值超限
max 最大值不满足提示 最大值超限
fail 格式不满足提示 参数不合法

4.json数组校验:jsonArray

@Check({"{type:'jsonArray',min:1,max:2,param:'c',msg:'require不通过'}"})

配置项含义:

key 描述
type 校验类型
rule 校验规则
param 参数名
min 最小个数
max 最大个数
msg 校验失败提醒
code 失败编码
condition 触发条件,当表达式为true时才会校验

智能提示

配置方法为把msg配置为json格式,如下。


@Check({"{type:'jsonArray',min:1,max:2,param:'c',msg:{min:'长度不可小于1',max:'长度不可大于20',null:'不可以为空值'}}"})
key 描述 default
min 最小值不满足提示 元素个数不足
max 最大值不满足提示 元素个数超限
null 格式不满足提示 参数必填

5.日期校验:date

@Check({"{type:'date',fmt:'yyyyMMdd HHmmss',before:2,after:3,param:'startTime',msg:'日期非法'}"})

配置项含义:

key 描述
type 校验类型
rule 校验规则
param 参数名
fmt 日期格式
before 早于当前时间毫秒数
after 晚于当前时间毫秒数
code 失败编码
condition 触发条件,当表达式为true时才会校验

6.日期跨度校验:dateInterval

@Check({"{type:'dateInterval',fmt:'yyyyMMdd HHmmss',maxInterval:2,minInterval:3,start:'startTime',end:'endTime',msg:{minInterval:'时间间隔太小',maxInterval:'时间间隔太长'}}"})

配置项含义:

key 描述
type 校验类型
start 开始时间参数名
end 结束时间参数名
require 是否必填
param 参数名
fmt 日期格式
maxInterval 最大跨度毫秒数
minInterval 最小跨度毫秒数
code 失败编码
condition 触发条件,当表达式为true时才会校验

6.防重校验

开启方式为

实现ReSumitWallCacheService接口实现。并注入spring中。推荐实现时使用redis.

例如:

@Service
public class ReSumitWallCacheServiceImpl implements ReSumitWallCacheService {
    @Override
    public boolean set(String s, String s1, int expire) {
        return CacheUtils.set(s, "01", expire, CacheUtils.ExPx.EX, CacheUtils.NxXx.NX);
    }
}

使用时配置项为reSubmitWall,配置格式如下。 调用方需要在入参中传入reSubmitWall(一个防重的token值,业务系统自发生成保证适当场景的唯一性。)

@Check(reSubmitWall = "{expire:2,prefix:'缓存前缀',msg:{null:'reSubmitWall不可传空',fail:'请勿重复提交'}}")

配置项含义:

key 描述
expire 防重token过期时间
msg 校验失败提醒
prefix token前缀,prefix=off表示关闭重复提交校验(开启配置中心时可用)

msg配置项含义:

key 描述
null token为空提醒
fail 重复提交提醒

6.单机版流控校验

配置方式为注解中的rateLimters项

@Check(rateLimters = {"{rate:1,msg:'流控',code:500}"})

配置项含义:

key 描述
rate 流控tps值
model 模式,动态:dynamic,静态:不配置
param 动态流控参数
sync 是否直接阻塞方式执行;true,false,默认为false;为true时直接阻塞直到获得令牌,慎用
warmupPeriod 从冷却状态到达最大速率所需时间(s)
waitLimit 取令牌等待(阻塞)时间(s)默认0;sync为false时候才有效;为 0的时候取不到令牌直接返回;
createRate 单位时间内动态流控对象生成速率
code 失败编码
msg 校验失败提醒
code 失败编码

7.集群版流控校验

配置方式为注解中的redisRateLimters项

    @Check(redisRateLimters={"{capacity:1,rate:1,perUser:1,msg:'您手速太快了,请稍后再试',code:500}"}

配置项含义:

key 描述
rate 流控tps值
param 动态流控参数
capacity 令牌桶容量
perUser 每次消耗令牌个数
code 失败编码
msg 校验失败提醒
code 失败编码

三、自定义msg格式

自定义格式注解配置项为msgTemp,格式必须为json,通过占位符的方式进行自定义 默认模板为{paramName:'#param',value:'#val',code:'#code',message:'#msg'}

例子:

@Check(msgTemp="{paramName:'#param',val:'#val',code:'#code',msg:'#msg'}")
描述
#param 入参名
#val 入参值
#code 失败编码
#msg 描述值

四、校验模式

目前支持三种校验模式mvc,mvc_html,args

默认的会自动探测校验模式,建议手动指定校验模式,效率更快。方法如下:

在注解中添加model项,可从枚举中获取支持的模式

 @Check(model = Model.MVC);
1.mvc模式:

校验request中的入参,校验失败无侵入代码直接响应json给客户端

2.mvc_html模式(不推荐):

校验request中的入参,校验失败,会缓存失败详情,可以通过如下方式获取校验结果,该种方式不会直接返回方法, 需要人工接收校验结果。使用场景是校验非ajax请求的场景

1.args模式:

从参数列表中取参数


boolean result=CheckResultContainer.check();//来在代码中获取是否校验通过;
Object msg=CheckResultContainer.getFailMsg();//来在代码中获取校验失败消息;

五、使用远程动态配置

使用远程配置,可以运行时修改校验规则,并且进行服务降级和流控等操作!(一般系统可能用不到的,可以不看)

如何配置:

自己继承AbstractExpressionsCacheService抽象类注入sping容器即可,实现remoteGet方法;获取远程配置需要你自己实现,这里返回远程配置的值即可;可以是从数据库查询的方式,或者配置中心获取的方式;

然后在你的配置改变之后请自行调用该bean类中的clear()方法;


public class DefaultExpressionsCacheServiceImpl extends AbstractExpressionsCacheService {
   @Override
     public String remoteGet(String s, String s1) {
                return  "返回数据库查询的值,或者配置中心的值即可";
     }
	 
	//当配置变化的时候自行调用clear()或者remoteSetCallBack(String remote, String val);
    public void remoteChange(String remote, String val) {
		//当配置变化的时候调用clear方法或者remoteSetCallBack清空或者刷新缓存
		clear();
    }
}

使用

a.注解上添加上remote配置项,指定远程的key,格式如下

@Check(remote="scm_validatekey"...)

b.然后你需要在你自己的服务中心(根据自己系统的实现做具体配置,可能是数据库配置,可能是配置中心配置),配置格式规则如下:和代码中配置类似,也是json格式

scm_validatekey={value:"[{type:'int/double/long',rule:{min:1,max:2,param:'a'},msg:{min:'不可小于1',max:'不可大于20',fail:'数字不合法'}}]"}

进行服务降级

同动态校验配置类似,在远端配置demoteConfig项即可

配置中心

scm_validatekey={demoteConfig:"{open:true,msg:'服务暂时不可使用请稍后重试',code:1000}"}

配置项含义

描述
open 是否开启降级,true表示开启
msg 降级触发拦截的时候的提示消息
code 降级触发拦截的时候的异常码

远程配置流控rateLimters

单机版

@Check(rateLimters = {"{rate:1,msg:'流控',code:500}"})

远程配置trafficControlConfig项即可

scm_validatekey={rateLimters : "{rate:100,param:'userName',msg:'流控命中服务暂时不可使用请稍后重试',code:10}"}

配置项含义

描述
rate 流控tps值
param 不为空表示根据参数动态流控,动态流控的时候会根据该参数进行动态流控
sync 是否直接阻塞方式执行;true,false,默认为false;为true时直接阻塞直到获得令牌,慎用
warmupPeriod 从冷却状态到达最大速率所需时间(s)
waitLimit 取令牌等待(阻塞)时间(s)默认0;sync为false时候才有效;为 0的时候取不到令牌直接返回;
code 失败编码
msg 校验失败提醒
code 失败编码

六、自定义流控

开启自定义流控

开启流控需要在spring 容器中实现TrafficControlService,并注入到spring容器中。

例如:

@Service
public class TrafficControlServiceImpl implements TrafficControlService {
    @Autowired
    private FlowControllerService flowControllerService;

    @Override
    public boolean check(String s) {
        return flowControllerService.check(s);
    }

    @Override
    public boolean dynamicCheck(String s, String s1) {
        return flowControllerService.dynamicCheck(s, s1);
    }
}

使用自定义流控

同动态校验配置类似,在配置中心配置项中添加trafficControlConfig;

在远程服务中配置

scm_validatekey={trafficControlConfig : "{key:'flow_control_key',param:'userName',msg:'流控命中服务暂时不可使用请稍后重试',code:1000}"}

配置项含义

描述
key 表示流控的配置中心key
param 不为空表示根据参数动态流控,动态流控的时候会根据该参数进行动态流控
msg 流控触发拦截的时候的提示消息
code 流控触发拦截的时候的异常码

七、参数为对象(json对象或者json数组等等)时的校验

可以对对象类型的数据中的字段进行校验;需要指定rules来进行校验,目前支持"(json),[json],javaBean,集合类型的对象等等"。 这里最初设计的时候我误入了一个误区,想要实现无限级嵌套,校验实现之后发现完全不好用,配置起来非常复杂。所以后来讨论后决定不做无限极嵌套, 如果你入参中对象深度较大。首先你应当考虑的是接口设计是否合理,如果必须这样做,那么建议你解析完成第一层后在另一个方法上做第二层的校验; 这样才是合理的。这是我折腾了很久之后想到的一点感悟;简单才是合理的。

(json)表示该对象是json对象[json]表示该对象是一个json数组 配置方式为:

//json对象
@Check(rules = "[{param:'userinfo',type:'(json)',msg:{error:'json格式不正确',null:'手机不可为空'},code:'500',rules:[{param:'username',type:'require',code:500,min:2,max:5,msg:{min:'手机名称太短',max:'手机名称太长',null:'不可为空'}}]}]")
//json数组
@Check(rules = "[{param:'param',type:'[json]',min:1,max:5,code:'500',msg:{min:'数组长度不足',max:'超长了',null:'数组不可为空'}, rules:[{param:'a',type:'require',min:2,max:5,msg:{min:'长度不足',max:'超长了',null:'不可为空'},code:500}]}]")

八、注意事项

ajax请求mvc的时候mvc返回值请使用Object,或者Map否则会出现类型转换异常

九、开发计划

开发辅助配置页面

十、架构:

默认规则引擎为aviator表达式引擎,另外提供必填和数字类型的定制化表达式引擎,定制化引擎支持更加完善的消息体系; 支持单个入参校验和多个参数之间进行表达式校验。 性能上通过把表达式预编译,放入LRU热点缓存的方式提高校验性能。

软件校验采用校验链的方式

校验链目前有四种。顺序分别为:

降级校验->流控校验->防重校验->参数校验;每个链路是否执行是可选的

两大引擎

规则解析引擎,

参数解析引擎

一个构造器

消息构造器

Java
1
https://gitee.com/cangjingge/chungkui.git
git@gitee.com:cangjingge/chungkui.git
cangjingge
chungkui
chungkui
master

搜索帮助