没有规矩,不成方圆;

一、布景

前段时间,在做项目重构的时分,遇到许多当地需求做许多的条件判别。当然能够用许多的if-else判别去处理,可是其时也不清楚怎么回事,就想玩点其他。于是乎,就去调研了规矩引擎。

当然,市道上有许多老练的规矩引擎,功用许多,功用很好。可是,便是想玩点不相同的(咱们做技术选型别这样,这个是反面教材)。终究一款URule的规矩引擎招引了我,首要仍是选用浏览器可直接装备,不需求过多安装,可视化规矩也做的不错。经过一系列调研,后边就把它接入了项目中,顺便记录下调研的成果。

二、介绍

规矩引擎其实是一种组件,它能够嵌入到程序当中。将程序杂乱的判别规矩从事务代码中剥离出来,使得程序只需求关心自己的事务,而不需求去进行杂乱的逻辑判别;简略的了解是规矩接受一组输入的数据,经过预定好的规矩装备,再输出一组成果。

当然,市道上有许多老练的规矩引擎,如:Drools、Aviator、EasyRules等等。可是URule,它能够运行在Windows、Linux、Unix等各种类型的操作体系之上,选用纯浏览器的修正方式,不需求安装工具,直接在浏览器上修正规矩和测验规矩。

当然这款规矩引擎有开源和pro版别的差异,至于pro版是啥,懂的都懂,下面放个表格,了解下详细的差异

特性 PRO版 开源版
导游式决议计划集
脚本式决议计划集
决议计划树
决议计划流
决议计划表
交叉决议计划表
杂乱评分卡
文件名、项目名重构
参数名、变量常量名重构
Excel决议计划表导入
规矩集模版保存与加载
中文项目名和文件名支撑
服务器推送常识包到客户端功用的支撑
常识包优化与压缩的支撑
客户端服务器方式下大常识包的推拉支撑
规矩集中履行组的支撑
规矩流中所有节点导游式条件与动作装备的支撑
循环规矩多循环单元支撑
循环规矩中无条件履行的支撑
导入项目主动重命名功用
规矩树构建优化
目标查找索引支撑
规矩树中短路核算的支撑
规矩条件冗余核算缓存支撑
基于计划的批量场景测验功用
常识包调用监控
更为完善的文件读写权限操控
常识包版别操控
SpringBean及Java类的热布置
技术支撑

三、安装运用

实际运用时,有四种运用URule Pro的办法,分别是嵌入式方式、本地方式、分布式核算方式以及独立服务方式。

可是咱们这儿不考虑URule Pro,咱自己整个开源版,在开源版集成springboot的基础上做一个二次开发,搜了一圈,其实就有处理计划。大致的项目模块如下:

URule规则引擎
自己创立个空数据库,只需求在edas-rule-server服务中修正下数据库的装备,然后发动服务即可。第一次发动完结,数据库中会创立表。

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/urule-data?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&useSSL=false
spring.datasource.username=root
spring.datasource.password=mysql

上面说过,它是纯用浏览器进行修正,装备规矩的,只需求打开浏览器,输入地址:http://localhost:8090/urule/frame,看到这个界面,就阐明发动成功了。

URule规则引擎

四、基础概念

3.1全体介绍

先说下URule它的构成部分,首要是两部分:1、规划器部分 2、规矩履行引擎。规划器部分首要是库文件和规矩文件构成。下面看下全体的结构图

URule规则引擎

3.2库文件

如上图介绍的,库文件有4种,包含变量库,参数库,常量库和动作库。其实类似于Java开发的体系中的实体目标,枚举,常量以及办法。

上面说过,规矩都是可视化装备的。在装备规矩的过程中,就需求引入各种现已界说好的库文件,再结合事务需求,然后装备出符合事务场景的事务规矩,所以哪里都有库文件的身影。

3.2.1变量库文件

在事务开发中,咱们会创立许多Getter和Setter的Java类,比方PO、VO、BO、DTO、POJO等等,其实这些类new目标后首要起到的效果便是数据的载体,用来传输数据。

在URule中,变量库便是用来映射这些目标,然后能够在规矩中运用,终究完结事务和规矩的互动。终究上一张图,用来创立变量库

URule规则引擎
对了,上面废话了这么多可视化装备,这才是第一次展示装备界面,惭愧惭愧。

上图一目了然,在“库”这个菜单底下右键,然后点击增加变量库即可,终究界说自己喜爱的变量库名,当然名字只支撑中文或许英文,其他字符不可用。

URule规则引擎
创立完变量库后,就能够对变量库进行修正,能够认为便是给POJO增加特点

URule规则引擎
也不弯弯绕绕讲什么术语,就个人了解。图左面是创立类,其间称号是它的别号,装备规矩用它替代这个类。图右边是类的特点,我这儿随便写了几个,估量看了懂得都懂。

