首页 > 作文

SpringBoot整合Drools规则引擎动态生成业务规则的实现

更新时间:2023-04-04 02:26:46 阅读: 评论:0

最近的项目中,使用的是flowable工作流来处理业务流程,但是在业务规则的配置中,是在代码中直接固定写死的,领导说这样不好,需要规则可以动态变化,可以通过页面去动态配置改变,所以就花了几天时间去研究了一下drools规则引擎框架。然后应用到了项目中。

首先在项目中引入规则引擎相关依赖

       <properties>        <java.version>1.8</java.version>        <drools.version>7.20.0.final</drools.version>    </properties><dependencies> <!--引入规则引擎-->        <dependency>            <groupid>org.kie</groupid>            <artifactid>kie-spring</artifactid>            <version>${drools.version}</version>            <exclusions>                <exclusion>                    <groupid>org.springframework</groupid>                    <artifactid>spring-tx</artifactid>                </exclusion>                <exclusion>                    <groupid>org.springframework</groupid>                    <artifactid>spring-beans</artifactid>                </exclusion>                <exclusion>                    <groupid>org.springframework</groupid>                    <artifactid>spring-core</artifactid>                </exclusion>                <exclusion>                    <groupid>org.springframework</groupid>                    <artifactid>spring-context</artifactid>                </exclusion>            </exclusions>        </dependency>        <dependency>            <groupid>org.drools</groupid>            <artifactid>drools-compiler</artifactid>            <version>${drools.version}</version>        </dependency>        <dependency>        垃圾袋英文    <groupid>org.projectlombok</groupid>            <artifactid>lombok</artifactid>            <scope>provided</scope>            <version>1.18.20</version>        </dependency></dependencies> <build>        <resources>            <resource>                <directory>src/main/resources</directory>                <includes>                    <include>**/*.*</include>                </includes>            </resource>            <resource>                <directory>src/main/java</directory>                <includes>                    <include>**/*.xml</include>                </includes>            </resource>        </resources>    </build>

这里的drools版本使用的是7.20.0.final,如果想和flowable结合使用,在流程画图中插入规则任务,可以将drools版本和flowable starter中管理的drools版本 一致,比如我现在的项目中用到的

flowable-srping-boot-starter的依赖版本是6.5.0,点进去这个jar包的pom文件

再进一步点parent标签

然后再点parent标签的依赖

然后再点parent标签内的flowable-root,然后搜索drools

可以看到flowable starter集成管理的drools版本是7.6.0-final,所以最好和这个版本保持一致

当然你需要在flowable modeler画图项目中引入,然后启动flowable modeler程序,在画图界面

任务类型中就可以看到一个business rule task,商业规则任务。

如果只是独立使用,则可以直接使用我最开始引入的那个版本7.20.0.final

还有一个问题就是如果你的项目中引入了spring boot的热部署工具,

需要把这个依赖注释掉,项目中不能引入这个jar包,不然这个jar包会影响drools规则引擎执行生成的规则,而且在运行规则的时候也不会报错,这是个很隐蔽的坑,我在项目中已经踩过坑了,所以特别提示一下,就是这个jar包存在,规则引擎在触发执行规则的时候,是不会执行的,在日志信息中一直显示的是执行规则0条,即使你的规则文件语法没有任何错误,直接将这个依赖删除后,就可以正常执行规则了。

引入相关依赖后,需要在项目中添加配置类:

在config包下创建droolsautoconfiguration类

