Spring Boot + URule 实现可视化规则引擎,太优雅了!

👉 这是一个或许对你有用的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入「芋道快速开发平台」知识星球。下面是星球提供的部分资料: 

892785b94592588bcb7b0cd417fa0fc7.gif

👉这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、商城、支付、工作流、大屏报表、微信公众号等等功能:

  • Boot 仓库:https://gitee.com/zhijiantianya/ruoyi-vue-pro

  • Cloud 仓库:https://gitee.com/zhijiantianya/yudao-cloud

  • 视频教程:https://doc.iocoder.cn

【国内首批】支持 JDK 21 + SpringBoot 3.2.2、JDK 8 + Spring Boot 2.7.18 双版本 

来源:juejin.cn/post/
7210194936276680759


前段时间,在做项目重构的时候,遇到很多地方需要做很多的条件判断。当然可以用很多的if-else判断去解决,但是当时也不清楚怎么回事,就想玩点别的。于是乎,就去调研了规则引擎。

当然,市面上有很多成熟的规则引擎,功能很多,性能很好。但是,就是想玩点不一样的(大家做技术选型别这样,这个是反面教材)。最终一款URule的规则引擎吸引了我,主要还是采用浏览器可直接配置,不需要过多安装,可视化规则也做的不错。经过一系列调研,后面就把它接入了项目中,顺便记录下调研的结果。

1. 介绍

规则引擎其实是一种组件,它可以嵌入到程序当中。将程序复杂的判断规则从业务代码中剥离出来,使得程序只需要关心自己的业务,而不需要去进行复杂的逻辑判断;简单的理解是规则接受一组输入的数据,通过预定好的规则配置,再输出一组结果。

当然,市面上有很多成熟的规则引擎,如:Drools、Aviator、EasyRules等等。但是URule,它可以运行在Windows、Linux、Unix等各种类型的操作系统之上,采用纯浏览器的编辑模式,不需要安装工具,直接在浏览器上编辑规则和测试规则。

当然这款规则引擎有开源和pro版本的区别,至于pro版是啥,懂的都懂,下面放个表格,了解下具体的区别

4236b17e38900de30393b65655ce1de2.png a6d146fb9275901ac158f8fc45d06309.png 3a10da4600009f718f5f2f6aeb7e7bfc.png

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

2. 安装使用

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

但是我们这里不考虑URule Pro,咱自己整个开源版,在开源版集成springboot的基础上做一个二次开发,搜了一圈,其实就有解决方案。大致的项目模块如下:

bc448ad190edbb4ff7f898f70e4cf286.jpeg

自己创建个空数据库,只需要在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,看到这个界面,就说明启动成功了。

d71d75e4e6597fd073fa5aaaf10cf729.jpeg

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/yudao-cloud

  • 视频教程:https://doc.iocoder.cn/video/

3. 基础概念

3.1整体介绍

先说下URule它的构成部分,主要是两部分:1、设计器部分 2、规则执行引擎。设计器部分主要是库文件和规则文件构成。下面看下整体的结构图

e859a5ee850b24b3a53cbe4f8e915daf.jpeg

3.2 库文件

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

上面说过,规则都是可视化配置的。在配置规则的过程中,就需要引入各种已经定义好的库文件,再结合业务需求,从而配置出符合业务场景的业务规则,所以哪里都有库文件的身影。

3.2.1变量库文件

在业务开发中,我们会创建很多Getter和Setter的Java类,比如PO、VO、BO、DTO、POJO等等,其实这些类new对象后主要起到的作用就是数据的载体,用来传输数据。

在URule中,变量库就是用来映射这些对象,然后可以在规则中使用,最终完成业务和规则的互动。最后上一张图,用来创建变量库

13dde04b25fbf9d5e3a9558d4569870e.jpeg

对了,上面废话了这么多可视化配置,这才是第一次展示配置界面,惭愧惭愧。

上图一目了然,在“库”这个菜单底下右键,然后点击添加变量库即可,最后定义自己喜欢的变量库名,当然名字只支持中文或者英文,其他字符不可用。

9eb207c12aa394ba10d5a40e9d9b6837.jpeg 创建完变量库后,就可以对变量库进行编辑,可以认为就是给POJO添加属性

94015992f557de83609ec75646c879bf.jpeg 也不弯弯绕绕讲什么术语,就个人理解。图左边是创建类,其中名称是它的别名,配置规则用它代替这个类。图右边是类的属性,我这里随便写了几个,估计看了懂得都懂。

最后在业务系统中创建对应的类,注意全限定名和配置变量库的类路径一致。

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系统中的常量,枚举。比如性别,要定义枚举吧;比如对接的机构,也可以定义一个枚举吧。

当然,类似于变量库,常量库也可以实现和系统中的枚举相互映射,这样做的好处可以避免我们手动输入,防止输入错误。创建常量库也比较简单,直接在“库”这个菜单下右键,“添加常量库”。

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

5eecb4eec795f8a4a848920f43012773.jpeg
3.2.3参数库文件

