快速集成和使用 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

相关推荐
s_fox_16 分钟前
Nginx Embedded Variables 嵌入式变量解析(4)
java·网络·nginx
Jelena1577958579222 分钟前
使用Java爬虫获取1688 item_get_company 接口的公司档案信息
java·开发语言·爬虫
数据小小爬虫25 分钟前
Jsoup解析商品详情时,如何确保数据准确性?
java·爬虫
V+zmm1013435 分钟前
自驾游拼团小程序的设计与实现(ssm论文源码调试讲解)
java·数据库·微信小程序·小程序·毕业设计
坚定信念,勇往无前1 小时前
springboot单机支持1w并发,需要做哪些优化
java·spring boot·后端
丁总学Java1 小时前
`AdminAdminDTO` 和 `userSession` 对象中的字段对应起来的表格
java
m0_748240252 小时前
SpringMVC详解
java
剑走偏锋o.O2 小时前
Java四大框架深度剖析:MyBatis、Spring、SpringMVC与SpringBoot
java·spring boot·spring·mybatis
早起的年轻人2 小时前
Java List 自定义对象排序 Java 8 及以上版本使用 Stream API
java·windows·list
柃歌2 小时前
【UCB CS 61B SP24】Lecture 5 - Lists 3: DLLists and Arrays学习笔记
java·数据结构·笔记·学习·算法