import cn.hutool.core.util.chartutil;import lombok.extern.slf4j.slf4j;import org.kie.api.kieba;import org.kie.api.kiervices;import org.kie.api.builder.*;import org.kie.api.runtime.kiecontainer;import org.kie.api.runtime.kiession;import org.kie.internal.io.resourcefactory;import org.kie.spring.kmodulebeanfactorypostprocessor;import org.springframework.boot.autoconfigure.condition.conditionalonmissingbean;import org.springframework.context.annotation.bean;import org.spri微笑日图片ngframework.context.annotation.configuration;import org.springframework.core.io.resource;import org.springframework.core.io.support.pathmatchingresourcepatternresolver;import org.springframework.core.io.support.resourcepatternresolver; import java.io.ioexception; /** * @author xiaomifeng1010 * @version 1.0 * @date: 2021/12/6 9:30 * @description drools配置类 */@configuration@slf4jpublic class droolsautoconfiguration {    public  static  final string  rule_path="rules/";    public kiervices getkiervices(){        kiervices kiervices = kiervices.factory.get();        return  kiervices;    }     /**     * 管理规则文件的位置路径信息     * @return     * @throws ioexception     */    @bean    @conditionalonmissingbean(kiefilesystem.class)    public kiefilesystem kiefilesystem() throws ioexception {        kiefilesystem kiefilesystem = getkiervices().newkiefilesystem();        for (resource file:getrulefiles()) {            kiefilesystem.write(resourcefactory.newclasspathresource(rule_path+file.getfilename(), chartutil.utf_8));        }        return  kiefilesystem;    }    @bean    @conditionalonmissingbean(kiecontainer.class)    public kiecontainer kiecontainer() throws ioexception {        kiervices kiervices = getkiervices();        kierepository kierepository = kiervices.getrepository();        kierepository.addkiemodule(new kiemodule() {             @override            public releaid getreleaid() {                return kierepository.getdefaultreleaid();            }        });         kiebuilder kiebuilder = kiervices.newkiebuilder(kiefilesystem());        kiebuilder.buildall();        results results = kiebuilder.getresults();        if (results.hasmessages(message.level.error)){            log.error(results.getmessages().tostring());         }        kiecontainer kiecontainer = kiervices.newkiecontainer(kierepository.getdefaultreleaid());        return kiecontainer;    }    @bean    @conditionalonmissingbean(kieba.class)    public kieba kieba() throws ioexception {        kieba kieba = kiecontainer().getkieba();        return kieba;    }     @bean    @conditionalonmissingbean(kiession.class)    public kiession kiession() throws ioexception {        return kiecontainer().newkiession();    }      @bean    @conditionalonmissingbean(kmodulebeanfactorypostprocessor.class)    public kmodulebeanfactorypostprocessor kmodulebeanfactorypostprocessor(){        kmodulebeanfactorypostprocessor kmodulebeanfactorypostprocessor = new kmodulebeanfactorypostprocessor();        return  kmodulebeanfactorypostprocessor;    }      /**     * 获取规则文件资源     * @return     * @throws ioexception     */    private resource[] getrulefiles() throws ioexception {        resourcepatternresolver resourcepatternresolver                =new pathmatchingresourcepatternresolver();        resource[] resources = resourcepatternresolver.getresources("classpath*:" + rule_path + "**/*.*");        return  resources;    }}

然后在项目的resources下创建rules文件夹存放规则文件

创建一个drl后缀的规则文件fixratecostcalculatorrule.drl

//package 可以随意指定,没有具体的要求,可以命名成和项目相关的,或者直接rulespackage com.drools//或者这样//package rules import java.math.bigdecimalimport java.lang.integerimport org.apache.commons.lang3.math.numberutils;import com.drools.bo.guatanteecost//这里设置的全局变量只相当于声明变量,需要在代码执行规则前给该变量赋值初始化global org.slf4j.logger loggerrule "rule1"//dialect "java"salience 30//防止死循环//no-loop trueenabled fal  when      $guaranteecost:guatanteecost(amount>numberutils.double_zero && amount<=300000)  then   $guaranteecost.tcost(200d);   logger.info("保费"+200);   update($guaranteecost)     end rule "rule2" enabled fal salience 20 when  $guaranteecost:guatanteecost(amount>300000,amount<=500000)  then  $guaranteecost.tcost(300d);  logger.info("保费"+300);     update($guaranteecost)   endrule "rule3"enabled falsalience 10when$guaranteecost:guatanteecost(amount>500000,amount<=800000)  then//  效果和上边两条范围中的更新数据效果一样  modify($guaranteecost){    tcost(400d)  }  logger.info("保费"+400);   end

然后需要创建一个java对象guatanteecost,用于向规则文件中传递fact(java对象)变量值

amount是guatanteecost类中的属性

@data@noargsconstructor@allargsconstructorpublic class guatanteecost {     /**     * 保证金金额     */    private double amount;    /**     * 保费金额     */    private double cost;}

然后就可以写一个单元测试方法,或者创建一个controller进行测试