终究在事务体系中创立对应的类,注意全限定名和装备变量库的类路径共同。

package com.cicada;
import com.bstek.urule.model.Label;
import lombok.Data;
/**
 * @author 往事如风
 * @version 1.0
 * @date 2023/3/3 15:38
 * @description
 */
@Data
public class Stu {
    @Label("名字")
    private String name;
    @Label("年纪")
    private int age;
    @Label("班级")
    private String classes;
}

终究说下这个@Label注解,这个是由URule供给的注解,首要是描述字段的特点,跟变量库的标题一栏共同就行。听官方介绍能够经过这个注解,完成POJO特点和变量库特点映射。便是POJO写好,然后对应规矩的变量库就不需求重新写,能够直接生成。反正就有这个功用,这儿就直接一笔带过了。

3.2.2常量库文件

说到常量库,这个就能够认为是咱们Java体系中的常量,枚举。比方性别,要界说枚举吧;比方对接的机构,也能够界说一个枚举吧。

当然,类似于变量库,常量库也能够完成和体系中的枚举相互映射,这样做的优点能够避免咱们手动输入,避免输入过错。创立常量库也比较简略,直接在“库”这个菜单下右键,“增加常量库”。

创立好常量库文件后,也会出现如下页面:

URule规则引擎

3.2.3参数库文件

参数库,便是URule规矩中的暂时变量,变量的类型和数量不固定。能够认为类似于Map,实际上存储参数库的也便是个Map。

同样的套路,直接在“库”这个菜单下右键,“增加参数库”。

URule规则引擎
能够看到,参数库现已少了左面分类这一项,直接增加参数,挑选类型便是干,相对简略了许多。“称号”这列我这儿用了英文,便是Map中的key,而“标题”这列便是在装备规矩时分显示用的,中文看着比较直观。

当然还需求注意的点是,界说的称号要保证仅有,由于Map中的key是仅有的,不然就会存在掩盖的情况。

3.2.4动作库文件

动作库能够对装备在spring中的bean办法进行映射,然后能够在规矩中直接调用这批办法。 惯用套路,仍是在“库”菜单下右键,点击“增加动作库”。

URule规则引擎
然后我在体系中增加了一个类Action,然后在类上符号@Component注解,将该类交给spring的bean容器办理。该类中增加一些办法,在办法上符号@ExposeAction注解,该注解是URule界说的,阐明被符号的办法都会被动作库读取到。

package com.bstek.urule.cicada;
import com.bstek.urule.action.ActionId;
import com.bstek.urule.model.ExposeAction;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
 * @author 往事如风
 * @version 1.0
 * @date 2023/3/10 13:59
 * @description
 */
@Component("action")
public class Action {
    @ActionId("Hello")
    public String hello(){
        return "hello";
    }
    @ExposeAction(value="办法1")
    public boolean evalTest(String username){
        if(username==null){
            return false;
        }else if(username.equals("张三")){
            return true;
        }
        return false;
    }
    @ExposeAction(value="测验Int")
    public int testInt(int a,int b){
        return a+b;
    }
    @ExposeAction(value="打印内容")
    public void printContent(String username, Date birthday){
        SimpleDateFormat sd=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if(birthday!=null){
            System.out.println(username+"本年现已"+sd.format(birthday)+"岁了!");
        }else{
            System.out.println("Hello "+username+"");
        }
    }
    @ExposeAction(value="打印Stu")
    public void printUser(Stu m){
        System.out.println("Hello "+m.getName()+", is age:"+m.getAge());
    }
}

终究在动作库页面上增加bean,“Bean Id”一列输入对应的spring bean的称号,这儿输入action。然后点击操作列中的小手按钮,就会弹出刚在Action类中符号了ExposeAction注解的办法。挑选一个指定的办法增加进来,终究看到办法对应的参数也会被主动加载进去。

URule规则引擎

URule规则引擎

终究,变量库、参数库、动作库、常量库这些库文件界说好后,各种规矩文件装备的时分就能够导入他们。可是一旦这些库文件被某个规矩文件运用,就不要随意修正库文件了。

3.3规矩集

说到规矩集,顾名思义,便是装备规矩了。前面界说的库文件就需求导入到规矩集中去装备运用。它是运用频率最高的一个事务规矩完成办法。

规矩集说的是规矩的调集,由三个部分规矩组成:如果、那么、否则。

在规矩集的界说的办法上,URule由导游式和脚本式两种;

  • 导游式规矩集:便是在页面上经过鼠标点点点,高度的可视化装备,不是开发都能懂,这也是这个规矩引擎的亮点所在。
  • 脚本式规矩集:听名字就知道了,这玩意要写脚本的。拉高装备门槛,需求懂点编码的人来编写。

3.3.1导游式规矩集

仍是相同,首先新建。这次是在“决议计划集”菜单上右键,点击“增加导游式决议计划集”,这样就创立好一个规矩集了。

