Fel表达式实践
项目背景
订单完成后,会由交易系统推送实时MQ消息给订单清算系统,告诉清算系统此订单交易完成,可以进行给商家结算等后续操作。
财务要求在交易推送订单到清算系统时和订单清算系统接收到订单消息后,需要按照财务给定的校验公式,验证交易推送的数据是否正确。比如下面的财务公式:
- 商品原价 = 商品活动价 + 活动价补贴
- 在线支付=微信+支付宝+QQ钱包+会员卡支付+翼支付
- 用户实付=在线支付+现金
- 订单总额=在线支付金额+会员卡优惠+代金券优惠+公司活动补贴+商家活动价补贴+现金支付
财务同学明确告知,随着支付网关后续接入更多支付渠道整体公式都要随着变化。另外营销手段的丰富化(拼团返现等),相应结算相关的金额都要纳入财务公式计算和校验中。故公式整体是不断变化的。
方案
金额单元参数化
为了应对后续财务相关字段的随时扩充,项目组组长确定使用大Json,单元参数形式表示非订单基础信息。形如:
[{"K":10112,"V":"2100"},{"K":10113,"V":"10"},{"K":10115,"V":"2300"},{"K":10117,"V":"0"}]
具体Key字段(比如:10112、10113、10115)含义由枚举形式维护。并人为规定10000~20000段为金额相关字段。
字典表或配置中心存储校验公式
校验公式前期是存储在MySQL的一张字典表里。后期有计划迁移到架构部维护的统一配置中心里。部分校验公式形如下:
1. p10125-(p10101+p10106+p10108+p10131+p10113)
2. p10101-(p10102+p10103+p10104+p10105+p10130)
3. p10108-(p10109+p10110+p10111+p10133)
4. p10125-(p10131+p10124)
5. p10131-(p10112+p10132)
6. p10107-(p10132+p10133)
7. p10117-(p10134+p10135+p10136+p10140+p10137+p10138+p10139)
其实,通过看上面一大堆公式,也可以看出 使用这种编码化的单元参数,可读性太差了!!
公式校验
在订单清算系统接收到到订单MQ消息时,会遍历消息体内全部金额相关字段写入到FelContext内,为后面计算做准备。
校验前准备:
private FelContext getFelContext(OrderSalary orderSalary, FelEngine fel) {
FelContext ctx = fel.getContext();
ParamEnum[] enums = ParamEnum.values();
for (ParamEnum paramEnum : enums) {
if (paramEnum.getCode() < 20000) {
// 获取对应的Value值
String value = ParamapUtil.getSingleton().getEntityParamValueByParamID(orderSalary, paramEnum.getCode()) == null ? "0" : ParamapUtil.getSingleton().getEntityParamValueByParamID(orderSalary, paramEnum.getCode());
// 以 p11002 , 2000 的形式写入FelContext
ctx.set("p" + paramEnum.getCode(), Long.parseLong(value));
}
}
return ctx;
}
公式校验: 比如 ( 用户实付 - (在线支付+现金) = 0 )
// checkValue为全部检验公式,是从字典表或者配置中心获取的
for (String check : checkValue) {
Expression exp = fel.compile(check, ctx);
Object result = exp.eval(ctx);
Long checkNumber = NumberUtil.toLong(result);
if (checkNumber != 0) {
logger.error("orderId={} 规则校验错误:{}", new Object[]{orderSalary.getOrderId(), check});
return Boolean.FALSE;
}
}
其他场景
比如计算本单实发,也就是本单实际给商家结算金额,就可以表达式引擎。我们公司旧的计算规则:
本单实发=结算金额-退款金额+商家补贴撤回+现金退款-现金支付-商家信息服务费-商家承税;
最后
还是想吐槽这种编码形式的单元参数设计,可读性太差了。人为去维护code和具体含义的枚举,一旦维护乱了,后面的人就再也不知道这个编码的含义了。
Fel表达式实践的更多相关文章
- Fel表达式使用过程中需要注意的问题
精度问题: 我们知道java中直接使用float和double参与的计算都可能会产生精度问题,比如0.1+0.3.1.0-0.9 等.所以一般财务系统,都会使用BigDecimal进行加减乘除. 在调 ...
- Fel表达式计算引擎学习
转载原文地址:Fel是轻量级的高效的表达式计算引擎 Fel的问题 Fel的问题 Fel是轻量级的高效的表达式计算引擎 Fel在源自于企业项目,设计目标是为了满足不断变化的功能需求和性能需求. Fel是 ...
- FEL表达式的用法
Fel是开放的,引擎执行中的多个模块都可以扩展或替换.Fel的执行主要是通过函数实现,运算符(+.-等都是Fel函数),所有这些函数都是可以替换的,扩展函数也非常简单. Fel有双引擎,同时支持解释执 ...
- Java8函数式接口以及lambda表达式实践
罗列一下遇到可以转换成lamada表达式的场景,仅供参考,如有更好的方式,欢迎在评论区留言. 1.计算订单总金额 订单总金额一般是在后台循环叠加每个购买商品的金额已获取到,通常的方式如下 BigDec ...
- Shell编程学习(六)
Shell 脚本条件测试与比较 条件测试方法综述 在Bash的各种条件结构和控制结构中都要进行各种测试,然后根据测试结果执行不同的操作,有时也会与if等条件语句相结合,来完成测试判断,以减少程序运行的 ...
- javascript之小积累-匿名函数表达式的最佳实践
在写js的时候,还是经常会用的匿名函数表达式,比如 setTimeout(function() { console.log(110); }, 1000); 上面那个function()就是匿名函数表达 ...
- Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法
Atitit 表达式原理 语法分析 原理与实践 解析java的dsl 递归下降是现阶段主流的语法分析方法 于是我们可以把上面的语法改写成如下形式:1 合并前缀1 语法分析有自上而下和自下而上两种分析 ...
- 表达式树练习实践:C# 五类运算符的表达式树表达
目录 表达式树练习实践:C# 运算符 一,算术运算符 + 与 Add() - 与 Subtract() 乘除.取模 自增自减 二,关系运算符 ==.!=.>.<.>=.<= 三 ...
- 表达式树练习实践:C# 循环与循环控制
目录 表达式树练习实践:C# 循环 LabelTarget for / while 循环 无限循环 最简单的循环 多次循环 break 和 continue 一起 表达式树练习实践:C# 循环 C# ...
随机推荐
- CC DGCD:Dynamic GCD——题解
https://vjudge.net/problem/CodeChef-DGCD https://www.codechef.com/problems/DGCD 题目大意: 给一颗带点权的树,两个操作: ...
- 洛谷P3759 [TJOI2017]不勤劳的图书管理员 【树状数组套主席树】
题目链接 洛谷P3759 题解 树状数组套主席树板题 #include<algorithm> #include<iostream> #include<cstring> ...
- oracle数据库数据导入导出步骤(入门)
oracle数据库数据导入导出步骤(入门) 说明: 1.数据库数据导入导出方法有多种,可以通过exp/imp命令导入导出,也可以用第三方工具导出,如:PLSQL 2.如果熟悉命令,建议用exp/imp ...
- finetune on caffe
官方例程:http://caffe.berkeleyvision.org/gathered/examples/finetune_flickr_style.html 相应的中文说明:http://blo ...
- HDU 3586 树形dp
Information Disturbing Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/ ...
- POJ 2112 二分+最大流
Optimal Milking Time Limit: 2000MS Memory Limit: 30000K Total Submissions: 17297 Accepted: 6203 ...
- Java设计模式の观察者模式(推拉模型)
目录: 一.观察者定义 二.观察者模式的结构(推模式实现) 三.推模型和拉模型(拉模式实现) 四.JAVA提供的对观察者模式的支持 五.使用JAVA对观察者模式的支持(自带推模式实现实例) 一.观察者 ...
- svn稀疏目录--通过设置工作目录的深度(depth)实现目录树的部分签出
对于一个大的版本库来说,本地工作目录签出整个目录树是即费时又占地儿的.虽然可以只签出某个子目录树,但有时候还是需要从根目录签出.那么,怎么才能只把自己感兴趣的子目录签出来呢? 从svn1.5版开始,提 ...
- 图论:最短路-Dijkstra
Dijkstra+堆优化具有稳定的时间复杂度,在一些数据范围要求比较严格(准确来说是图比较苛刻)的时候能够保证稳定的时间复杂度 但是Dijkstra不能够解决负边权的问题,所以在使用的时候一定要仔细读 ...
- redis 模糊查找keys
Redis入门教程可参考:超强.超详细Redis数据库入门教程 Redis操作命令可参考:Redis操作命令总结 redis可以通过命令Keys Match来进行键值的模糊匹配,借助StackExch ...