快速集成和使用 solon-flow 规则与流引擎(用 yaml 编写业务规则)

本文参考自:https://www.cnblogs.com/studyjobs/p/18125096

规则引擎技术的主要思想是将应用程序中的业务规则分离出来,业务规则不再以程序代码的形式驻留在系统中,而是存储在独立的文件或者数据库中,完全独立于程序。业务人员可以像管理数据一样对业务规则进行管理。业务规则在程序运行时被加载到规则引擎中供应用系统调用。

solon-flow 是新的规则引擎技术,由 OpenSolon 开源组织提供的基于 Java 语言开发的开源规则引擎,可以将复杂且多变的业务规则从硬编码中解放出来,以 yaml 规则脚本的形式存放在文件或特定的存储介质中(例如数据库),使得业务规则的变更不需要修改项目代码、不需要重启服务器就可以立即生效。

本篇博客的 demo 以个税计算器为例,介绍如何使用 solon-flow 规则引擎,有关具体技术细节,限于篇幅有限,这里不会介绍,具体细节可以参考官网。

solon-flow 官网地址:https://solon.noear.org/article/learn-solon-flow

solon-flow 源码下载地址:https://gitee.com/opensolon/solon/tree/main/solon-projects/solon-flow/solon-flow

1、搭建工程

搭建一个 solon 工程,结构如下:

solon-flow 规则引擎将规则编写在以 .yml (很流行的配置文)为后缀的文件中,yml 文件默认也是使用 yaml + java 语言编写,所以学习起来很容易。

一般情况下,我们使用 IDEA 编写业务规则,默认情况下 .yml 文件会被打包到项目 jar 包中,为了方便后续调整规则,我们可以将 yml 文件的内容,存储到数据库中或者 oss 云盘中,程序在运行时从 jar 包外部读取规则内容。

完束上的 pom 文件的内容:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.noear</groupId>
        <artifactId>solon-parent</artifactId>
        <version>3.0.8</version>
        <relativePath />
    </parent>

    <groupId>com.example</groupId>
    <artifactId>demo-rule</artifactId>
    <version>1.0</version>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-web</artifactId>
        </dependency>

        <!-- 规则与流引擎 -->
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-flow</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-logging-simple</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>org.noear</groupId>
            <artifactId>solon-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>

        <plugins>
            <plugin>
                <groupId>org.noear</groupId>
                <artifactId>solon-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2、代码细节展示

此文的 demo 是个税计算器,我们创建一个用于向规则引擎传递数据的实体类

java 复制代码
package com.example.demo.model;

import lombok.Data;

@Data
public class Calculation {
    //税前工资
    private double wage;
    //应纳税所得额
    private double wagemore;
    //税率
    private double cess;
    //速算扣除数
    private double preminus;
    //扣税额
    private double wageminus;
    //税后工资
    private double actualwage;
}

这里不考虑缴纳社保和专项扣除等因素,个税计算的规则如下:

之后我们在 flow/rule.yml 中编写的规则如下:

yaml 复制代码
id: rule
nodes:
  - id: "tax_setWagemore" #计算应纳税所得额
    when: |
      import java.time.LocalDate;
      //2022-10-1 后生效
      return cal.getWage() > 0 && LocalDate.now().compareTo(LocalDate.of(2022,10,1)) > 0;
    task: |
      double wagemore = cal.getWage() - 5000;
      cal.setWagemore(wagemore);
  - id: "tax_3000"  #设置税率、速算扣除数
    when: "cal.getWagemore() <= 3000"
    task: |
      cal.setCess(0.03);//税率
      cal.setPreminus(0);//速算扣除数
  - id: "tax_12000"
    when: "cal.getWagemore() > 3000 && cal.getWagemore() <= 12000"
    task: |
      cal.setCess(0.1);//税率
      cal.setPreminus(210);//速算扣除数
  - id: "tax_25000"
    when: "cal.getWagemore() > 12000 && cal.getWagemore() <= 25000"
    task: |
      cal.setCess(0.2);
      cal.setPreminus(1410);
  - id: "tax_35000"
    when: "cal.getWagemore() > 25000 && cal.getWagemore() <= 35000"
    task: |
      cal.setCess(0.25);
      cal.setPreminus(2660);
  - id: "tax_55000"
    when: "cal.getWagemore() > 35000 && cal.getWagemore() <= 55000"
    task: |
      cal.setCess(0.25);
      cal.setPreminus(2660);
  - id: "tax_80000"
    when: "cal.getWagemore() > 55000 && cal.getWagemore() <= 80000"
    task: |
      cal.setCess(0.35);
      cal.setPreminus(7160);
  - id: "tax_max"
    when: "cal.getWagemore() > 80000"
    task: |
      cal.setCess(0.45);
      cal.setPreminus(15160);
  - id: "tax_result"
    when: "cal.getWage() > 0 && cal.getWagemore() > 0 && cal.getCess() > 0"
    task: |
      //扣税额
      double wageminus = cal.getWagemore() * cal.getCess() - cal.getPreminus();
      double actualwage = cal.getWage() - wageminus;
      cal.setWageminus(wageminus);
      cal.setActualwage(actualwage);
      System.out.println("--税前工资:"+cal.getWage());
      System.out.println("--应纳税所得额:"+cal.getWagemore());
      System.out.println("--税率:" + cal.getCess());
      System.out.println("--速算扣除数:" + cal.getPreminus());
      System.out.println("--扣税额:" + cal.getWageminus());
      System.out.println("--税后工资:" + cal.getActualwage());