URule规则引擎
在装备规矩前,能够先导入前面界说好的库文件。我这儿导入变量库文件,页面上点击“变量库”,然后挑选指定的变量库文件即可。如图所示;

URule规则引擎
终究,能够愉快的装备规矩了,导游式没什么好讲的,都是可视化界面,点点点即可。下面是我装备的一个简略的规矩集;

URule规则引擎
能够看到由三部分组成:如果、那么、否则;

  1. 如果:装备规矩的条件;
  2. 那么:装备满意条件后履行的动作,一般装备变量赋值比较多
  3. 否则:装备不满意条件履行的动作

终究,附上增加完规矩后,经过代码去履行规矩;

package com.cicada;
import cn.hutool.core.bean.BeanUtil;
import com.Result;
import com.bstek.urule.Utils;
import com.bstek.urule.runtime.KnowledgePackage;
import com.bstek.urule.runtime.KnowledgeSession;
import com.bstek.urule.runtime.KnowledgeSessionFactory;
import com.bstek.urule.runtime.service.KnowledgeService;
import com.cicada.req.StuReq;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
/**
 * @author 往事如风
 * @version 1.0
 * @date 2023/3/10 16:47
 * @description
 */
@RestController
@RequestMapping("/rule")
public class RuleDataController {
    @PostMapping("/stu")
    public Result rule(@RequestBody StuReq stuReq) throws IOException {
        KnowledgeService knowledgeService = (KnowledgeService) Utils.getApplicationContext().getBean(KnowledgeService.BEAN_ID);
        KnowledgePackage knowledgePackage = knowledgeService.getKnowledge("xxx/xxx");
        KnowledgeSession knowledgeSession = KnowledgeSessionFactory.newKnowledgeSession(knowledgePackage);
        Stu stu = BeanUtil.copyProperties(stuReq, Stu.class);
        knowledgeSession.insert(stu);
        knowledgeSession.fireRules();
        return Result.success(stu.getTeacher());
    }
}

URule规则引擎
恳求接口,终究参数符合装备的条件,回来“那么”中装备的输出成果。

3.3.2脚本式规矩集

脚本式的规矩集,各种原理都是和导游式一模相同,无非便是拉高门槛,用写脚本的办法去完成装备的规矩。这儿不做过多的介绍了。

3.4决议计划表

再聊下决议计划表,其实它便是规矩集的另一种展示方式,比较相对规矩集,我更喜爱用决议计划表去装备规矩,应为它呈现的愈加直观,更便于了解。可是实质和规矩集没啥差异。

也不打开过多的赘述,这儿我就放一张装备过的决议计划表;

URule规则引擎

3.5其他

当然,还有其他的概念和功用,这儿也纷歧一介绍了,由于上面说的现已是最常用的了,想了解的能够自行去了解。其他功用包含:交叉决议计划表、评分卡、杂乱评分卡、决议计划树、规矩流;当然,其间有些是Pro版的功用。

四、运用场景

最近在开发一期大版别的需求,其间就有个场景,详细如下; 参加购买订单的用户都会有自己的一个职级,也能够说是角色。每个用户都会有三个职位:普通用户、会员、精英会员。

然后,每个月初都会对用户进行一次提升处理,普通用户到达要求,就会提升为会员,会员到达要求就会提升为精英会员。

当然,普通用户提升会员,会员提升精英会员,都会有不同的规矩;

  1. 普通用户->会员:3个月内帮注册人数到达3人;3个月内自己和底下团队的人,下单金额超越1万;个人的订单持续率超越80%。
  2. 会员->精英会员:3个月内帮注册人数到达6人;3个月内自己和底下团队的人,下单金额超越5万;个人的订单持续率超越90%。
  3. 不能跨级提升,普通用户最多只能到会员,到达会员了才干提升到精英会员。

当然,这仅仅做过简化的一部分需求,我做过稍许的改动,实在的需求场景并没有这么简略。

下面,我对这个需求做一个规矩的装备,这儿用一个决议计划表进行装备;在装备规矩前,我增加一个变量库文件和常量库;

URule规则引擎

URule规则引擎
终究,增加一个决议计划表,并进行规矩装备;

URule规则引擎
能够看到,表格总共五列,其间前四列是规矩,终究一列是满意规矩后输出的信息。这样看着就很明晰,即便并不是技术人员,也能够轻松看懂其间的规矩。

五、总结

规矩引擎关于咱们的体系而言可用可不用,它能够如虎添翼,协助咱们剥离出事务中需求进行很多判别的场景。可是,这种规矩的剥离,需求咱们开发人员对需求进行了解,在了解的基础上进行抽象概念的具化。这,也是整个编程的必经之路

六、参阅源码

编程文档:
https://gitee.com/cicadasmile/butte-java-note
应用仓库:
https://gitee.com/cicadasmile/butte-flyer-parent