参数库,就是URule规则中的临时变量,变量的类型和数量不固定。可以认为类似于Map,实际上存储参数库的也就是个Map。

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

0fc94ebd00ff082b49405e02faa23c3e.jpeg 可以看到,参数库已经少了左边分类这一项,直接添加参数,选择类型就是干,相对简单了很多。“名称”这列我这里用了英文,就是Map中的key,而“标题”这列就是在配置规则时候显示用的,中文看着比较直观。

当然还需要注意的点是,定义的名称要保证唯一,因为Map中的key是唯一的,不然就会存在覆盖的情况。

3.2.4动作库文件

动作库可以对配置在spring中的bean方法进行映射,然后可以在规则中直接调用这批方法。惯用套路,还是在“库”菜单下右键,点击“添加动作库”。

fac62b81ffbe627c853f23c4950b7444.jpeg 然后我在系统中添加了一个类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注解的方法。选择一个指定的方法添加进来,最后看到方法对应的参数也会被自动加载进去。

9fbbafad91e0c25552da4ee9bc48f833.jpeg d205fd5d9f7c038e8a272851ecf30c57.jpeg

最后,变量库、参数库、动作库、常量库这些库文件定义好后,各种规则文件配置的时候就可以导入他们。但是一旦这些库文件被某个规则文件使用,就不要随意修改库文件了。

3.3规则集

说到规则集,顾名思义,就是配置规则了。前面定义的库文件就需要导入到规则集中去配置使用。它是使用频率最高的一个业务规则实现方式。

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

在规则集的定义的方式上,URule由向导式和脚本式两种;

  • 向导式规则集 :就是在页面上通过鼠标点点点,高度的可视化配置,不是开发都能懂,这也是这个规则引擎的亮点所在。

  • 脚本式规则集 :听名字就知道了,这玩意要写脚本的。拉高配置门槛,需要懂点编码的人来编写。

3.3.1向导式规则集

还是一样,首先新建。这次是在“决策集”菜单上右键,点击“添加向导式决策集”,这样就创建好一个规则集了。

5a3987f2a8a33ed59ea249f3df370559.jpeg 在配置规则前,可以先导入前面定义好的库文件。我这里导入变量库文件,页面上点击“变量库”,然后选择指定的变量库文件即可。如图所示;

45fba0ddeb26de1ca83994bd75da415e.jpeg 最后,可以愉快的配置规则了,向导式没什么好讲的,都是可视化界面,点点点即可。下面是我配置的一个简单的规则集;

0813ffe2b97788a3fcd2578dad6febff.jpeg 可以看到由三部分组成:如果、那么、否则;

  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());
    }
}
ecd455ac1d059c147b20cccffe1c513b.jpeg

请求接口,最终参数符合配置的条件,返回“那么”中配置的输出结果。

3.3.2脚本式规则集

脚本式的规则集,各种原理都是和向导式一模一样,无非就是拉高门槛,用写脚本的方式去实现配置的规则。这里不做过多的介绍了。

3.4决策表

再聊下决策表,其实它就是规则集的另一种展示形式,比较相对规则集,我更喜欢用决策表去配置规则,应为它呈现的更加直观,更便于理解。但是本质和规则集没啥区别。

也不展开过多的赘述,这里我就放一张配置过的决策表;

285bf59ed8ef08435aae177194e0ced8.jpeg

3.5其他

当然,还有其他的概念和功能,这里也不一一介绍了,因为上面说的已经是最常用的了,想了解的可以自行去了解。其他功能包括:交叉决策表、评分卡、复杂评分卡、决策树、规则流;当然,其中有些是Pro版的功能。

4. 运用场景

最近在开发一期大版本的需求,其中就有个场景,具体如下;参与购买订单的用户都会有自己的一个职级,也可以说是角色。每个用户都会有三个职位:普通用户、会员、精英会员。

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

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

  1. 普通用户->会员:3个月内帮注册人数达到3人;3个月内自己和底下团队的人,下单金额超过1万;个人的订单继续率超过80%。

  2. 会员->精英会员:3个月内帮注册人数达到6人;3个月内自己和底下团队的人,下单金额超过5万;个人的订单继续率超过90%。

  3. 不能跨级晋升,普通用户最多只能到会员,达到会员了才能晋升到精英会员。

当然,这只是做过简化的一部分需求,我做过稍许的改动,真实的需求场景并没有这么简单。

下面,我对这个需求做一个规则的配置,这里用一个决策表进行配置;在配置规则前,我添加一个变量库文件和常量库;

a03e8a652602978cb8ac9f399f162d5a.jpeg 660af25d80570717a4863e51d9c4e1ca.jpeg

最后,添加一个决策表,并进行规则配置;

275da49f340fd1b13dc3659d22a51b51.jpeg

可以看到,表格一共五列,其中前四列是规则,最后一列是满足规则后输出的信息。这样看着就很清晰,即使并不是技术人员,也可以轻松看懂其中的规则。

5. 总结

