EasyRules动态规则实现

之前写了easyRules的基本使用方法,可以说还是非常方便而且操作也不复杂,个人觉得相较于Drools来说是简便了不少。接下来就需要更深入的了解一下规则的动态使用方法。

动态规则

动态规则就是由于业务场景的变化,之前的规则已经不适用现在的业务场景,需要更改相对应的规则,但是又不想每次都去修改代码,例如:某宝做活动,之前是满100块才能减免,但是现在只用满10块就能减免了,按照以前的逻辑,我们需要去一下规则文件里面的比较参数就可以,但是这样就需要重新编译打包才能生效,如果使用动态规则,就是我传一个规则文件,只需要运用这个规则文件,就能达到效果,也不需要重新编译打包,何乐而不为呢!!!

要实现这个效果,可以利用easyRules规则定义的两种方式来实现,ymal文件定义规则和json文件定义规则。

存在的问题

这里先说一下在使用过程中遇到的问题(这几个问题都是在运行代码时发现的,可以结合下面的代码实现来看):

  1. 使用规则文件定义规则,condition和action中只能操作facts中有的对象

    在规则文件中虽然可以在conditon和action中使用java代码来写逻辑,但是无法向规则类(pojo类定义的规则)那样的输入参数,因为规则文件中是没办法设置传入参数,例如,在规则类中的action注解对应的方法中我们存入了facts参数,可以使用facts.get()方法获取内容,但是在规则文件中就没办法使用facts这个参数,因为规则文件中无法传入facts这个参数;

  2. 通过规则监听处理自定义规则的逻辑处理

    基于上一个问题,我想到了使用规则监听来进行处理,可以在规则监听类中的afterEvaluate方法中进行相关的逻辑编写,evaluationResult参数时布尔类型的,表示规则匹配是否通过,通过值为true,未通过值未false,也可以使用facts和rule,还是很不错的;

  3. 使用监听则会作用到所有执行的规则,如何准确处理

    基于第二个问题,发现使用了规则监听后,如果你设置的了多个规则进行匹配,那么每次规则执行都会走到afterEvaluate方法中,所以这里的代码逻辑就可能被重复执行多次,这里我处理方法是通过规则的名称来匹配,只有是指定名称的规则才会走逻辑处理。

代码实现

场景简述

接下来使用的测试场景是,输入一个人的信息,信息中包含了这个人的学历等级,根据学历等级去查询他的学历证书情况(集合存储),查询完学历证书后,在检测学历证书与他的学历等级是否匹配,匹配规则为,学历证书数量与学历等级相同,并且最大学历证书的学历等级与人的学历等级一致,则匹配通过,最终人的信息中会添加学历匹配结果,匹配通过的为学历真实,未匹配通过的为存在学历造假嫌疑,并且会保存人的学历资质集合信息。

图解

java规则类实现

规则类

CheckIt:通过检测学历真实

package entity.rules.education;import entity.pojo.Education;
import entity.pojo.Person;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;/*** @author 莫须有* @Date 2021/12/31 15:45* @Description 检测学历真实性*/
@Rule(name = "check", description = "检测学历真实性")
public class CheckIt {@Conditionpublic boolean check(@Fact("person")Person person, Facts facts){List<Education> educationList = person.getEducationList();List<Education> collect = educationList.stream().sorted(Comparator.comparing(Education::getGrade).reversed()).collect(Collectors.toList());person.setEducationList(collect);facts.put("person", person);return person.getQualifications() == educationList.size() && collect.get(0).getGrade() == person.getQualifications();}@Actionpublic void set(Facts facts){Person person = facts.get("person");person.setDec("学历真实!");facts.put("person", person);}
}

EducationAdd:添加学历资质集合

package entity.rules.education;import entity.pojo.Person;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;
import utils.AddEducation;import java.util.List;/*** @author 莫须有* @Date 2021/12/31 15:22* @Description 根据学历添加学历集合*/
@Rule(name = "EducationAdd", description = "添加学历规则匹配")
public class EducationAdd {@Conditionpublic boolean educationAdd(@Fact("person") Person person){return person.getQualifications() >=0 &&  person.getQualifications() <= 10;}@Actionpublic void add(Facts facts){Person person = facts.get("person");List list = AddEducation.getQualification(person);person.setEducationList(list);facts.put("person", person);}
}

