同步操作将从 藏经阁/chungkui 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
钟馗是一款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";
}
}
有两种配置方式:
该配置项为一个数组。每个参数是数组的一个元素。方便复用校验配置
整个配置项为一个json字符串,复用性差。但是方便进行远程管理所有配置项。有问题时方便拷贝整个配置进行修改
@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 | 数据格式不正确报错 | 无 |
@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 | 格式不满足提示 | 参数必填 |
@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 | 格式不满足提示 | 参数不合法 |
@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 | 格式不满足提示 | 参数必填 |
@Check({"{type:'date',fmt:'yyyyMMdd HHmmss',before:2,after:3,param:'startTime',msg:'日期非法'}"})
key | 描述 |
---|---|
type | 校验类型 |
rule | 校验规则 |
param | 参数名 |
fmt | 日期格式 |
before | 早于当前时间毫秒数 |
after | 晚于当前时间毫秒数 |
code | 失败编码 |
condition | 触发条件,当表达式为true时才会校验 |
@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时才会校验 |
实现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表示关闭重复提交校验(开启配置中心时可用) |
key | 描述 |
---|---|
null | token为空提醒 |
fail | 重复提交提醒 |
@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 | 失败编码 |
@Check(redisRateLimters={"{capacity:1,rate:1,perUser:1,msg:'您手速太快了,请稍后再试',code:500}"}
key | 描述 |
---|---|
rate | 流控tps值 |
param | 动态流控参数 |
capacity | 令牌桶容量 |
perUser | 每次消耗令牌个数 |
code | 失败编码 |
msg | 校验失败提醒 |
code | 失败编码 |
自定义格式注解配置项为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);
校验request中的入参,校验失败无侵入代码直接响应json给客户端
校验request中的入参,校验失败,会缓存失败详情,可以通过如下方式获取校验结果,该种方式不会直接返回方法, 需要人工接收校验结果。使用场景是校验非ajax请求的场景
从参数列表中取参数
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 | 降级触发拦截的时候的异常码 |
@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 | 流控触发拦截的时候的异常码 |
可以对对象类型的数据中的字段进行校验;需要指定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热点缓存的方式提高校验性能。
校验链目前有四种。顺序分别为:
降级校验->流控校验->防重校验->参数校验;每个链路是否执行是可选的
规则解析引擎,
参数解析引擎
消息构造器
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。