当前位置: 首页 > news >正文

springboot + easyRules 搭建规则引擎服务

依赖
        <dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-core</artifactId><version>4.0.0</version></dependency><dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-mvel</artifactId><version>4.0.0</version></dependency><dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-spel</artifactId><version>4.0.0</version></dependency>
输入

为更灵活的发挥规则引擎的功能,输入可以使用JSONObject,这样增删改字段无需修改代码。

输出
@Data
public class RuleResult {/*** 规则主键*/Long ruleId;/*** 规则名* 默认false*/boolean isMatch = false;/*** 规则名*/String value;/*** 满足规则后执行*/public void setValue(String msg){this.value = msg;this.isMatch = true;}
}

规则引擎本身的目的是为了业务与开发解耦,因此只输出是否满足规则,至于满足规则后要干什么业务,这个就是调用方的事。

简单的测试
    @Testvoid jsonExpressionTest() {// 输入项JSONObject dataSource = new JSONObject();dataSource.put("name","大帅比");dataSource.put("age",18);// 结果RuleResult result = new RuleResult();// 规则实例Facts facts = new Facts();facts.put("fact",dataSource);facts.put("result",result);// whenString when = "fact.get(\"name\")==\"大帅比\"";// thenString then = "result.setValue(\"确实帅\");";// 规则内容Rule testModeRule = new MVELRule().name("test rule").description("rule for test").when(when).then(then);// 规则集合Rules rules = new Rules();// 将规则添加到集合rules.register(testModeRule);//创建规则执行引擎,并执行规则RulesEngine rulesEngine = new DefaultRulesEngine();rulesEngine.fire(rules, facts);log.info("result:{}",result.toString());}

完善下,把规则抽象出来,最终的目的就是通过调用方传入的参数,生成when和then表达式;

规则
@Data
@ToString(callSuper = true)
@TableName("EXPRESSION_RULE")
public class ExpressionRule {/*** 主键*/Long id;/*** 规则分组*/String ruleGroup;/*** 规则标识(英文,且唯一)*/String ruleCode;/*** 规则名*/String ruleName;/*** 规则描述*/String ruleDescription;/*** 满足规则后的消息*/String message;/*** 规则表达式,通过conditionList生成*/String whenExpression;/*** 匹配规则操作表达式*/String thenExpression;/*** 创建人工号*/String creatUser;/*** 创建时间*/Date createTime;/*** 最近更新时间*/Date lastUpdateTime;/*** 最近更新人*/String lastUpdateUser;/*** 是否启用*/boolean isEnable;/*** 条件列表*/@TableField(exist = false)List<ExpressionRuleCondition> conditionList;
}
规则下的条件
@Data
@ToString(callSuper = true)
@TableName("EXPRESSION_RULE_CONDITION")
public class ExpressionRuleCondition {/*** 主键*/Long id;/*** 主表ID*/Long masterId;/*** 左括号* ( ~ (((((*/String leftBrackets;/*** 字段*/String field;/*** 操作* 大于,小于,等于,不等于,包含,不包含,前缀,后缀* >  , <  , ==, !=  , contains , !contains, startWith, endWith**/String operator;/*** 值字段类型* 自定义输入 或 实体字段*  input , field*/String valueType;/*** 字段规则命中值*/String value;/*** 右括号* ) ~ )))))*/String rightBrackets;/*** 多条件连接符号* && ~ ||*/String link;
}
RuleUtils
@Slf4j
public class RuleUtils {public static RuleResult match(JSONObject dataSource, ExpressionRule rule){// 结果RuleResult result = new RuleResult();// 规则实例Facts facts = new Facts();facts.put("fact",dataSource);facts.put("result",result);// 规则内容Rule mvelrule = new MVELRule().name(rule.getRuleName()).description(rule.getRuleDescription()).when(rule.getWhenExpression()).then(rule.getThenExpression());// 规则集合Rules rules = new Rules();// 将规则添加到集合rules.register(mvelrule);//创建规则执行引擎,并执行规则RulesEngine rulesEngine = new DefaultRulesEngine();rulesEngine.fire(rules, facts);result.setRuleId(rule.getId());return result;}}
新建规则

controller

    @PostMapping("/addRule")@ApiOperation("新增表达式规则")public ResponseResult<Long> addRule(@RequestBody BaseRuleRo ruleRo){return ruleService.addRule(ruleRo);}

serviceImpl

    /*** 新增表达式规则*/@Override@Transactional(rollbackFor = Exception.class)public ResponseResult<Long> addRule(BaseRuleRo rule) {ExpressionRule expressionRule = new ExpressionRule();expressionRule.setId(ruleMapper.nextSque());expressionRule.setCreateTime(new Date());expressionRule.setEnable(true);expressionRule.setRuleGroup(rule.getRuleGroup());expressionRule.setRuleCode(rule.getRuleCode());expressionRule.setRuleDescription(rule.getRuleDescription());expressionRule.setRuleName(rule.getRuleName());expressionRule.setMessage(rule.getMessage());// 核心代码段expressionRule.setWhenExpression(rule.getWhenExpression("fact"));expressionRule.setThenExpression(rule.getThenExpression("result"));// TODO 获取用户信息// expressionRule.setCreatUser(userHandler.getUserName());ruleMapper.insert(expressionRule);// 条件表List<ExpressionRuleCondition> conditionList = new ArrayList<>();rule.getConditionRoList().forEach(condition->{ExpressionRuleCondition expressionRuleCondition = new ExpressionRuleCondition();expressionRuleCondition.setId(conditionMapper.nextSque());expressionRuleCondition.setMasterId(expressionRule.getId());expressionRuleCondition.setLeftBrackets(condition.getLeftBrackets());expressionRuleCondition.setField(condition.getField());expressionRuleCondition.setOperator(condition.getOperator());expressionRuleCondition.setValueType(condition.getValueType());expressionRuleCondition.setValue(condition.getValue());expressionRuleCondition.setRightBrackets(condition.getRightBrackets());expressionRuleCondition.setLink(condition.getLink());conditionList.add(expressionRuleCondition);});conditionMapper.insertBatch(conditionList);return ResponseResult.buildSucc(expressionRule.getId());}

RO

@Slf4j
@Data
@ToString
public class BaseRuleRo {/*** 主键*/@ApiModelProperty(value = "id")Long id;/*** 规则组*/@ApiModelProperty(value = "ruleGroup",required = true)String ruleGroup;/*** 规则标识(英文,且唯一)*/@ApiModelProperty(value = "ruleCode",required = true)String ruleCode;/*** 规则名*/@ApiModelProperty(value = "ruleName",required = true)String ruleName;/*** 规则描述*/@ApiModelProperty(value = "ruleDescription",required = true)String ruleDescription;/*** 条件*/@ApiModelProperty(value = "conditionRoList",required = true)List<ConditionRo> conditionRoList;/*** 满足规则后可以带这个值*/@ApiModelProperty(value = "message",required = true)String message;/*** 是否启用*/@ApiModelProperty(value = "isEnable")boolean isEnable = true;/*** 条件表达式*/@ApiModelProperty(hidden=true)@JsonIgnoreprivate String whenExpression;/*** 结果表达式*/@ApiModelProperty(hidden=true)@JsonIgnoreprivate String thenExpression;/*** 组装when表达式*/public String getWhenExpression(String factAlias) throws UnSupportException {StringBuilder expression = new StringBuilder();conditionRoList.forEach(conditionRo -> {expression.append(conditionRo.leftBrackets).append(factAlias)// 从JSON中取出字段值.append(".get(\"").append(conditionRo.field).append("\")").append(conditionRo.getOperatorExpress(factAlias)).append(conditionRo.rightBrackets).append(conditionRo.getLinkExpress());});log.info("whenExpression: {}",expression.toString());return expression.toString();}/*** 组装then表达式* 不做太过灵活的操作,值返回是否命中规则,至于命中后改干什么业务代码自己实现*/public String getThenExpression(String resultAlias){StringBuilder expression = new StringBuilder();expression.append(resultAlias).append(".setValue(\"").append(message).append("\");");log.info("thenExpression: {}",expression.toString());return expression.toString();}
}
@Data
@ToString(callSuper = true)
public class ConditionRo {/*** 左括号* ( ~ (((((*/@ApiModelProperty(value = "leftBrackets",required = true)String leftBrackets;/*** 字段*/@ApiModelProperty(value = "field",required = true)String field;/*** 操作* 大于,小于,等于,不等于,包含,不包含,前缀,后缀* >  , <  , ==, !=  , contains , !contains, startWith, endWith**/@ApiModelProperty(value = "operator",required = true)String operator;/*** 值字段类型* 自定义输入 或 实体字段*  input , field*/@ApiModelProperty(value = "valueType",required = true)String valueType;/*** 字段规则命中值*/@ApiModelProperty(value = "value",required = true)String value;/*** 右括号* ) ~ )))))*/@ApiModelProperty(value = "rightBrackets",required = true)String rightBrackets;/*** 多条件连接符号* && ~ ||*/@ApiModelProperty(value = "link",required = true)String link;/*** 运算符表达式*/String getOperatorExpress(String factAlias) throws UnSupportException {if(operator.equalsIgnoreCase(RuleOperation.OPERATOR_GREATER_THEN)){return ">"+getValueExpress(factAlias);}if(operator.equalsIgnoreCase(RuleOperation.OPERATOR_LESS_THEN)){return "<"+getValueExpress(factAlias);}if(operator.equalsIgnoreCase(RuleOperation.OPERATOR_QEUAL)){return "=="+getValueExpress(factAlias);}if(operator.equalsIgnoreCase(RuleOperation.OPERATOR_UNQEUAL)){return "!="+getValueExpress(factAlias);}if(operator.equalsIgnoreCase(RuleOperation.OPERATOR_CONTAIN)){return ".contains("+getValueExpress(factAlias)+")";}if(operator.equalsIgnoreCase(RuleOperation.OPERATOR_PREFIX)){return ".startsWith("+getValueExpress(factAlias)+")";}if(operator.equalsIgnoreCase(RuleOperation.OPERATOR_SUFFIX)){return ".endsWith("+getValueExpress(factAlias)+")";}throw new UnSupportException(operator+" is not support ");}/*** 比较值表达式*/private String getValueExpress(String factAlias) throws UnSupportException{if(!valueType.equalsIgnoreCase(RuleOperation.INPUT_VALUE) && !valueType.equalsIgnoreCase(RuleOperation.FIELD_VALUE)){throw new UnSupportException(valueType+" is not support ");}return valueType.equalsIgnoreCase(RuleOperation.INPUT_VALUE)? String.format("\"%s\"", value) : String.format("%s.get(\"%s\")", factAlias, value);}/*** 连接符表达式*/String getLinkExpress() throws UnSupportException{if(StringUtils.isEmpty(link)){return "";}if(link.equalsIgnoreCase(RuleOperation.LINK_AND)){return "&&";}if(link.equalsIgnoreCase(RuleOperation.LINK_OR)){return "||";}throw new UnSupportException(link+" is not support ");}
}
匹配规则

controller

    /*** 匹配规则*/@PostMapping("/match")@ApiOperation("匹配规则")public ResponseResult<List<RuleResult>> match(@RequestBody RuleMatchRo matchRo){return ruleService.match(matchRo);}

serviceImpl

    /*** 匹配规则*/@Overridepublic ResponseResult<List<RuleResult>> match(RuleMatchRo ruleRo) {try{if(CollectionUtils.isEmpty(ruleRo.getRuleIds())) {return ResponseResult.buildFail("ruleIds为空");}// 查询规则,先查redis,再查DBList<ExpressionRule> rules = getRuleList(ruleRo.getRuleIds());// 进行规则匹配List<RuleResult> results = new ArrayList<>();rules.forEach(rule -> {RuleResult matchResult = RuleUtils.match(ruleRo.getFact(),rule);results.add(matchResult);});return ResponseResult.buildSucc(results);}catch (Exception e){log.error("匹配规则异常",e);return ResponseResult.buildFail("匹配规则异常!");}}

RO

@Data
public class RuleMatchRo {/*** 需要匹配的规则ID列表*/@ApiModelProperty(value = "ruleIds")List<Long> ruleIds;/*** 数据源*/@ApiModelProperty(value = "fact")JSONObject fact;
}

http://www.lryc.cn/news/307415.html

相关文章:

  • Mac电脑配置环境变量
  • Windows系统x86机器安装(麒麟、统信)ARM系统详细教程
  • 消息中间件篇之RabbitMQ-高可用机制
  • express+mysql+vue,从零搭建一个商城管理系统5--用户注册
  • canvas水波纹效果,jquery鼠标水波纹插件
  • Zookeeper客户端命令、JAVA API、监听原理、写数据原理以及案例
  • [嵌入式系统-34]:RT-Thread -19- 新手指南:RT-Thread标准版系统架构
  • postman访问k8s api
  • UE4c++ ConvertActorsToStaticMesh
  • Qt中tableView控件的使用
  • 【医学影像】LIDC-IDRI数据集的无痛制作
  • MacOS开发环境搭建详解
  • 全量知识系统问题及SmartChat给出的答复 之2
  • 嵌入式驱动学习第一周——vim的使用
  • loop_list单向循环列表
  • Python爬虫实战第二例【二】
  • Eclipse是如何创建web project项目的?
  • Excel的中高级用法
  • 【ArcGIS】基本概念-空间参考与变换
  • Qt QWidget 简约美观的加载动画 第五季 - 小方块风格
  • 针对KZG承诺和高效laconic OT的extractable witness encryption
  • Spring Boot中实现列表数据导出为Excel文件
  • 华为ipv6 over ipv4 GRE隧道配置
  • 项目解决方案:海外门店视频汇聚方案(全球性的连锁店、国外连锁店视频接入和汇聚方案)
  • Java中的数据类型详解
  • ABBYY FineReader16文档转换、PDF管理与文档比较功能介绍
  • 导览系统厂家|景区电子导览|手绘地图|AR导览|语音导览系统
  • oracle 如何使用脚本实现访问控制(无需额外插件)
  • 【C语言】指针初阶
  • 07_html