QualificationNotMach:不符合要求的学历,即造假学历

package entity.rules.education;import entity.pojo.Education;
import entity.pojo.Person;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
import org.jeasy.rules.api.Facts;import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;/*** @author 莫须有* @Date 2021/12/31 17:51* @Description 学历造假规则匹配*/
@Rule(name = "QualificationNotMach", description = "学历检测未通过匹配规则")
public class QualificationNotMach {@Conditionpublic boolean qualificationNotMach(@Fact("person")Person person, Facts facts){List<Education> educationList = person.getEducationList();List<Education> collect = educationList.stream().sorted(Comparator.comparing(Education::getGrade).reversed()).collect(Collectors.toList());person.setEducationList(collect);facts.put("person", person);return !(person.getQualifications() == educationList.size() && collect.get(0).getGrade() == person.getQualifications());}@Actionpublic void add(Facts facts){Person person = facts.get("person");person.setDec("存在学历造假的嫌疑!");facts.put("person", person);}
}

AddEducation :添加学历资质集合工具类

package utils;import entity.pojo.Education;
import entity.pojo.Person;import java.util.ArrayList;
import java.util.List;/*** @author 莫须有* @Date 2021/12/31 14:32* @Description 添加学历集合*/
public class AddEducation {public static List getQualification(Person person){List qList = new ArrayList();switch (person.getQualifications()){case 0:qList.add(getGrade0());break;case 1:qList.add(getGrade1());break;case 2:qList.add(getGrade1());qList.add(getGrade3());break;case 3:····default:break;}return qList;}private static Education getGrade0() {Education Education = new Education();Education.setGrade(0);Education.setQualificationsName("文盲");Education.setSchoolName("无教育经历");return Education;}····
}

测试类:

package test;import config.MyRulesListener;
import entity.pojo.Person;
import entity.rules.education.CheckIt;
import entity.rules.education.EducationAdd;
import entity.rules.education.QualificationNotMach;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.core.DefaultRulesEngine;/*** @author 莫须有* @Date 2021/12/31 15:11* @Description 学历规则匹配测试*/
public class EducationTest {public static void main(String[] args) {Person person = new Person();person.setName("莫须有");person.setAge(25);person.setQualifications(6);Facts facts = new Facts();facts.put("person", person);Rules rules = new Rules();rules.register(new EducationAdd());rules.register(new CheckIt());rules.register(new QualificationNotMach());DefaultRulesEngine engine = new DefaultRulesEngine();engine.fire(rules, facts);System.out.println("----------------------------");System.out.println(person);}
}

执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FkiYzHOc-1642052913427)(E:\suredata\markdown\img\规则类执行结果.png)]

以上时java规则类实现学历检测的代码实现。

自定义规则文件实现

这里加入了一个学历资质11,因为之前是只能匹配到10,由于是测试,所以在学历资质添加类里面也加入了对应11的资质添加代码,如果是真实场景就可以是从数据库查询,就不需要进行修改。

AddEducation :添加学历资质集合工具类(添加11)

package utils;import entity.pojo.Education;
import entity.pojo.Person;import java.util.ArrayList;
import java.util.List;/*** @author 莫须有* @Date 2021/12/31 14:32* @Description 添加学历集合*/
public class AddEducation {public static List getQualification(Person person){List qList = new ArrayList();switch (person.getQualifications()){case 0:qList.add(getGrade0());break;case 1:qList.add(getGrade1());break;case 2:qList.add(getGrade1());qList.add(getGrade3());break;····default:}return qList;}private static Education getGrade0() {Education Education = new Education();Education.setGrade(0);Education.setQualificationsName("文盲");Education.setSchoolName("无教育经历");return Education;}····}

规则文件(这里与json文件为例,yml文件类似)

EducationAddJsonFile.json