import cn.hutool.core.util.chartutil;import com.baomidou.mybatisplus.core.toolkit.wrappers;import com.drools.bo.guatanteecost;import com.drools.entity.droolsruleconfig;import com.drools.rvice.droolsruleconfigrvice;import com.github.xiaoymin.knife4j.annotations.apisort;import io.swagger.annotations.api;import io.swagger.annotations.apiimplicitparam;import io.swagger.annotations.apioperation;import lombok.allargsconstructor;import lombok.extern.slf4j.slf4j;import org.apache.commons.lang3.stringutils;import org.drools.template.objectdatacompiler;import org.kie.api.io.resourcetype;import org.kie.api.runtime.kiession;import org.kie.internal.io.resourcefactory;import org.kie.internal.utils.kiehelper;import org.springframework.beans.factory.annotation.autowired;import org.springframework.web.bind.annotation.postmapping;import org.springframework.web.bind.annotation.requestmapping;import org.springframework.web.bind.annotation.restcontroller; import java.io.ioexception;import java.io.inputstream;import java.math.bigdecimal;import java.util.list; /** * @author xiaomifeng1010 * @version 1.0 * @date: 2021/12/6 15:41 * @description */@restcontroller@requestmapping("/drools")@allargsconstructor(onconstructor_={@autowired})@api(tags = "drools规则引擎测试接口")@apisort(30)@slf4jpublic class droolstestcontroller {     @autowired    private kiession kiession;    @autowired    private droolsruleconfigrvice droolsruleconfigrvice;     @apioperation("测试计算保费规则")    @apiimplicitparam(name="bzjamount",value = "保证金金额(单位元)")    @postmapping("test/rule")    public string testdrools(bigdecimal bzjamount){        guatanteecost guatanteecost = new guatanteecost();        guatanteecost.tamount(bzjamount.doublevalue());        kiession.inrt(guatante防震减灾手抄报图片简单又漂亮ecost);        kiession.tglobal("logger",log);        int allrules = kiession.fireallrules();        double cost = guatanteecost.getcost();        log.info("成功执行{}条规则",allrules);        log.info("计算保费{}元", cost);        kiession.dispo();        return cost+"";     }     @apioperation("测试使用规则模板计算保费规则")    @apiimplicitparam(name="bzjamount",value = "保证金金额(单位元)")    @postmapping("test/ruletemplate")    public string testdroolsruletemplate(bigdecimal bzjamount){        guatanteecost guatanteecost = new guatanteecost();        guatanteecost.tamount(bzjamount.doublevalue());        list<droolsruleconfig> droolsruleconfiglist = droolsruleconfigrvice.list(wrappers.<droolsruleconfig>lambdaquery()                .eq(droolsruleconfig::getrulename, "fix"));        objectdatacompiler converter = new objectdatacompiler();        string drlcontent = stringutils.empty;        try(inputstream dis= resourcefactory.                newclasspathresource("rules/fixratecostcalculatorrule.drt", chartutil.utf_8)                .getinputstream()){//            填充模板内容            drlcontent=converter.compile(droolsruleconfiglist, dis);            log.info("生成的规则内容:{}",drlcontent);        }catch (ioexception e) {            log.error("获取规则模板文件出错:{}",e.getmessage());        }        kiehelper helper = new kiehelper();        helper.addcontent(drlcontent, resourcetype.drl);        kiession ks = helper.build().newkiession();        ks.inrt(guatanteecost); //        kiession.tglobal("logger",log);        int allrules = ks.fireallrules();        double cost = guatanteecost.getcost();        log.info("成功执行{}条规则",allrules);        log.info("计算保费{}元", cost);        kiession.dispo();        return cost+"";     } }

至此,可以先忽视第二个接口方法,使用第一个接口方法来测试规则的运行

计算的费用是200,执行的是rule1规则,200000介于0-300000之间,所以保费计算的是200

这种直接写drl规则文件,在里边设定规则的方式比较简便,但是却不灵活,如果我想再添加几条范围,那么就需要重新再来修改这个drl文件,所以在项目中可以使用规则模板drt

然后在项目resources的rules目录下再创建一个drt文件fixratecostcalculatorrule.drt

//模板文件template pro什么意思headerminmaxfixedfee package drools.templatesimport com.drools.bo.guatanteecosttemplate "fixrate"rule "calculate rule_@{row.rownumber}"dialect "mvel"no-loop truewhen $guaranteecost:guatanteecost(amount>@{min} && amount<=@{max})then modify($guaranteecost){     tcost(@{fixedfee})   }  end end template

然后创建一个表,用于保存min,max和fixed的参数值(注意事项:template header下边的min,max和fixedfee都相当于声明的参数,但是不能在min上边加一行注释如://参数说明,在解析规则模板时候会把“//参数说明”也当做声明的参数变量),因为这些值可以动态变化了,所以范围规则也相当于可以动态变化,范围就不是之前设置的固定的啦

创建这样一个表,这样就可以灵活配置范围和保费金额了

create table `biz_drools_rule_config` (  `id` bigint(20) not null,  `rule_code` varchar(255) default null comment '规则编码',  `rule_name` varchar(255) default null comment '规则名称',  `min` int(10) default null comment '保证金范围最小值',  `max` int(10) default null comment '保证金范围最大值',  `fixed_fee` decimal(10,2) default null comment '固定保费',  `fee_rate` decimal(5,3) default null comment '费率(小数)',  `create_by` varchar(25) default null,  `create_time` datetime default null,  `update_by` varchar(25) default null,  `update_time` datetime default null,  primary key (`id`) using btree) engine=innodb default chart=utf8mb4 row_format=dynamic;

然后创建对应的实体类,mapper和rvice,可以使用项目中的代码生成器快捷生成或者idea的插件生成

然后就可以使用controller中的第二个接口方法来测试了

数据库中的数据插入,可以在项目页面中写一个用于添加规则配置参数的页面,在里边插入几条数

这里我是先随意手动添加了几条数据

然后在knife4j文档页面执行接口测试

加上oauth2的验证信息

输入amount的值,也计算的固定保费200

同时从数据库中查询出来3条数据,对应三个范围,生成了三个规则(rule),可以从项目日志中查看

此时可以把数据库中的最大最小值改变一下,再测试一下

此时再传入一个保证金amount值20万,就会计算出保费费用是300元,执行代码时,会再次生成新的规则,每次执行规则模板动态生成的规则drl内容实际上保存在内存中的,并不像最开始创建的drl文件那样

再次执行,就会发现保费计算就成了300元

同时规则模板动态生成的规则内容也对应发生了变化

为了方便使用这个规则模板,可以将测试规则模板的这个接口方法封装成一个辅助类,在业务使用时,可以直接调用

package com.drools.util; import cn.hutool.core.util.chartutil;import com.baomidou.mybatisplus.core.toolkit.wrappers;import com.drools.bo.guatanteecost;import com.drools.entity.droolsruleconfig;import com.drools.rvice.droolsruleconfigrvice;import lombok.extern.slf4j.slf4j;import org.apache.commons.lang3.stringutils;import org.drools.template.objectdatacompiler;import org.kie.api.io.resourcetype;import org.kie.api.runtime.kiession;import org.kie.internal.io.resourcefactory;import org.kie.internal.utils.kiehelper;import org.springframework.beans.factory.annotation.autowired;import org.springframework.stereotype.component; import java.io.ioexception;import java.io.inputstream;import java.math.bigdecimal;import java.util.list; /** * @author xiaomifeng1010 * @version 1.0 * @date: 2021/12/8 16:22 * @description 根据规则引擎模板获取保费金额 */@component@slf4jpublic class calculatecostutil {     @autowired    private droolsruleconfigrvice droolsruleconfigrvice;     /**     * @description: 获取固定保费     * @author: xiaomifeng1010     * @date: 2021/12/8     * @param bzjamount     * @return: bigdecimal     **/    public bigdecimal getfixedfee(bigdecimal bzjamount){        guatanteecost guatanteecost = new guatanteecost();        guatanteecost.tamount(bzjamount.doublevalue());        list<droolsruleconfig> droolsruleconfiglist = droolsruleconfigrvice.list(wrappers.<droolsruleconfig>lambdaquery()                .eq(droolsruleconfig::getrulename, "fix"));        objectdatacompiler converter = new objectdatacompiler();        string drlcontent = stringutils.empty;        try(inputstrea不吃药减肥最快秘籍m dis= resourcefactory.                newclasspathresource("rules/fixratecostcalculatorrule.drt", chartutil.utf_8)                .getinputstream()){//            填充模板内容            drlcontent=converter.compile(droolsruleconfiglist, dis);            log.info("生成的规则内容:{}",drlcontent);        }catch (ioexception e) {            log.error("获取规则模板文件出错:{}",e.getmessage());        }        kiehelper helper = new kiehelper();        helper.addcontent(drlcontent, resourcetype.drl);        kiession ks = helper.build().newkiession();        ks.inrt(guatanteecost);         int allrules = ks.fireallrules();        double cost = guatanteecost.getcost();        log.info("成功执行{}条规则",allrules);        log.info("计算保费{}元", cost);        ks.dispo();        return bigdecimal.valueof(cost);    } }

暂时就研究了这些点东西,算是刚刚入门这个框架,买的drools图书,还得再多读几遍,多实践操作一下,以后再做一些更深入的总结

到此这篇关于springboot整合drools规则引擎动态生成业务规则的实现的文章就介绍到这了,更多相关springboot整合drools生成业务规则内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!

本文发布于:2023-04-04 02:26:44,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/700610fff7bed46876a248462789372e.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:SpringBoot整合Drools规则引擎动态生成业务规则的实现.doc

本文 PDF 下载地址:SpringBoot整合Drools规则引擎动态生成业务规则的实现.pdf

标签:规则   保费   项目   文件
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图