• 第2-4-10章 规则引擎Drools实战(3)-保险产品准入规则


    9.3 保险产品准入规则

    全套代码及资料全部完整提供,点此处下载

    9.3.1 决策表

    前面我们编写的规则文件都是drl形式的文件,Drools除了支持drl形式的文件外还支持xls格式的文件(即Excel文件)。这种xls格式的文件通常称为决策表(decision table)。

    决策表(decision table)是一个“精确而紧凑的”表示条件逻辑的方式,非常适合商业级别的规则。决策表与现有的drl文件可以无缝替换。Drools提供了相应的API可以将xls文件编译为drl格式的字符串。

    一个决策表的例子如下:

    在这里插入图片描述

    决策表语法:

    关键字说明是否必须
    RuleSet相当于drl文件中的package必须,只能有一个。如果没有设置RuleSet对应的值则使用默认值rule_table
    Sequential取值为Boolean类型。true表示规则按照表格自上到下的顺序执行,false表示乱序可选
    Import相当于drl文件中的import,如果引入多个类则类之间用逗号分隔可选
    Variables相当于drl文件中的global,用于定义全局变量,如果有多个全局变量则中间用逗号分隔可选
    RuleTable它指示了后面将会有一批rule,RuleTable的名称将会作为以后生成rule的前缀必须
    CONDITION规则条件关键字,相当于drl文件中的when。下面两行则表示 LHS 部分,第三行则为注释行,不计为规则部分,从第四行开始,每一行表示一条规则每个规则表至少有一个
    ACTION规则结果关键字,相当于drl文件中的then每个规则表至少有一个
    NO-LOOP相当于drl文件中的no-loop可选
    AGENDA-GROUP相当于drl文件中的agenda-group可选

    在决策表中还经常使用到占位符,语法为$后面加数字,用于替换每条规则中设置的具体值。

    上面的决策表例子转换为drl格式的规则文件内容如下:

    package rules;
    
    import com.itheima.drools.entity.PersonInfoEntity;
    import java.util.List;
    global java.util.List listRules;
    
    rule "personCheck_10"
    	salience 65535
    	agenda-group "sign"
    	when
    		$person : PersonInfoEntity(sex != "男")
    	then
    		listRules.add("性别不对");
    end
    
    rule "personCheck_11"
    	salience 65534
    	agenda-group "sign"
    	when
    		$person : PersonInfoEntity(age < 22 || age > 25)
    	then
    		listRules.add("年龄不合适");
    end
    
    rule "personCheck_12"
    	salience 65533
    	agenda-group "sign"
    	when
    		$person : PersonInfoEntity(salary < 10000)
    	then
    		listRules.add("工资太低了");
    end
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    要进行决策表相关操作,需要导入如下maven坐标:

    <dependency>
        <groupId>org.droolsgroupId>
        <artifactId>drools-decisiontablesartifactId>
        <version>7.10.0.Finalversion>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    通过下图可以发现,由于maven的依赖传递特性在导入drools-decisiontables坐标后,drools-core和drools-compiler等坐标也被传递了过来

    在这里插入图片描述

    Drools提供的将xls文件编译为drl格式字符串的API如下:

    String realPath = "C:\\testRule.xls";//指定决策表xls文件的磁盘路径
    File file = new File(realPath);
    InputStream is = new FileInputStream(file);
    SpreadsheetCompiler compiler = new SpreadsheetCompiler();
    String drl = compiler.compile(is, InputType.XLS);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Drools还提供了基于drl格式字符串创建KieSession的API:

    KieHelper kieHelper = new KieHelper();
    kieHelper.addContent(drl, ResourceType.DRL);
    KieSession session = kieHelper.build().newKieSession();
    
    • 1
    • 2
    • 3

    基于决策表的入门案例:

    第一步:创建maven工程drools_decisiontable_demo并配置pom.xml文件

    <dependency>
        <groupId>org.droolsgroupId>
        <artifactId>drools-decisiontablesartifactId>
        <version>7.10.0.Finalversion>
    dependency>
    <dependency>
        <groupId>junitgroupId>
        <artifactId>junitartifactId>
        <version>4.12version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    第二步:创建实体类PersonInfoEntity

    package com.itheima.drools.entity;
    
    public class PersonInfoEntity {
        private String sex;
        private int age;
        private double salary;
    
        public String getSex() {
            return sex;
        }
    
        public void setSex(String sex) {
            this.sex = sex;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public double getSalary() {
            return salary;
        }
    
        public void setSalary(double salary) {
            this.salary = salary;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    第三步:创建xls规则文件(可以直接使用资料中提供的testRule.xls文件)

    第四步:创建单元测试

    @Test
    public void test1() throws Exception{
        String realPath = "d:\\testRule.xls";//指定决策表xls文件的磁盘路径
        File file = new File(realPath);
        InputStream is = new FileInputStream(file);
        SpreadsheetCompiler compiler = new SpreadsheetCompiler();
        String drl = compiler.compile(is, InputType.XLS);
    
        System.out.println(drl);
        KieHelper kieHelper = new KieHelper();
        kieHelper.addContent(drl, ResourceType.DRL);
        KieSession session = kieHelper.build().newKieSession();
    
        PersonInfoEntity personInfoEntity = new PersonInfoEntity();
        personInfoEntity.setSex("男");
        personInfoEntity.setAge(35);
        personInfoEntity.setSalary(1000);
    
        List<String> list = new ArrayList<String>();
        session.setGlobal("listRules",list);
    
        session.insert(personInfoEntity);
        
        session.getAgenda().getAgendaGroup("sign").setFocus();
        
        session.fireAllRules();
    
        for (String s : list) {
            System.out.println(s);
        }
        session.dispose();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    9.3.2 规则介绍

    各保险公司针对人身、财产推出了不同的保险产品,作为商业保险公司,筛选出符合公司利益最大化的客户是非常重要的,即各保险产品的准入人群是不同的,也就是说保险公司会针对不同的人群特征,制定不同的产品缴费和赔付规则。

    我们来看一下某保险产品准入规则的简化版,当不满足以下规则时,系统模块需要返回准入失败标识和失败原因

    规则1:  保险公司是:PICC
    规则2:  销售区域是:北京、天津
    规则3:  投保人年龄:0 ~ 17岁
    规则4:  保险期间是:20年、25年、30年
    规则5:  缴费方式是:趸交(一次性交清)或年交
    规则6:  保险期与交费期规则一:保险期间为20年期交费期间最长10年交且不能选择[趸交]
    规则7:  保险期与交费期规则二:保险期间为25年期交费期间最长15年交且不能选择[趸交]
    规则8:  保险期与交费期规则三:保险期间为30年期交费期间最长20年交且不能选择[趸交]
    规则9:  被保人要求:(投保年龄+保险期间)不得大于40周岁
    规则10: 保险金额规则:投保时约定,最低为5万元,超过部分必须为1000元的整数倍
    规则11: 出单基本保额限额规则:线上出单基本保额限额62.5万元,超62.5万元需配合契调转线下出单
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在本案例中规则文件是一个Excel文件,业务人员可以直接更改这个文件中指标的值,系统不需要做任何变更。

    9.3.3 实现步骤

    本案例还是基于Spring Boot整合Drools的架构来实现。

    在这里插入图片描述

    第一步:创建maven工程insuranceInfoCheck并配置pom.xml文件

    
    <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.0modelVersion>
        <parent>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-startersartifactId>
            <version>2.0.6.RELEASEversion>
        parent>
        <groupId>com.itheimagroupId>
        <artifactId>insuranceInfoCheckartifactId>
        <version>1.0-SNAPSHOTversion>
        <dependencies>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-aopartifactId>
            dependency>
            <dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-testartifactId>
            dependency>
            <dependency>
                <groupId>commons-langgroupId>
                <artifactId>commons-langartifactId>
                <version>2.6version>
            dependency>
            
            <dependency>
                <groupId>org.droolsgroupId>
                <artifactId>drools-coreartifactId>
                <version>7.6.0.Finalversion>
            dependency>
            <dependency>
                <groupId>org.droolsgroupId>
                <artifactId>drools-compilerartifactId>
                <version>7.6.0.Finalversion>
            dependency>
            <dependency>
                <groupId>org.droolsgroupId>
                <artifactId>drools-templatesartifactId>
                <version>7.6.0.Finalversion>
            dependency>
            <dependency>
                <groupId>org.kiegroupId>
                <artifactId>kie-apiartifactId>
                <version>7.6.0.Finalversion>
            dependency>
            <dependency>
                <groupId>org.kiegroupId>
                <artifactId>kie-springartifactId>
                <exclusions>
                    <exclusion>
                        <groupId>org.springframeworkgroupId>
                        <artifactId>spring-txartifactId>
                    exclusion>
                    <exclusion>
                        <groupId>org.springframeworkgroupId>
                        <artifactId>spring-beansartifactId>
                    exclusion>
                    <exclusion>
                        <groupId>org.springframeworkgroupId>
                        <artifactId>spring-coreartifactId>
                    exclusion>
                    <exclusion>
                        <groupId>org.springframeworkgroupId>
                        <artifactId>spring-contextartifactId>
                    exclusion>
                exclusions>
                <version>7.6.0.Finalversion>
            dependency>
        dependencies>
        <build>
            <finalName>${project.artifactId}finalName>
            <resources>
                <resource>
                    <directory>src/main/javadirectory>
                    <includes>
                        <include>**/*.xmlinclude>
                    includes>
                    <filtering>falsefiltering>
                resource>
                <resource>
                    <directory>src/main/resourcesdirectory>
                    <includes>
                        <include>**/*.*include>
                    includes>
                    <filtering>falsefiltering>
                resource>
            resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.pluginsgroupId>
                    <artifactId>maven-compiler-pluginartifactId>
                    <version>2.3.2version>
                    <configuration>
                        <source>1.8source>
                        <target>1.8target>
                    configuration>
                plugin>
            plugins>
        build>
    project>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108

    第二步:创建/resources/application.yml文件

    server:
      port: 8080
    spring:
      application:
        name: insuranceInfoCheck
    
    • 1
    • 2
    • 3
    • 4
    • 5

    第三步:创建实体类InsuranceInfo

    package com.itheima.drools.entity;
    
    /**
     * 保险信息
     */
    public class InsuranceInfo {
        private String param1;//保险公司
        private String param2;//方案代码
        private String param3;//渠道号
        private String param4;//销售区域
        private String param5;//投保年龄
        private String param6;//保险期间
        private String param7;//缴费期间
        private String param8;//缴费方式
        private String param9;//保障类型
        private String param10;//等待期
        private String param11;//犹豫期
        private String param12;//职业类型
        private String param13;//保额限制
        private String param14;//免赔额
        private String param15;//主险保额
        private String param16;//主险保费
        private String param17;//附加险保额
        private String param18;//附加险保费
        private String param19;//与投保人关系
        private String param20;//与被保人关系
        private String param21;//性别
        private String param22;//证件
        private String param23;//保费
        private String param24;//保额
    
        //getter setter省略
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    第四步:创建决策表文件(也可以直接使用实战资料中提供的insuranceInfoCheck.xls文件)

    在这里插入图片描述

    第五步:封装工具类KieSessionUtils

    package com.itheima.drools.utils;
    
    import com.itheima.drools.entity.InsuranceInfo;
    import com.itheima.drools.entity.PersonInfoEntity;
    import org.drools.decisiontable.InputType;
    import org.drools.decisiontable.SpreadsheetCompiler;
    import org.kie.api.builder.Message;
    import org.kie.api.builder.Results;
    import org.kie.api.io.ResourceType;
    import org.kie.api.runtime.KieSession;
    import org.kie.internal.utils.KieHelper;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    
    public class KieSessionUtils {
        private KieSessionUtils() {
    
        }
        // 把xls文件解析为String
        public static String getDRL (String realPath) throws FileNotFoundException {
            File file = new File(realPath); // 例如:C:\\abc.xls
            InputStream is = new FileInputStream(file);
            SpreadsheetCompiler compiler = new SpreadsheetCompiler();
            String drl = compiler.compile(is, InputType.XLS);
            System.out.println(drl);
            return drl;
        }
    
        // drl为含有内容的字符串
        public static KieSession createKieSessionFromDRL(String drl) throws Exception{
            KieHelper kieHelper = new KieHelper();
            kieHelper.addContent(drl, ResourceType.DRL);
            Results results = kieHelper.verify();
            if (results.hasMessages(Message.Level.WARNING, Message.Level.ERROR)) {
                List<Message> messages = results.getMessages(Message.Level.WARNING, Message.Level.ERROR);
                for (Message message : messages) {
                    System.out.println("Error: "+message.getText());
                }
                // throw new IllegalStateException("Compilation errors were found. Check the logs.");
            }
            return kieHelper.build().newKieSession();
        }
    
        // realPath为Excel文件绝对路径
        public static KieSession getKieSessionFromXLS(String realPath) throws Exception {
            return createKieSessionFromDRL(getDRL(realPath));
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    第六步:创建RuleService类

    package com.itheima.drools.service;
    
    import com.itheima.drools.entity.InsuranceInfo;
    import com.itheima.drools.utils.KieSessionUtils;
    import org.kie.api.runtime.KieSession;
    import org.springframework.stereotype.Service;
    import java.util.ArrayList;
    import java.util.List;
    
    @Service
    public class RuleService {
        public List<String> insuranceInfoCheck(InsuranceInfo insuranceInfo) throws Exception{
            KieSession session = KieSessionUtils.getKieSessionFromXLS("D:\\rules.xls");
            session.getAgenda().getAgendaGroup("sign").setFocus();
    
            session.insert(insuranceInfo);
    
            List<String> listRules = new ArrayList<>();
            session.setGlobal("listRules", listRules);
    
            session.fireAllRules();
            
            return listRules;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    第七步:创建RuleController类

    package com.itheima.drools.controller;
    
    import com.itheima.drools.entity.InsuranceInfo;
    import com.itheima.drools.service.RuleService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    @RestController
    @RequestMapping("/rule")
    public class RuleController {
        @Autowired
        private RuleService ruleService;
    
        @RequestMapping("/insuranceInfoCheck")
        public Map insuranceInfoCheck(){
            Map map = new HashMap();
            
            //模拟数据,实际应为页面传递过来
            InsuranceInfo insuranceInfo = new InsuranceInfo();
            insuranceInfo.setParam1("picc");
            insuranceInfo.setParam4("上海");
            insuranceInfo.setParam5("101");
            insuranceInfo.setParam6("12");
            insuranceInfo.setParam7("222");
            insuranceInfo.setParam8("1");
            insuranceInfo.setParam13("3");
            
            try {
                List<String> list = ruleService.insuranceInfoCheck(insuranceInfo);
                if(list != null && list.size() > 0){
                    map.put("checkResult",false);
                    map.put("msg","准入失败");
                    map.put("detail",list);
                }else{
                    map.put("checkResult",true);
                    map.put("msg","准入成功");
                }
                return map;
            } catch (Exception e) {
                e.printStackTrace();
                map.put("checkResult",false);
                map.put("msg","未知错误");
                return map;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    第八步:创建启动类DroolsApplication

    package com.itheima.drools;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class DroolsApplication {
        public static void main(String[] args) {
            SpringApplication.run(DroolsApplication.class);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    全套代码及资料全部完整提供,点此处下载

  • 相关阅读:
    字符串思维题练习 DAY5(CF1137 B , CF 733D , CF 1360 F)
    Spring Security—Servlet 应用架构
    聊聊分布式架构06——[NIO入门]简单的Netty NIO示例
    ScrapeKit 和 Swift 编写程序
    聚观早报 | 小米汽车SU7将发布;一加Ace 3V渲染图曝光
    保证通信的机制有哪些
    【nlohmann/json】树节点的序列化和反序列化
    设计模式七大原则
    文件格式引起的脚本执行错误
    R语言生物群落数据统计分析
  • 原文地址:https://blog.csdn.net/weixin_42208775/article/details/128125886