[{"name": "newEducationAdd","description": "修改学历添加列表","condition": "person.getQualifications() >= 0 && person.getQualifications()<=11","priority": 3,"actions": ["System.out.println(\"新规则执行了\")"]}
]

在规则文件中actions是规则执行的内容,由于上面问题2中的问题,所以文件中只是进行condition条件的编写,actions中的逻辑处理放到监听类的afterEvaluate方法中进行处理,但是actions内容不能未空,所以随便写一个打印语句。

监听类 MyRulesListener:

package config;import entity.pojo.Person;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.RuleListener;
import utils.AddEducation;import java.util.List;/*** @author 莫须有* @Date 2021/12/30 18:20* @Description 规则监听器*/
public class MyRulesListener implements RuleListener {@Overridepublic boolean beforeEvaluate(Rule rule, Facts facts) {System.out.println("beforeEvaluate 触发");return true;}@Overridepublic void afterEvaluate(Rule rule, Facts facts, boolean evaluationResult) {if (evaluationResult && rule.getName().equals(facts.get("ruleName"))){Person person = facts.get("person");List list = AddEducation.getQualification(person);person.setEducationList(list);facts.put("person", person);}System.out.println("afterEvaluate 触发");}@Overridepublic void onEvaluationError(Rule rule, Facts facts, Exception exception) {System.out.println("onEvaluationError 触发");}@Overridepublic void beforeExecute(Rule rule, Facts facts) {System.out.println("beforeExecute 触发");}@Overridepublic void onSuccess(Rule rule, Facts facts) {System.out.println("onSuccess 触发");}@Overridepublic void onFailure(Rule rule, Facts facts, Exception exception) {System.out.println("onFailure 触发");}
}

测试类 TestUploudFile:

package test;import config.MyEngineListener;
import config.MyRulesListener;
import entity.pojo.Person;
import entity.rules.education.CheckIt;
import entity.rules.education.QualificationNotMach;
import lombok.extern.slf4j.Slf4j;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.support.reader.JsonRuleDefinitionReader;
import org.jeasy.rules.support.reader.RuleDefinitionReader;
import org.jeasy.rules.support.reader.YamlRuleDefinitionReader;import java.io.FileReader;/*** @author 莫须有* @Date 2022/1/10 9:46* @Description 测试文件上传*/
@Slf4j
public class TestUploudFile {public static void main(String[] args) {//        MVELRuleFactory factory = new MVELRuleFactory(new YamlRuleDefinitionReader());MVELRuleFactory factory = new MVELRuleFactory(new JsonRuleDefinitionReader());// 读取json文件String path = JsonTest.class.getResource("/rules/EducationAddJsonFile.json").getPath();
//        String path = JsonTest.class.getResource("/rules/EducationAddYmlFile.yml").getPath();try {FileReader jsonFile = new FileReader(path);Rule rule = factory.createRule(jsonFile);String ruleName = rule.getName();Rules rules = new Rules();rules.register(rule);rules.register(new CheckIt());rules.register(new QualificationNotMach());Person person = new Person();person.setName("莫须有");person.setAge(25);person.setQualifications(11);Facts facts = new Facts();facts.put("person", person);facts.put("ruleName", ruleName);DefaultRulesEngine engine = new DefaultRulesEngine();engine.registerRuleListener(new MyRulesListener());engine.fire(rules, facts);System.out.println(person);}catch (Exception e){e.printStackTrace();}}
}

执行结果:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8A9NSyRL-1642052913428)(E:\suredata\markdown\img\json规则文件执行结果.png)]

以上是自定义规则文件执行规则实现。

条件语句调用方法处理

以上内容完成后,在老大的引导下对自定义文件中condition内容进行探讨,是否可以调用方法来进行判断,测试后发现,可以调用方法进行判断,但是对调用方法的位置有要求,方法只能是facts对象的参数对象内部定义的方法,也就是说在上述例子中,只能使用person中定义的方法,后续测试中尝试了通过person中的方法在调用外部方法也是可以的,所以虽然condition中需要强依赖于facts中的内容,但是可以通过facts中的对象调用其他外部方法实现规则判断。

