赞
踩
1、是什么
2、作用
业务系统在应用过程中,常常包含着要处理"复杂、多变"的部分,这部分往往是"业务规则"或者是"数据的处理逻辑"。因此这部分的动态规则的问题,往往需要可配置,并对系统性能和热部署有一定的要求。从开发与业务的视角主要突出以下的一些问题:
1)逻辑复杂,要使用大量if-else来实现,或者使用设计模式。但过于复杂的规则逻辑,使用设计模式也往往是存在大量并且关系复杂的类,导致代码难于维护,对新加入的同学极不友好。
2)变更时需要从头梳理逻辑,在适当的地方进行if…else…代码逻辑调整,耗费大量时间进行梳理。
3)开发周期较长,当需求发生变更时,需要研发人员安排开发周期上线,对于当下快速变化的业务,传统的开发工作方式显得捉襟见肘。
1)业务人员期望友好的管理界面,不需要专业的开发技能就能够完成规则的管理、发布。
2)期望能够实现热部署,由业务人员配置好之后即配即用。
3)减少业务规则对开发人员的依赖。
4)降低需求变动的时间成本,快速验证发布
3、怎么做:
你可以自己构建一个简单的规则引擎。你所需要做的就是创建一组带有条件和动作的规则对象rule,将它们存储在一个集合中rules,然后遍历它们以评估(fire)条件(condition)并执行这些动作(action)。
<dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-core</artifactId> <version>3.3.0</version> </dependency> <!--规则定义文件格式,支持json,yaml等--> <dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-support</artifactId> <version>3.3.0</version> </dependency> <!--支持mvel规则语法库--> <dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-mvel</artifactId> <version>3.3.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.jeasy/easy-rules-spel --> <dependency> <groupId>org.jeasy</groupId> <artifactId>easy-rules-spel</artifactId> <version>4.1.0</version> </dependency>
大多数业务规则可以由以下定义表示:
名称name:规则命名空间中的唯一规则名称
说明description:规则的简要说明
优先级priority:相对于其他规则的规则优先级,较小的值表示较高的优先级
事实fact:去匹配规则时的一组已知事实
条件condition:为了匹配该规则,在给定某些事实的情况下应满足的一组条件
如果规则条件为true,则规则将被触发执行。否则,规则将被忽略
动作action:当条件满足时要执行的一组动作(可以添加/删除/修改事实)
它可以用于实现各种应用程序逻辑,例如更新数据、发送消息等。
public interface Rule extends Comparable<Rule> {
String DEFAULT_NAME = "rule";
String DEFAULT_DESCRIPTION = "description";
int DEFAULT_PRIORITY = 2147483646;
boolean evaluate(Facts var1);
void execute(Facts var1) throws Exception;
}
package org.jeasy.rules.core; import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Rule; public class BasicRule implements Rule { protected String name;//名称 protected String description;//说明 protected int priority;//优先 /** * 此方法封装规则的条件(conditions) * * @param facts :事实 * @return 如果提供的事实适用于该规,则条件返回true */ public boolean evaluate(Facts facts) { return false; } /** * 此方法封装规则的操作(actions) * evaluate方法值为TRUE才能触发execute方法(在满足规则条件时应执行的操作)。 * @throws 如果在执行过程中发生错误将抛出Exception */ public void execute(Facts facts) throws Exception { } }
package org.jeasy.rules.api; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; public class Facts implements Iterable<Map.Entry<String, Object>> { private Map<String, Object> facts = new HashMap(); public Object put(String name, Object fact) { Objects.requireNonNull(name); return this.facts.put(name, fact); } public Object remove(String name) { Objects.requireNonNull(name); return this.facts.remove(name); } public <T> T get(String name) { Objects.requireNonNull(name); return this.facts.get(name); } }
@Resource
private MqService mqService;
facts.put("mqService", mqService)
这样condition方法就可以使用mqService的方法
.when("mqService.doRuleConditions(conditionList,tmpParam)")
或
@Override
public boolean evaluate(@Facts("mqService") MqService mqService) {
mqService.doRuleConditions();
}
public interface Condition {
Condition FALSE = new Condition() {
public boolean evaluate(Facts facts) {
return false;
}
};
Condition TRUE = new Condition() {
public boolean evaluate(Facts facts) {
return true;
}
};
boolean evaluate(Facts var1);
}
public interface Action {
void execute(Facts var1) throws Exception;
}
1、eg1(也可以实现Rule接口)
package com.mjp.easyrules.drmo1; import org.jeasy.rules.annotation.Action; import org.jeasy.rules.annotation.Condition; import org.jeasy.rules.annotation.Fact; import org.jeasy.rules.api.Facts; import org.jeasy.rules.core.BasicRule; public class MyRule extends BasicRule { @Override public boolean evaluate(Facts facts) { return false; } @Override public void execute(Facts facts) throws Exception { } }
2、纯注解
@Rule(name = "weather rule", description = "if it rains then take an umbrella", priority = 777) public class WeatherRule { @Condition public boolean itRains(@Fact("rain") boolean rain, @Fact("other") String other) { return rain; } @Action(order = 1) public void takeAnUmbrella() { System.out.println("It rains, take an umbrella!"); } @Action(order = 2) public void then2(Facts facts) throws Exception { //my actions2 } }
1、eg1
Rule rule = new RuleBuilder()
.name("myRule")
.description("myRuleDescription")
.priority(2)
.when(facts -> true)
.then(facts -> {
// do Action1
})
.then(facts -> {
// do Action2
})
.build();
2、eg2
Rule weatherRule = new RuleBuilder()
.name("weather rule")
.description("if it rains then take an umbrella")
.when(facts -> facts.get("rain").equals(true))
.then(facts -> System.out.println("It rains, take an umbrella!"))
.build();
1、eg1:Mvel表达式
Rule weatherRule = new MVELRule()
.name("weather rule")
.description("if it rains then take an umbrella")
.when("rain == true")
.then("System.out.println(\"It rains, take an umbrella!\");");
when方法参数,只能是facts对象中key对象,内部定义的属性或方法
.when("person.age > 18")
.when("person.isHappy() == true")
也可以是类的静态方法
Demo.add(1,2)//这样when会执行去调用类方法add
2、补充:
3、eg2:Spel表达式同理
eg1: weather-rule.yml
name: "weather rule"
description: "if it rains then take an umbrella"
condition: "true"
actions:
- "System.out.println(\"It rains, take an umbrella!\");"
condition: "person.isAdult() == false"
condition: "person.getResult(person.getQualifications())"
eg2:一个yml文件创建多个规则
---
name: adult rule
description: when age is greater than 18, then mark as adult
priority: 1
condition: "person.age > 18"
actions:
- "person.setAdult(true);"
---
name: weather rule
description: when it rains, then take an umbrella
priority: 2
condition: "rain == true"
actions:
- "System.out.println("It rains, take an umbrella!");"
MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader());
Rule weatherRule = ruleFactory.createRule(new FileReader("D:\\CodeBetter\\src\\main\\resources\\weather-rule.yml"));
// 多条规则
Rules rules = ruleFactory.createRules(new FileReader("rules.yml"));
package org.jeasy.rules.core; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.jeasy.rules.api.Action; import org.jeasy.rules.api.Condition; import org.jeasy.rules.api.Facts; class DefaultRule extends BasicRule { private Condition condition;//一个规则,一个条件。 private List<Action> actions;//一个规则,当满足条件时,可以有多个动作 public boolean evaluate(Facts facts) { return this.condition.evaluate(facts); } public void execute(Facts facts) throws Exception { Iterator var2 = this.actions.iterator(); while(var2.hasNext()) { Action action = (Action)var2.next(); action.execute(facts); } } }
package org.jeasy.rules.spel; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.jeasy.rules.api.Action; import org.jeasy.rules.api.Condition; import org.jeasy.rules.api.Facts; import org.jeasy.rules.core.BasicRule; import org.springframework.expression.BeanResolver; import org.springframework.expression.ParserContext; public class SpELRule extends BasicRule { private Condition condition;//条件 private final List<Action> actions;//动作 private final ParserContext parserContext;//文本解析 private BeanResolver beanResolver; public boolean evaluate(Facts facts) { return this.condition.evaluate(facts); } public void execute(Facts facts) throws Exception { Iterator var2 = this.actions.iterator(); while(var2.hasNext()) { Action action = (Action)var2.next(); action.execute(facts); } } public SpELRule when(String condition) { this.condition = new SpELCondition(condition, this.parserContext, this.beanResolver); return this; } public SpELRule then(String action) { this.actions.add(new SpELAction(action, this.parserContext, this.beanResolver)); return this; } }
public class SpELCondition implements Condition { private final ExpressionParser parser; private final Expression compiledExpression; private BeanResolver beanResolver; public SpELCondition(String expression, ParserContext parserContext, BeanResolver beanResolver) { this.parser = new SpelExpressionParser(); this.beanResolver = beanResolver; this.compiledExpression = this.parser.parseExpression(expression, parserContext); } public boolean evaluate(Facts facts) { StandardEvaluationContext context = new StandardEvaluationContext(); context.setRootObject(facts.asMap()); context.setVariables(facts.asMap()); if (this.beanResolver != null) { context.setBeanResolver(this.beanResolver); } return (Boolean)this.compiledExpression.getValue(context, Boolean.class); } }
public class SpELAction implements Action { private static final Logger LOGGER = LoggerFactory.getLogger(SpELAction.class); private final ExpressionParser parser; private final String expression; private final Expression compiledExpression; private BeanResolver beanResolver; public SpELAction(String expression, ParserContext parserContext, BeanResolver beanResolver) { this.parser = new SpelExpressionParser(); this.expression = expression; this.beanResolver = beanResolver; this.compiledExpression = this.parser.parseExpression(expression, parserContext); } public void execute(Facts facts) { try { StandardEvaluationContext context = new StandardEvaluationContext(); context.setRootObject(facts.asMap()); context.setVariables(facts.asMap()); if (this.beanResolver != null) { context.setBeanResolver(this.beanResolver); } this.compiledExpression.getValue(context); } catch (Exception var3) { LOGGER.error("Unable to evaluate expression: '" + this.expression + "' on facts: " + facts, var3); throw var3; } } }
抽象CompositeRule类由一组规则组成。这是一个典型地组合设计模式的实现。可以以不同方式触发组合规则。
三种CompositeRule具体子类:
UnitRuleGroup : 要么应用所有规则,要么不应用任何规则(AND逻辑)
ActivationRuleGroup : 它触发第一个适用规则,并忽略组中的其他规则(XOR逻辑)
ConditionalRuleGroup : 如果具有最高优先级的规则计算结果为true,则触发其余规则
Rule weatherRule1 = new MVELRule()
.name("weather rule1")
.description("if it rains then move")
.when("isRain == true")
.then("System.out.println(\"rule1: It rains, move!\");");
@Rule(name = "weather rule2", description = "if it rains then take an umbrella",priority = 777) public class WeatherRule { @Condition public boolean itRains(@Fact("isRain") boolean isRain) { return isRain; } @Action(order = 1) public void takeAnUmbrella() { System.out.println("rule2: action1-It rains, take an umbrella!"); } @Action(order = 2) public void then(Facts facts) throws Exception { System.out.println("rule2: action2-边打伞,边听歌"); } }
// 1.创建事实fact Facts facts = new Facts(); facts.put("isRain", true); // 2.创建规则1(Mvel形式) Rule weatherRule1 = new MVELRule() .name("weather rule1") .description("if it rains then move") .when("isRain == true") .then("System.out.println(\"rule1: It rains, move!\");"); // 2.创建规则1(注解形式) WeatherRule weatherRule2 = new WeatherRule(); // 3.创建组合规则 UnitRuleGroup myUnitRuleGroup = new UnitRuleGroup("myUnitRuleGroup", "unit of weatherRule1 and weatherRule2"); myUnitRuleGroup.addRule(weatherRule1); myUnitRuleGroup.addRule(weatherRule2); // 4.创建规则引擎 DefaultRulesEngine defaultRulesEngine = new DefaultRulesEngine(); // 5.定义Rules Rules rules = new Rules(); rules.register(myUnitRuleGroup); // 7.执行 defaultRulesEngine.fire(rules, facts);
rule2: action1-It rains, take an umbrella!
rule2: action2-边打伞,边听歌
rule1: It rains, move!
先输出规则2(优先级为777),规则1(优先级为默认值:2147483646),值越小,优先级越高
public interface RulesEngine {
RulesEngineParameters getParameters();
List<RuleListener> getRuleListeners();
List<RulesEngineListener> getRulesEngineListeners();
void fire(Rules var1, Facts var2);
Map<Rule, Boolean> check(Rules var1, Facts var2);
}
AbstractRuleEngine作用就是抽出多个引擎类共有的,不需要再各自额外重复去实现
public final class DefaultRulesEngine extends AbstractRuleEngine { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultRulesEngine.class); public void fire(Rules rules, Facts facts) { this.triggerListenersBeforeRules(rules, facts); this.doFire(rules, facts); this.triggerListenersAfterRules(rules, facts); } void doFire(Rules rules, Facts facts) { Iterator var3 = rules.iterator(); while(var3.hasNext()) { Rule rule = (Rule)var3.next(); String name = rule.getName(); int priority = rule.getPriority(); if (rule.evaluate(facts)) { this.triggerListenersAfterEvaluate(rule, facts, true); try { this.triggerListenersBeforeExecute(rule, facts); rule.execute(facts); this.triggerListenersOnSuccess(rule, facts); if (this.parameters.isSkipOnFirstAppliedRule()) { LOGGER.debug("Next rules will be skipped since parameter skipOnFirstAppliedRule is set"); break; } } catch (Exception var8) { this.triggerListenersOnFailure(rule, var8, facts); if (this.parameters.isSkipOnFirstFailedRule()) { LOGGER.debug("Next rules will be skipped since parameter skipOnFirstFailedRule is set"); break; } } } else { this.triggerListenersAfterEvaluate(rule, facts, false); if (this.parameters.isSkipOnFirstNonTriggeredRule()) { LOGGER.debug("Next rules will be skipped since parameter skipOnFirstNonTriggeredRule is set"); break; } } } } public Map<Rule, Boolean> check(Rules rules, Facts facts) { this.triggerListenersBeforeRules(rules, facts); Map<Rule, Boolean> result = this.doCheck(rules, facts); this.triggerListenersAfterRules(rules, facts); return result; } private Map<Rule, Boolean> doCheck(Rules rules, Facts facts) { LOGGER.debug("Checking rules"); Map<Rule, Boolean> result = new HashMap(); Iterator var4 = rules.iterator(); while(var4.hasNext()) { Rule rule = (Rule)var4.next(); if (this.shouldBeEvaluated(rule, facts)) { result.put(rule, rule.evaluate(facts)); } } return result; } }
RulesEngineParameters
skipOnFirstAppliedRule:为true告诉引擎规则,被触发时跳过后面的规则。使用场景是:各个规则之间互斥
a || b || c || d,如果a为true,则b、c、d不执行
当发现一个满足条件的规则并执行了相关操作后,便不再继续判断其他规则
skipOnFirstFailedRule:失败时跳过后面的规则。
a && b && c && d,如果a为false,则b、c、d不执行
skipOnFirstNonTriggeredRule:一个规则不会被触发跳过后面的规则。
如果满足当前的规则,则执行相应的操作,直到遇到不满足条件的规则为止,并且也不会对其他规则进行判断了
rulePriorityThreshold:如果优先级超过定义的阈值,则跳过下一个规则。版本3.3已经不支持更改,默认MaxInt。
默认打印Hello World
public class MyRule extends BasicRule { @Override public String getName() { return "my rule"; } @Override public String getDescription() { return "my rule description"; } @Override public boolean evaluate(Facts facts) { return true; } @Override public void execute(Facts facts) throws Exception { System.out.println("我是一个打印Hello World的规则"); } }
public static void main(String[] args) { // 1.创建事实fact Facts facts = new Facts(); // 2.创建条件condition(这里MyRule中默认为true,就不自定义Condition实现类了) // 3.创建动作action(这里MyRule中默认为:打印HelloWorld,就不自定义Action实现类了) // 4.创建规则 MyRule myRule = new MyRule(); // 5.定义Rules Rules rules = new Rules(); rules.register(myRule); // 6.创建规则引擎 DefaultRulesEngine defaultRulesEngine = new DefaultRulesEngine(); // 7.执行 defaultRulesEngine.fire(rules, facts); }
输出
DefaultRulesEngineListener - Rules evaluation started
DefaultRuleListener - Rule 'my rule' triggered
我是一个打印Hello World的规则
DefaultRuleListener - Rule 'my rule' performed successfully
第一步: List<RulesEngineListener> rulesEngineListeners; 执行 void beforeEvaluate(Rule var1, Facts var2) 第二步: MyRule的boolean evaluate(Facts facts) 第三步: List<RuleListener> ruleListeners; 执行void afterEvaluate(Rule var1, Facts var2, boolean evaluateResult) 第四步: List<RuleListener> ruleListeners; 执行void beforeExecute(Rule var1, Facts var2); 第五步: MyRule的 void execute(Facts facts) 第六步: List<RuleListener> ruleListeners; 执行void onSuccess(Rule var1, Facts var2);
1、规则description
if it rains then take an umbrella
2、定义规则
weather-rule.yml
name: "weather rule"
description: "if it rains then take an umbrella"
condition: "isRain == true"
actions:
- "System.out.println(\"It rains, take an umbrella!\");"
3、自定义规则引擎:使用默认的
4、执行
// 1.创建事实fact Facts facts = new Facts(); facts.put("isRain", true); // 2.创建条件condition(weatherRule中:isRain == true,就不自定义Condition实现类了) // 3.创建动作action(weatherRule中默认为:It rains, take an umbrella!,就不自定义Action实现类了) // 4.创建规则(Yml形式) MVELRuleFactory ruleFactory = new MVELRuleFactory(new YamlRuleDefinitionReader()); Rule weatherRule = ruleFactory.createRule(new FileReader("D:\\CodeBetter\\src\\main\\resources\\weather-rule.yml")); // 5.创建规则引擎 DefaultRulesEngine defaultRulesEngine = new DefaultRulesEngine(); // 6.定义Rules Rules rules = new Rules(); rules.register(weatherRule); // 7.执行 defaultRulesEngine.fire(rules, facts);
1、功能描述
从1数到100,并且:
2、常规实现方法
public class FizzBuzz {
public static void main(String[] args) {
for(int i = 1; i <= 100; i++) {
if (((i % 5) == 0) && ((i % 7) == 0))
System.out.print("fizzbuzz");
else if ((i % 5) == 0) System.out.print("fizz");
else if ((i % 7) == 0) System.out.print("buzz");
else System.out.print(i);
}
}
}
3、使用Easy Rules规则引擎实现
将每个需求编写一条规则:
@Rule(name = "Mod5Rule", description = "mod5", priority = 1)
public class Mod5Rule {
@Condition
public boolean canMod5(@Fact("number") Integer number) {
return number % 5 == 0;
}
@Action
public void action(Facts facts) {
Integer i = facts.get("number");
System.out.print(i + " :是5的倍数");
}
}
@Rule(name = "Mod7Rule", description = "mod7", priority = 2)
public class Mod7Rule {
@Condition
public boolean canMod7(@Fact("number") Integer number) {
return number % 7 == 0;
}
@Action
public void action(Facts facts) {
Integer i = facts.get("number");
System.out.print(i + " :是7的倍数");
}
}
public class Mod5And7Rule extends UnitRuleGroup {
public Mod5And7Rule(Object... rules) {
for (Object rule : rules) {
addRule(rule);
}
}
@Override
public int getPriority() {
return 0;
}
}
@Rule(name = "OtherRule", description = "不是5和7的倍数", priority = 3)
public class OtherRule {
@Condition
public boolean canNotMod5Or7(@Fact("number") Integer number) {
return number % 5 != 0 || number % 7 != 0;
}
@Action
public void action(@Fact("number") Integer number) {
System.out.print(number);
}
}
// 创建规则引擎 RulesEngineParameters parameters = new RulesEngineParameters().skipOnFirstAppliedRule(true); RulesEngine fizzBuzzEngine = new DefaultRulesEngine(parameters); // 创建规则 Rules rules = new Rules(); rules.register(new Mod5Rule()); rules.register(new Mod7Rule()); rules.register(new Mod5And7Rule(new Mod5Rule(), new Mod7Rule())); rules.register(new OtherRule()); // 触发规则 Facts facts = new Facts(); for (int i = 1; i <= 100; i++) { facts.put("number", i); fizzBuzzEngine.fire(rules, facts); }
这里规则引擎参数:skipOnFirstAppliedRule(true):告诉引擎,被触发时跳过后面的规则。
即当i = 5时,满足规则1(mod5),执行完action1,就不会再去匹配其他rule2、3、4规则了。使用场景是:各个规则之间互斥
如图1
输入facts:NORMAL_NUMBER和ERROR_NUMBER两个值,使用Mvel表达式解析facts是否满足上述json中定义的condition
package com.mjp.easyrules.csdn; public enum OperationEnum { GREATER_THAN("GREATER_THAN", "%s > %s", "大于"), GREATER_THAN_EQUAL("GREATER_THAN_EQUAL", "%s >= %s", "大于等于"), LESS_THAN("LESS_THAN", "%s < %s", "小于"), LESS_THAN_EQUAL("LESS_THAN_EQUAL", "%s <= %s", "小于等于"), EQUAL("EQUAL", "%s == %s", "等于"), UNEQUAL("UNEQUAL", "%s != %s", "不等于"), BETWEEN("BETWEEN", "%s >= %s && %s <= %s", "介于之间"), OUT_OF_RANGE("OUT_OF_RANGE", "%s >= %s || %s >= %s", "超出范围"), CONTAINS("CONTAINS", "%s.contains(\"%s\")", "包含"), STARTSWITH("STARTSWITH", "%s.startsWith(\"%s\")", "前缀"), ENDSWITH("ENDSWITH", "%s.endsWith(\"%s\")", "后缀"), ; public static OperationEnum getOperationByOperator(String operator) { OperationEnum[] list = OperationEnum.values(); for (OperationEnum item : list) { String compareOperator = item.getOperator(); if (compareOperator.equals(operator)) { return item; } } return null; } private final String operator; private final String expression; private final String remark; OperationEnum(String operator, String expression, String remark) { this.operator = operator; this.expression = expression; this.remark = remark; } public String getOperator() { return operator; } public String getExpression() { return expression; } public String getRemark() { return remark; } }
public class EasyRulesConstants { // 事实别名 public static final String FACT_ALIAS = "fact"; // 结果别名 public static final String RESULT_ALIAS = "result"; // and关系 public static final String RELATION_AND = "and"; // or关系 public static final String RELATION_OR = "or"; // 匹配成功信息 public static final String MATCH_SUCCESS_MESSAGE = "匹配成功"; public static final String FIELD_TYPE = "type"; public static final String FIELD_OPERATOR = "operator"; public static final String FIELD_NAME = "metricName"; public static final String FIELD_VALUE = "value"; public static final String FIELD_CHILDREN = "children"; public static final String EXPRESSION_TYPE = "EXPRESSION"; public static final String RELATION_TYPE = "RELATION"; public static final String LEFT_BRACKETS = "("; public static final String RIGHT_BRACKETS = ")"; public static final String SYMBOL_SPACE = " "; public static final String SYMBOL_EMPTY = ""; public static final String LOGICAL_AND = "&&"; public static final String LOGICAL_OR = "||"; }
package com.mjp.easyrules.csdn; @Slf4j public class EasyRulesUtil { /** * 执行规则匹配 * @param fact 事实json * @param ruleModel 规则模型 */ public static RuleResult match(JSONObject fact, RuleModel ruleModel){ // 结果 RuleResult result = new RuleResult(); result.setRuleId(ruleModel.getRuleId()); // 规则实例 Facts facts = new Facts(); facts.put(FACT_ALIAS, fact); facts.put(RESULT_ALIAS, result); // 规则内容 Rule mvelrule = new MVELRule() .name(ruleModel.getRuleName()) .description(ruleModel.getDescription()) .when(ruleModel.getWhenExpression()) .then(ruleModel.getThenExpression()); // 规则集合 Rules rules = new Rules(); // 将规则添加到集合 rules.register(mvelrule); // 创建规则执行引擎,并执行规则 RulesEngine rulesEngine = new DefaultRulesEngine(); rulesEngine.fire(rules, facts); return result; } /** * 构建mvel条件表达式 * @param json 节点json,例如: * { * "type": "EXPRESSION", * "operator": "LESS_THAN", * "metricName": "NORMAL_NUMBER", * "value": "11", * "children": [] * } */ public static String buildWhenExpression(JSONObject json) { StringBuilder mvelExpressionSB = new StringBuilder(); String type = json.getString(FIELD_TYPE); String operator = json.getString(FIELD_OPERATOR); switch (type) { case EXPRESSION_TYPE: String fieldName = json.getString(FIELD_NAME); String fieldValue = json.getString(FIELD_VALUE); mvelExpressionSB.append(buildOperatorExpress(operator, fieldName, fieldValue)); break; case RELATION_TYPE: JSONArray children = json.getJSONArray(FIELD_CHILDREN); if (children.size() == 0) { return SYMBOL_EMPTY; } operator = convertRelationExpress(operator); StringBuilder sb = new StringBuilder(); for (int i = 0; i < children.size(); i++) { JSONObject child = children.getJSONObject(i); // 递归构建单个规则条件 String childExpression = buildWhenExpression(child); if (!childExpression.isEmpty()) { if (sb.length() > 0) { sb.append(SYMBOL_SPACE).append(operator).append(SYMBOL_SPACE); } sb.append(LEFT_BRACKETS).append(childExpression).append(RIGHT_BRACKETS); } } mvelExpressionSB.append(sb); break; default: break; } return mvelExpressionSB.toString(); } /** * 构建mvel表达式 * @param operator 操作符 * @param fieldName 字段名称 * @param value 字段值 */ private static String buildOperatorExpress(String operator, String fieldName, Object value) { OperationEnum operationEnum = OperationEnum.getOperationByOperator(operator); if (ObjectUtils.isNotEmpty(operationEnum)) { String expression = operationEnum.getExpression(); return String.format(expression, buildValueExpress(fieldName), value); } return SYMBOL_EMPTY; } /** * 构建mvel取值表达式 * @param fieldName 字段名称 */ private static String buildValueExpress(String fieldName) { return String.format("%s.get(\"%s\")", FACT_ALIAS, fieldName); } /** * 转换条件连接符 * @param relation 条件连接符 */ private static String convertRelationExpress(String relation) { if (StringUtils.isEmpty(relation)){ return SYMBOL_EMPTY; } else if(relation.equalsIgnoreCase(RELATION_AND)){ return LOGICAL_AND; } else if(relation.equalsIgnoreCase(RELATION_OR)){ return LOGICAL_OR; } return relation; } /** * 构建mvel结果表达式 */ public static String buildThenExpression() { StringBuilder sb = new StringBuilder(); sb.append(RESULT_ALIAS).append(".setValue(\"").append(MATCH_SUCCESS_MESSAGE).append("\");"); log.info("thenExpression: {}", sb); return sb.toString(); } @Data public static class RuleModel { private String ruleId; String ruleName; String description; String whenExpression; String thenExpression; } @Data public static class RuleResult { // 规则主键 private String ruleId; // 是否匹配, 默认false boolean isMatch = false; // 匹配信息,默认为匹配失败 String message = "匹配失败"; /** * 匹配成功后设置成功信息 */ public void setValue(String message){ this.message = message; this.isMatch = true; } } }
// 1. 新增规则 EasyRulesUtil.RuleModel ruleModel = new EasyRulesUtil.RuleModel(); ruleModel.setRuleId("1"); ruleModel.setRuleName("rule1"); ruleModel.setDescription("测试规则"); // 2. 设置规则条件 String ruleJson = "{\n" + " \"validateCondition\": {\n" + " \"type\": \"RELATION\",\n" + " \"operator\": \"OR\",\n" + " \"children\": [\n" + " {\n" + " \"type\": \"EXPRESSION\",\n" + " \"operator\": \"LESS_THAN\",\n" + " \"metricName\": \"NORMAL_NUMBER\",\n" + " \"value\": \"11\",\n" + " \"children\": []\n" + " },\n" + " {\n" + " \"type\": \"EXPRESSION\",\n" + " \"operator\": \"LESS_THAN_EQUAL\",\n" + " \"metricName\": \"ERROR_NUMBER\",\n" + " \"value\": \"11\",\n" + " \"children\": []\n" + " },\n" + " {\n" + " \"type\": \"RELATION\",\n" + " \"children\": [\n" + " {\n" + " \"type\": \"EXPRESSION\",\n" + " \"metricName\": \"NORMAL_NUMBER\",\n" + " \"operator\": \"GREATER_THAN\",\n" + " \"value\": 10,\n" + " \"children\": []\n" + " },\n" + " {\n" + " \"type\": \"EXPRESSION\",\n" + " \"metricName\": \"ERROR_NUMBER\",\n" + " \"operator\": \"GREATER_THAN\",\n" + " \"value\": 100,\n" + " \"children\": []\n" + " },\n" + " {\n" + " \"type\": \"RELATION\",\n" + " \"children\": [\n" + " {\n" + " \"type\": \"EXPRESSION\",\n" + " \"metricName\": \"NORMAL_NUMBER\",\n" + " \"operator\": \"EQUAL\",\n" + " \"value\": 1,\n" + " \"children\": []\n" + " },\n" + " {\n" + " \"type\": \"EXPRESSION\",\n" + " \"metricName\": \"ERROR_NUMBER\",\n" + " \"operator\": \"EQUAL\",\n" + " \"value\": 1,\n" + " \"children \": []\n" + " }\n" + " ],\n" + " \"operator\": \"OR\"\n" + " }\n" + " ],\n" + " \"operator\": \"OR\"\n" + " }\n" + " ]\n" + " }\n" + "}"; JSONObject conditionJson = JSON.parseObject(ruleJson); // 3. 设置fact String whenExpression = EasyRulesUtil.buildWhenExpression(conditionJson.getJSONObject("validateCondition")); ruleModel.setWhenExpression(whenExpression); // 4. 设置结果表达式 ruleModel.setThenExpression(EasyRulesUtil.buildThenExpression()); // 5. 设置匹配条件 JSONObject json = new JSONObject(); json.put("NORMAL_NUMBER", 12); json.put("ERROR_NUMBER", 12); json.put("省=陕西;市=西安;", 100); // 6. 调用规则匹配 EasyRulesUtil.RuleResult result = EasyRulesUtil.match(json, ruleModel); System.out.println(result);
结果分析:显然结果匹配成功。原因如图2
facts:NORMAL_NUMBER = 10、ERROR_NUMBER = 10
condition:如图1
显然NORMAL_NUMBER = 10,满足第一个条件 < 11,直接返回true。
如果我们设置fact:NORMAL_NUMBER = 12,则NORMAL_NUMBER 不满足第一个条件。
但是fact中ERROR_NUMBER = 10 <= 11满足第二个条件,直接返回True
1、使用阿里的QLExpress
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>QLExpress</artifactId>
<version>3.3.2</version>
</dependency>
ExpressRunner runner = new ExpressRunner(); DefaultContext<String, MetaRuleResult> context = new DefaultContext<>(); context.put("o", MetaRuleResult.builder().skuId(1L).result(true).metaRule("o").failureReason("").build()); context.put("l", MetaRuleResult.builder().skuId(1L).result(false).metaRule("l").failureReason("锁库存不可更改").build()); context.put("s", MetaRuleResult.builder().skuId(1L).result(true).metaRule("s").failureReason("").build()); context.put("w", MetaRuleResult.builder().skuId(1L).result(true).metaRule("w").failureReason("售罄预警").build()); context.put("lo", MetaRuleResult.builder().skuId(1L).result(true).metaRule("lo").failureReason("").build()); context.put("llo", MetaRuleResult.builder().skuId(1L).result(false).metaRule("llo").failureReason("锁库且修改值小于等于OR值可以更改").build()); Object result; DefaultContext<String, Object> computeContext = new DefaultContext<>(); for (Map.Entry<String, MetaRuleResult> entry : context.entrySet()) { computeContext.put(entry.getKey(), entry.getValue().getResult()); } String ruleExpress = "o&&l&&s&&w&&lo&&llo"; result = runner.execute(ruleExpress, computeContext, null, true, false); Boolean bResult = (Boolean) result; System.out.println(bResult);//false
@Data
@Builder
public class MetaRuleResult {
private Long skuId;
private Boolean result;
private String metaRule;
private String failureReason;
}
2、使用EasyRules实现上述功能
@Rule(name = "oRule", description = "修改值>=OR可修改")
public class ORule {
@Condition
public boolean when(@Fact("oRule") MetaRuleResult oRule) {
return oRule.getResult();
}
@Action
public void then(Facts facts) {
System.out.println("修改值>=OR可修改");
}
}
这里的规则是原子规则
@Rule(name = "lRule", description = "锁库不可更改")
public class LRule {
@Condition
public boolean when(@Fact("lRule") MetaRuleResult lRule) {
return lRule.getResult();
}
@Action
public void then(Facts facts) {
System.out.println("没锁库可更改");
}
}
public class MyUnitRuleGroup extends CompositeRule { public MyUnitRuleGroup() { } public MyUnitRuleGroup(String name) { super(name); } public MyUnitRuleGroup(String name, String description) { super(name, description); } public MyUnitRuleGroup(String name, String description, int priority) { super(name, description, priority); } public boolean evaluate(Facts facts) { if (!this.rules.isEmpty()) { Iterator var2 = this.rules.iterator(); Rule rule; do { if (!var2.hasNext()) { return true; } rule = (Rule)var2.next(); } while(rule.evaluate(facts)); // 将失败的facts记录失败的原因 String ruleName = rule.getName(); MetaRuleResult metaRuleResult = facts.get(ruleName); facts.put("执行失败" + ruleName, metaRuleResult); return false; } else { return false; } } public void execute(Facts facts) throws Exception { Iterator var2 = this.rules.iterator(); while(var2.hasNext()) { Rule rule = (Rule)var2.next(); rule.execute(facts); } } }
作用:这里的规则是组合规则,是原子规则的组合形式,可扩展
这里的自定义规则组合,是快速失败机制:即l&&o中如果lRule的condiotion为false,则直接失败,使用facts记录一个失败原因。也可以自定义将每个rule-condition为false的原因都记录下来
public class MyRuleListener implements RuleListener { @Override public boolean beforeEvaluate(Rule rule, Facts facts) { return true; } @Override public void afterEvaluate(Rule rule, Facts facts, boolean b) { String ruleName = rule.getName(); if (b) { // 只有l&&o为true,才会走到这个逻辑,否则走下面逻辑 facts.put(ruleName, MetaRuleResult.builder().skuId(1L).result(true).metaRule(ruleName).failureReason("").build()); } else { // l&&o有一个不满足,则总体失败,将各个失败的原因都记录下来 StringBuilder sb = new StringBuilder(); for (Map.Entry<String, Object> fact : facts) { String key = fact.getKey(); if (key.contains("失败")) { MetaRuleResult result = (MetaRuleResult)fact.getValue(); // 这里result中有中间参数比如lockStatus,则原因就可以写:lockStatus=true,已锁库,不允许修改 sb.append(result.getFailureReason()+ "且"); } } facts.put(ruleName, MetaRuleResult.builder().skuId(1L).result(false).metaRule(ruleName).failureReason(sb.toString()).build()); } } @Override public void beforeExecute(Rule rule, Facts facts) { } @Override public void onSuccess(Rule rule, Facts facts) { } @Override public void onFailure(Rule rule, Facts facts, Exception e) { } }
作用:组合规则,执行结果。成功|失败,已经失败原因
// 1.fact Facts facts = new Facts(); facts.put("oRule", MetaRuleResult.builder().skuId(1L).result(true).metaRule("o").failureReason("").build()); facts.put("lRule", MetaRuleResult.builder().skuId(1L).result(false).metaRule("l").failureReason("").build()); // 2.rule ORule oRule = new ORule(); LRule lRule = new LRule(); String oAndLRuleName = "o&&l"; MyUnitRuleGroup oAndL = new MyUnitRuleGroup(oAndLRuleName, ">=OR且未锁过库规则校验"); oAndL.addRule(oRule); oAndL.addRule(lRule); // 3.rules Rules rules = new Rules(); rules.register(oAndL); // 4.引擎 DefaultRulesEngine engine = new DefaultRulesEngine(); engine.registerRuleListener(new MyRuleListener()); engine.fire(rules,facts); MetaRuleResult result = facts.get(oAndLRuleName); if (!result.getResult()) { System.out.println(oAndLRuleName + result.getFailureReason()); }
1)db获取规则表达式:
先根据网店+品类+角色+修改类型,查询db获取组合规则,比如l&&o
2)工厂模式解析组合规则
然后根据l&&o,解析出规则为l和o,组合成l&&o
3)facts获取数据
自定义策略模式,key为枚举类型,value为对应的rpc查询接口
facts.put("o", MetaRuleResult.builder().skuId(1L).result(queryData("o")).metaRule("o").failureReason("").build());
这里的queryData方法,根据规则类型o,获取对应的Rpc接口-ORGateway,然后查询or值,然后比较结果
4)组合规则中,判断每个原子规则是否执行通过,失败则记录对应执行失败原因
5)在condition-after中自定义listeren,如果组合规则condition为false,则记录组合规则整体的执行失败以及失败原因
6)如果组合规则整体执行失败,则本次结果为false
1、背景
动态规则就是由于业务场景的变化,之前的规则已经不适用现在的业务场景,需要更改相对应的规则。
例如:之前是满300减30,现在是满200-30
2、前提说明
1)规则类中的condtion方法,可以入参传入Facts参数,然后使用facts.get()方法获取内容 ,但是规则文件(eg:json)的condtion中无法传入Facts参数,也就无法使用此参数
2) 自定义RuleListener监听会作用到所有执行的规则,如何仅处理我们指定的规则
@Override
public void afterEvaluate(Rule rule, Facts facts, boolean evaluateResult) {
if(evaluateResult && Objects.equals(rule.getName(), "我们指定的规则名称")) {
}
}
3、场景
输入一个人的信息,信息中包含了这个人的学历等级,作为规则事实
[
{
"name": "newEducationAdd",
"description": "修改学历添加列表",
"condition": "person.getQualifications() >= 0 && person.getQualifications()<=11",
"priority": 3,
"actions": [
"System.out.println(\"新规则执行了\")"
]
}
]
[{
"name": "newEducationAdd",
"description": "修改学历添加列表",
"condition": "person.getResult(person.getQualifications())",
"priority": 3,
"actions": [
"System.out.println(\"新规则执行了\")"
]
}]
@Data public class Person { // 姓名 private String name; // 年龄 private int age; // 描述 private String dec; // 学历等级 private int qualifications; private List<Education> educationList; public boolean getResult(int level){ return AddEducation.getResult(level); } } @UtilityClass public class AddEducation { public static boolean getResult(int level){ return level >= 0 && level <= 11; } }
如果学历等级符合规则,则去查询学历证书情况(集合存储)
查出完学历证书后,在检测学历证书与他的学历等级是否匹配,匹配规则为:
匹配通过则学历真实,信息中会添加真实学历匹配结果
未匹配通过则学历造假嫌疑,信息中会添加造假学历信息
上线
2、前提说明
1)规则类中的condtion方法,可以入参传入Facts参数,然后使用facts.get()方法获取内容 ,但是规则文件(eg:json)的condtion中无法传入Facts参数,也就无法使用此参数
2) 自定义RuleListener监听会作用到所有执行的规则,如何仅处理我们指定的规则
@Override
public void afterEvaluate(Rule rule, Facts facts, boolean evaluateResult) {
if(evaluateResult && Objects.equals(rule.getName(), "我们指定的规则名称")) {
}
}
3、场景
输入一个人的信息,信息中包含了这个人的学历等级,作为规则事实
[
{
"name": "newEducationAdd",
"description": "修改学历添加列表",
"condition": "person.getQualifications() >= 0 && person.getQualifications()<=11",
"priority": 3,
"actions": [
"System.out.println(\"新规则执行了\")"
]
}
]
[{
"name": "newEducationAdd",
"description": "修改学历添加列表",
"condition": "person.getResult(person.getQualifications())",
"priority": 3,
"actions": [
"System.out.println(\"新规则执行了\")"
]
}]
@Data public class Person { // 姓名 private String name; // 年龄 private int age; // 描述 private String dec; // 学历等级 private int qualifications; private List<Education> educationList; public boolean getResult(int level){ return AddEducation.getResult(level); } } @UtilityClass public class AddEducation { public static boolean getResult(int level){ return level >= 0 && level <= 11; } }
如果学历等级符合规则,则去查询学历证书情况(集合存储)
查出完学历证书后,在检测学历证书与他的学历等级是否匹配,匹配规则为:
匹配通过则学历真实,信息中会添加真实学历匹配结果
未匹配通过则学历造假嫌疑,信息中会添加造假学历信息
1、背景
如果商家发生了履约缺货,则需要对商家进行罚款,罚款金额计算的逻辑如下:
这里以skuId=1,skuName=“苹果”, 供应商id=777为例
则需要对777这个商家,关于skuId=1的品进行罚款,罚款金额Java代码实现如下
BigDecimal saleGmv = BigDecimal.valueOf(100); BigDecimal saleCount = BigDecimal.valueOf(5); BigDecimal less = BigDecimal.valueOf(3); BigDecimal price = saleGmv.divide(saleCount, 2, RoundingMode.HALF_UP); Double fineMoney; if (price.compareTo(BigDecimal.valueOf(10)) >= 0) { BigDecimal money = saleGmv.multiply(BigDecimal.valueOf(0.1)).add(less.multiply(BigDecimal.valueOf(10))); double val = money.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); fineMoney = Math.max(val, 200.0); } else { BigDecimal money = saleGmv.multiply(BigDecimal.valueOf(0.1)).add(less.multiply(BigDecimal.valueOf(4))); double val = money.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue(); fineMoney = Math.max(val, 200.0); } System.out.println(fineMoney);
这里商家skuId=1缺货了3件,按照这个逻辑Java代码实现没有问题,加入skuid=1缺货了300件,则不能按照这个罚款的计算逻辑,计算逻辑就要重新Java代码实现,或者大量的if-else。这里仅有6中分支,加入分支很多很多,则代码变得异常臃肿。
假如代码实现后,那天业务变更了计算公式的一个值,或者干脆改变了计算逻辑max->min,则只能通过代码上线。
实现如下
2、实现
public void calculateFineMoneyBySku() { Facts facts = new Facts(); // 1.单个sku信息 // 这里直接使用facts.put值,实际业务中,具体的值是从外部获取到的 facts.put("saleGmv", BigDecimal.valueOf(100)); facts.put("saleCount", BigDecimal.valueOf(5)); facts.put("less",BigDecimal.valueOf(30)); BigDecimal a = facts.get("saleGmv"); BigDecimal b= facts.get("saleCount"); facts.put("price", a.divide(b, 2, RoundingMode.HALF_UP)); // 2.从配置中获取规则(这里举例子获取到2个规则) String ruleName1 = "rule1"; String whenExpress1 = "less > 0 && less <= 10"; String thenExp1 = "price < 10 ? Math.max(0.1 * saleGmv + less * 4, 200) : Math.max(0.1 * saleGmv + less * 10, 200)"; facts.put(ruleName1 + "Exp", thenExp1);//给Listener使用的 Rule lessRule1 = new MVELRule() .name(ruleName1) .description("履约缺货规则1") .when(whenExpress1) .then(thenExp1); String ruleName2 = "rule2"; String whenExpress2 = "less > 10 && less <= 50"; String thenExp2 = "price < 10 ? Math.max(0.1 * saleGmv + less * 4, 500) : Math.max(0.1 * saleGmv + less * 10, 500)"; facts.put(ruleName2 + "Exp", thenExp2); Rule lessRule2 = new MVELRule() .name(ruleName2) .description("履约缺货规则2") .when(whenExpress2) .then(thenExp2); Rules rules = new Rules(); rules.register(lessRule1); rules.register(lessRule2); DefaultRulesEngine engine = new DefaultRulesEngine(); MyRuleListener listener = new MyRuleListener(); engine.registerRuleListener(listener); engine.fire(rules, facts); Map<String, Object> map = facts.asMap(); Set<String> keys = map.keySet(); for (String key : keys) { if (key.contains("Result")) { Object res = facts.get(key); System.out.println(res); break; } } }
3.监听器
通过监听器,如果then执行成功了,则一定会执行监听器的onSuccess方法。故在此再执行一遍then表达式,获取then的执行结果存入map中(这里之所以要通过监听器来存then的结果,原因是原生的MvelRule规则的execute方法返回值类型是void,它只关系then中的表达式是否执行成功,不关系表达式执行的结果)
package com.mjp.easyrules.qlexpress; import org.jeasy.rules.api.Facts; import org.jeasy.rules.api.Rule; import org.jeasy.rules.api.RuleListener; import org.mvel2.MVEL; /** * Author:majinpeng * Date: 2023/12/31 9:40 */ public class MyRuleListener implements RuleListener { @Override public boolean beforeEvaluate(Rule rule, Facts facts) { return true; } @Override public void afterEvaluate(Rule rule, Facts facts, boolean b) { } @Override public void beforeExecute(Rule rule, Facts facts) { } @Override public void onSuccess(Rule rule, Facts facts) { String ruleName = rule.getName(); String key = ruleName + "Exp"; String actionExp = facts.get(key); Object result = MVEL.eval(actionExp, facts.asMap()); facts.put(ruleName+"Result", result); } @Override public void onFailure(Rule rule, Facts facts, Exception e) { } }
1.调用类的带参数方法
MyTest obj = new MyTest();
Map<String, Object> map = new HashMap<>();
map.put("key1", 1);
map.put("key2", 2);
String expression = "func(map)";
Map<String, Object> vars = new HashMap<>();
vars.put("map", map);
MVEL.executeExpression(MVEL.compileExpression(expression), obj, vars);
System.out.println(map);
2.调用类不带参方法
@Test public void t() throws Exception{ Facts facts = new Facts(); facts.put("myTest",new MyTest()); Rule lessRule = new MVELRule() .name(ruleName) .description("履约缺货规则") .when(whenExpress) .then("myTest.func()"); Rules rules = new Rules(); rules.register(lessRule); DefaultRulesEngine engine = new DefaultRulesEngine(); engine.fire(rules, facts); System.out.println(facts);
1、背景
当满足when(指定类的方法),则执行then(执行类的方法)
2、举例
public class Demo {
public static boolean whenFunc(Long id) {
return id > 0;
}
public static void thenFunc1(Long id, Map<String, Object> map) {
System.out.println(id);
System.out.println(map);
}
public static String thenFunc2(Long id, String name) {
return id + name;
}
}
Facts facts = new Facts(); facts.put("id",1); facts.put("name","mjp"); facts.put("Demo", Demo.class); Facts ff = new Facts(); ff.put("age", 18); facts.put("ff", ff); MVELRule rule = new MVELRule().name("rule").description("test") .when("Demo.whenFunc(id)") .then("Demo.thenFunc1(id,ff.asMap())") .then("Demo.thenFunc2(id,name)"); Rules rules = new Rules(); rules.register(rule); DefaultRulesEngine engine = new DefaultRulesEngine(); engine.fire(rules,facts);
我mjp愿称之为EasyRules最强实战场景2024.01.07
1、背景
综合上述场景7和8。
我们知道规则的处罚动作actions可能不止一个。除了对商家进行罚款,还可以对商家停排期,甚至可以降低商家商品的曝光度等等一系列处罚动作。
基于此,我们可以将处罚actions配置为json字符串
{
"fineMoney":"price < 10 ? Math.max(0.1 * saleGmv + less * 4, 200) : Math.max(0.1 * saleGmv + less * 10, 200)",
"stopSchedule":3,
"降低曝光度":true
}
2、特殊化
规则1
{
"fineMoney":"price < 10 ? Math.max(0.1 * saleGmv + less * 4, 200) : Math.max(0.1 * saleGmv + less * 10, 200)",
"stopSchedule":3,
"降低曝光度":true
}
规则2
{
"fineMoney":"price < 10 ? Math.max(0.1 * saleGmv + less * 4, 200) : Math.max(0.1 * saleGmv + less * 10, 200)"
}
即规则2的处罚动作只有罚款
那么问题来了,如何为每个规则,定制化处罚actions动作
答案:通过职责链模式
3、思想
然后每一条规则的actions =》映射成List handlerList,然后遍历执行处理器。
4、代码实现
@RunWith(SpringRunner.class) @SpringBootTest(classes = ApplicationLoader.class) @Slf4j public class SpringTest { @Resource private Demo demo; @Test public void t() { Facts facts = new Facts(); facts.put("id",1); facts.put("name","mjp"); facts.put("Demo", demo); Facts ff = new Facts(); ff.put("age", 18); facts.put("ff", ff); MVELRule rule = new MVELRule().name("rule").description("test") .when("Demo.whenFunc(id)") .then("Demo.thenFunc1(id,ff.asMap())"); Rules rules = new Rules(); rules.register(rule); DefaultRulesEngine engine = new DefaultRulesEngine(); engine.fire(rules,facts); } }
package com.mjp.easyrules.less; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * Author:mjp * Date: 2024/01/07 9:50 */ @Service public class Demo { @Resource private List<Handler> handlerList; public boolean whenFunc(Long id) { return id > 0; } public void thenFunc1(Long id, Map<String, Object> map) { System.out.println(id); // 方式一:所有处理器都参与 for (Handler handler : handlerList) { handler.exe(); } // 方式二:不同的规则有不同的处罚actions,对应不同的处理器集合,这里可以定制化处理器集合 // 根据入参内容(从入参map中获取信息,可知得知actions-json字符串内容),这样我们就可以据此,构造定制化的处罚器集合 handlerList = handlerList.stream().filter(Handler::needExe).collect(Collectors.toList()); for (Handler handler : handlerList) { handler.exe(); } } }
public interface Handler {
/**
* 惩罚体
*/
void exe();
/**
* 是否需要执行此处理器
* @return
*/
default boolean needExe() {
return true;
}
}
处理器实现类
罚款处理器
@Order(value = 1)
@Service
public class FineMoneyHandler implements Handler{
@Override
public void exe() {
System.out.println("fineMoney");
}
}
停排处理器
@Order(value = 2) @Service public class StopScheduleHandler implements Handler{ @Override public void exe() { System.out.println("停排期"); } /** * 不执行停排期惩罚 * @return */ @Override public boolean needExe() { return false; } }
根据入参定制化处理器集合
处理器接口默认都不参与,根据json的key添加谁参与
public interface Handler {
/**
* 惩罚体
*/
void exe();
/**
* 是否需要执行此处理器
* @return
*/
default boolean needExe() {
return false;
}
}
@Service public class Demo { @Resource private List<Handler> handlerList; @Resource private ApplicationContext applicationContext; public boolean whenFunc(Long id) { return id > 0; } public void thenFunc1(Long id, Map<String, Object> map) { System.out.println(id); // 方式一:所有处理器都参与 for (Handler handler : handlerList) { handler.exe(); } } public void thenFunc2(Long id, Map<String, Object> map) throws ClassNotFoundException { // 根据actions的json字符串的key,key存在,则说明对应的处罚动作存在,则映射成对应的处理器 // 1.遍历所有的json k-v // 2.拿到key String name = "FineMoney"; String className = "com.mjp.easyrules.less." + name + "Handler"; Class<?> aClass = Class.forName(className); // 3.生成对应的处理器,并添加到集合中 Handler bean = (Handler)applicationContext.getBean(aClass); handlerList.add(bean); // 4.执行所有处罚动作 for (Handler handler : handlerList) { handler.exe(); } } }
5、罚款处理器扩展
罚款处理器中,也可以使用Mvel表达式,直接计算罚款多少钱
@Order(value = 1)
@Service
public class FineMoneyHandler implements Handler{
@Override
public void exe(Map<String, Object> facts) {
System.out.println("fineMoney");
// 使用Mvel表达式直接计算罚款金额
// 这里fineMoneyExp也是方法传递过来的,然后每个参数都可以在facts拿到
String fineMoneyExp = "price < 10 ? Math.max(0.1 * saleGmv + less * 4, 500) : Math.max(0.1 * saleGmv + less * 10, 500)";
Object fineMoney = MVEL.eval(fineMoneyExp, facts);
}
}
1.调用类的带参数方法
MyTest obj = new MyTest();
Map<String, Object> map = new HashMap<>();
map.put("key1", 1);
map.put("key2", 2);
String expression = "func(map)";
Map<String, Object> vars = new HashMap<>();
vars.put("map", map);
MVEL.executeExpression(MVEL.compileExpression(expression), obj, vars);
System.out.println(map);
2.调用类不带参方法
@Test public void t() throws Exception{ Facts facts = new Facts(); facts.put("myTest",new MyTest()); Rule lessRule = new MVELRule() .name(ruleName) .description("履约缺货规则") .when(whenExpress) .then("myTest.func()"); Rules rules = new Rules(); rules.register(lessRule); DefaultRulesEngine engine = new DefaultRulesEngine(); engine.fire(rules, facts); System.out.println(facts);
撒花2024.01.07 10:45-mjp
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。