规则引擎对于我们的系统而言可用可不用,它可以锦上添花,帮助我们剥离出业务中需要进行大量判断的场景。但是,这种规则的剥离,需要我们开发人员对需求进行理解,在理解的基础上进行抽象概念的具化。这,也是整个编程的必经之路


欢迎加入我的知识星球,全面提升技术能力。

👉 加入方式,长按”或“扫描”下方二维码噢

6035147d3a0ec393dbea450f6782b6bd.png

星球的内容包括:项目实战、面试招聘、源码解析、学习路线。

e04857a2929815959b973ae75792334e.png

87a1a39478d6a41b29511b6b1b1dd490.png612d484aabbf5422bfbb2d13f220afe8.png9bb327d44f9e8aacb615c8e3bcc2b20a.pngdedeae48eaf07acc1769854de3731932.png

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现搜索引擎一般需要以下步骤: 1. 数据库建表和数据导入:根据需要建立相应的数据库表,并导入数据。 2. Elasticsearch安装和配置:安装Elasticsearch,配置Elasticsearch集群,并将数据导入到Elasticsearch中。 3. Spring Boot和Vue.js项目搭建:使用Spring Boot和Vue.js框架搭建项目。 4. 搜索功能实现:使用Elasticsearch进行搜索功能的实现。 具体实现步骤如下: 1. 数据库建表和数据导入 根据需求建立相应的数据库表,并将数据导入到数据库中。这里以MySQL为例,建立一个books表: CREATE TABLE `books` ( `id` int NOT NULL AUTO_INCREMENT, `title` varchar(255) DEFAULT NULL, `author` varchar(255) DEFAULT NULL, `content` text, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 将数据导入到books表中: INSERT INTO `books` (`id`, `title`, `author`, `content`) VALUES (1, 'Java编程思想', 'Bruce Eckel', 'Java编程思想是一本Java入门书籍。'), (2, 'Spring Boot实战', 'Craig Walls', 'Spring Boot实战是一本介绍Spring Boot框架的书籍。'), (3, 'Vue.js实战', '梁灏', 'Vue.js实战是一本介绍Vue.js框架的书籍。'); 2. Elasticsearch安装和配置 安装Elasticsearch,配置Elasticsearch集群,并将数据导入到Elasticsearch中。这里以Elasticsearch 7.2.0为例,安装步骤如下: (1)下载Elasticsearch 官网下载地址:https://www.elastic.co/downloads/elasticsearch (2)解压并启动Elasticsearch 解压后进入bin目录,执行以下命令启动Elasticsearch: ./elasticsearch (3)安装中文分词器 Elasticsearch默认使用英文分词器,需要安装中文分词器,这里使用IK Analyzer中文分词器。IK Analyzer的GitHub地址为:https://github.com/medcl/elasticsearch-analysis-ik 下载IK Analyzer插件: wget https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.2.0/elasticsearch-analysis-ik-7.2.0.zip 将插件安装到Elasticsearch中: ./elasticsearch-plugin install file:///path/to/elasticsearch-analysis-ik-7.2.0.zip (4)将数据导入到Elasticsearch中 使用Elasticsearch的API将数据库中的数据导入到Elasticsearch中。 3. Spring Boot和Vue.js项目搭建 使用Spring Boot和Vue.js框架搭建项目,这里不再赘述。 4. 搜索功能实现 (1)在Spring Boot中使用Elasticsearch进行搜索 使用Spring Data Elasticsearch实现与Elasticsearch的交互,具体步骤如下: 1. 在pom.xml中添加Spring Data Elasticsearch依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> 2. 在application.yml中配置Elasticsearch: spring: data: elasticsearch: cluster-name: elasticsearch cluster-nodes: 127.0.0.1:9300 3. 创建一个Book实体类,并使用@Document注解标注该实体类对应的Elasticsearch索引和类型: @Document(indexName = "books", type = "book") public class Book { @Id private Long id; private String title; private String author; private String content; // getter和setter方法省略 } 4. 创建一个BookRepository接口,继承ElasticsearchRepository接口: public interface BookRepository extends ElasticsearchRepository<Book, Long> { } 5. 在BookService中实现搜索功能: @Service public class BookService { @Autowired private BookRepository bookRepository; public List<Book> search(String keyword) { QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, "title", "author", "content"); Iterable<Book> iterable = bookRepository.search(queryBuilder); List<Book> books = new ArrayList<>(); iterable.forEach(books::add); return books; } } (2)在Vue.js中调用搜索接口 使用axios库调用Spring Boot的接口,具体步骤如下: 1. 安装axios库: npm install axios --save 2. 在Vue.js中调用搜索接口: <script> import axios from 'axios'; export default { data() { return { keyword: '', books: [] } }, methods: { search() { axios.get('/api/search?keyword=' + this.keyword).then(response => { this.books = response.data; }).catch(error => { console.log(error); }); } } } </script> 以上就是使用Spring Boot和Vue.js实现Elasticsearch搜索引擎的步骤。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值