测试代码

json文件:

[{"name": "newEducationAdd","description": "修改学历添加列表","condition": "person.getResult(person.getQualifications())","priority": 3,"actions": ["System.out.println(\"新规则执行了\")"]
}]

person类

package entity.pojo;import entity.rules.education.EducationAdd;
import lombok.Data;
import utils.AddEducation;import java.util.List;/*** @author 莫须有* @Date 2021/12/31 13:59* @Description*/
@Data
public class Person {// 姓名private String name;// 年龄private int age;// 描述private String dec;// 学历等级private int qualifications;private List<Education> educationList;public boolean getResult(int i){return AddEducation.getResult(i);
//        return i >=0 && i <= 11;}
}

AddEducation类中添加getResult方法:


/*** @author 莫须有* @Date 2021/12/31 14:32* @Description 添加学历集合*/
public class AddEducation {public static boolean getResult(int i){System.out.println("111111");return i >= 0 && i <= 11;}}

启动测试类:

package test;import config.MyEngineListener;
import config.MyRulesListener;
import entity.pojo.Person;
import entity.rules.education.CheckIt;
import entity.rules.education.QualificationNotMach;
import lombok.extern.slf4j.Slf4j;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rule;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.jeasy.rules.mvel.MVELRuleFactory;
import org.jeasy.rules.support.reader.JsonRuleDefinitionReader;
import org.jeasy.rules.support.reader.RuleDefinitionReader;
import org.jeasy.rules.support.reader.YamlRuleDefinitionReader;import java.io.FileReader;/*** @author 莫须有* @Date 2022/1/10 9:46* @Description 测试文件上传*/
@Slf4j
public class TestUploudFile {public static void main(String[] args) {//        MVELRuleFactory factory = new MVELRuleFactory(new YamlRuleDefinitionReader());MVELRuleFactory factory = new MVELRuleFactory(new JsonRuleDefinitionReader());// 读取json文件String path = JsonTest.class.getResource("/rules/EducationAddJsonFile.json").getPath();
//        String path = YmlTest.class.getResource("/rules/EducationAddYmlFile.yml").getPath();try {FileReader jsonFile = new FileReader(path);Rule rule = factory.createRule(jsonFile);String ruleName = rule.getName();Rules rules = new Rules();rules.register(rule);rules.register(new CheckIt());rules.register(new QualificationNotMach());Person person = new Person();person.setName("莫须有");person.setAge(25);person.setQualifications(11);Facts facts = new Facts();facts.put("person", person);facts.put("ruleName", ruleName);DefaultRulesEngine engine = new DefaultRulesEngine();engine.registerRuleListener(new MyRulesListener());engine.fire(rules, facts);System.out.println(person);}catch (Exception e){e.printStackTrace();}}
}
总结

easyrules自定义规则通过json和yml文件来实现,可以适应变化的需求,有效避免重复修改代码逻辑,是一个很好的if-else替代品;并且它的condition判断可以通过调用方法来进行处理,这对业务的可扩展性也有很大的帮助,后续可以将规则存入数据库,存储内容可以以json字符串格式存储,只是在使用规则的时候需要将规则字符串转换为json文件,需要注意的是,json文件中的规则需要以数组形式存放,无论是一个还是多个。

EasyRules动态规则实现相关推荐

  1. 一文了解分而治之和动态规则算法在前端中的应用

    一文了解分而治之和动态规则算法 一.分而治之 1.分而治之是什么? 2.应用场景 3.场景剖析:归并排序和快速排序 二.动态规则 1.动态规则是什么? 2.应用场景 3.场景剖析:斐波那契数列 4.动 ...

  2. Sentinel(十三)之动态规则扩展