本 demo 设定每次被调用时,都去读取 rule.yml 的内容(可时实生效),具体代码在 RuleService 中实现:

java 复制代码
package com.example.demo.dso;

import com.example.demo.model.Calculation;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Inject;
import org.noear.solon.flow.ChainContext;
import org.noear.solon.flow.FlowEngine;

@Component
public class RuleService {
    //调用Drools规则引擎实现个人所得税计算
    public Calculation calculate(Calculation calculation) throws Throwable {
        FlowEngine flowEngine = FlowEngine.newInstance();
        flowEngine.load(Chain.parseByUri("file:src/main/resources/flow/rule.yml")); //动态加载源码下的文件,修改后实时生效

        //构建上下文
        ChainContext ctx = new ChainContext();
        ctx.put("cal", calculation);

        //执行规则
        flowEngine.eval("rule", ctx);

        //返回运行算后的
        return calculation;
    }
}

然后在 RuleController 中对外提供计算个税的接口,只需要传递一个税前工资额即可计算得出结果

java 复制代码
@Mapping("rule")
@Controller
public class RuleController {
    @Inject
    RuleService ruleService;

    @Mapping("calculate")
    public Calculation calculate(double wage) throws Throwable {
        Calculation calculation = new Calculation();
        calculation.setWage(wage);
        calculation = ruleService.calculate(calculation);
        System.out.println(calculation);
        return calculation;
    }
}

3、验证成果

启动后,可以访问接口 http://localhost:8080/rule/calculate?wage=10000 即可查看到静态页面,输入 10000 元计算个税,如下图:

结果可以发现,税率是 0.1,执行的是 rule.yml 文件中的名称为 tax_12000 的规则,此时你可以使用 IDEA 修改一下,比如将税率修改为 0.2

yaml 复制代码
  - id: "tax_12000"
    when: "cal.getWagemore() > 3000 && cal.getWagemore() <= 12000"
    task: |
      cal.setCess(0.2);//这里故意将税率修改为 0.2
      cal.setPreminus(210);//速算扣除数

注意不需要重启 IDEA 的项目(可时实生效),此时重新点击页面中的计算,发现刚刚修改的规则生效了,如下图所示:

好了,以上就是有关 solon 使用 drools 规则引擎的介绍(在 spring 里差不多),有兴趣的话可以下载源代码进行验证。

本示例,源码下载地址:

https://gitee.com/opensolon/solon-flow_rule-demo

相关推荐
振鹏Dong1 小时前
微服务架构及常见微服务技术栈
java·后端
丶小鱼丶1 小时前
二叉树算法之【中序遍历】
java·算法
摇滚侠2 小时前
Oracle 关闭 impdp任务
java
编程爱好者熊浪3 小时前
RedisBloom使用
java
苇柠3 小时前
Spring框架基础(1)
java·后端·spring
yics.3 小时前
数据结构——栈和队列
java·数据结构
架构师沉默3 小时前
我用一个 Postgres 实现一整套后端架构!
java·spring boot·程序人生·架构·tdd
xiucai_cs4 小时前
布隆过滤器原理与Spring Boot实战
java·spring boot·后端·布隆过滤器
向阳花自开4 小时前
Spring Boot 常用注解速查表
java·spring boot·后端
huan_19934 小时前
通过docker构建一个java镜像
java·docker