    转载自  动态规则扩展 规则 Sentinel 的理念是开发者只需要关注资源的定义,当资源定义成功后可以动态增加各种流控降级规则.Sentinel 提供两种方式修改规则: 通过 API 直接修改 (l ...

  3. flink+drools动态规则示例之温度跳变告警

    flink+drools动态规则示例之温度跳变告警 package com.mz.test;import com.google.common.collect.Lists; import lombok. ...

  4. Flink动态规则实时智能营销系统

    视频地址 简单来说,本系统,核心是一个基于事件驱动且可进行动态规则计算的实时系统: 在技术上,它是通用的:本套架构及系统内核,不仅可以用于"实时运营",也可以用于"实时风 ...

  5. 从零构建FLINK整合Drools动态规则实时运营系统(项目案例)第1篇(项目介绍篇)

    1 整体架构 前言 项目介绍在线视频: https://www.bilibili.com/video/BV1zv41157yY 本案例是一个专注于flink动态规则计算的项目,核心技术组件涉及flin ...

  6. Flink Cep 扩展 - 动态规则更新及Pattern间within()

    上一篇文章 <Flink Cep 源码分析>我们可以知道Flink cep中Pattern的创建,state的转换,以及匹配结果的数据.这一篇则对Flink cep的两个痛点进行扩展: 1 ...

  7. sentinel 1.8. 2持久化Nacos动态规则热点规则和授权规则不生效的问题

    sentinel 1.8.2 持久化Nacos动态规则热点规则和授权规则不生效的问题 问题:规则持久化到nacos之后,我在本地测试时候只有热点和授权规则不生效,我慢慢的在客户端sentinel-cs ...

  8. 从零构建FLINK整合Drools动态规则实时运营系统(项目案例)第2篇(业务介绍篇)

    项目简介 本案例是一个专注于flink动态规则计算的项目,核心技术组件涉及flink.hbase.clickhouse.drools等 项目可根据各类个性化需求进行二次开发后,直接用于实时运营,实时风 ...

  9. uBlock的动态规则过滤规则书写

    uBlock具有动态和静态两种规则,但是它比之前的ABP等规则过滤规则强的地方就在于他的动态规则,静态规则的语法继承与ABP,有兴趣的可以去看ABP的过滤规则https://adblockplus.o ...

最新文章

  1. MySQL定义条件和处理程序_MySQL教程111-MySQL定义条件和处理程序
  2. html5之通讯API
  3. python【力扣LeetCode算法题库】225-用队列实现栈
  4. 中国石油计算机文化基础答案,中国石油大学17年秋《计算机文化基础》第二次在线作业答案...
  5. UEditor ASP.NET 版使用教程
  6. java定义上三角矩阵,数据结构-矩阵-三角矩阵(Java语言)
  7. 基于GPS的车辆导航及GPRS网络监控
  8. u-boot-2016.09 make工具之fixdep
  9. win 7 安装 VMware 14的bug
  10. 初始C语言——成绩等级划分
  11. 电脑实时监控信息:CPU 内存 GPU使用率在桌面上动态展现
  12. 成成你好呀(C知识点整理二)
  13. 安卓电话补充业务 SS
  14. 造车 8 年,苹果“认输”了:放弃 L 5 级全自动驾驶,售价低于 70 万,将于 2026 年推出...
  15. Python数据分析(6)----招聘信息数据分析
  16. USACO——挤牛奶
  17. 第三十四届广东金融科技交流会顺利举行,墨云分享风险验证技术新思路
  18. jeecg扩展自定义菜单图标
  19. 用c语言编写棋盘以及光标,C语言实习指导书.doc
  20. 值得收藏极速PDF阅读器和编辑器快捷键大全

热门文章

  1. 常用的Linux命令.cmd
  2. C3D复现出现的问题及其解决方法
  3. 博客项目——登录功能实现
  4. 计算机专业课科目,考研计算机专业课有哪些科目
  5. Centos7安装freeswitch-1.10.8(2023)
  6. Flutter 淡入淡出效果
  7. C#面向对象程序设计课程实验二: 实验名称:Windows 窗体程序
  8. 【java学习】JDK(Java Development Kit)
  9. 考研热催生百亿市场,行业老兵文都教育的“冷思考” ——和大学生交朋友
  10. cad角度命令怎么输入_新手入门,学习CAD必须掌握,教你使用标注命令,绘图效率翻一倍...