• Drools实战


    1. Drools实战

    1 个人所得税计算器

    本小节我们需要通过Drools规则引擎来根据规则计算个人所得税,最终页面效果如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M1HjKK8N-1653749251774)(…/media/pictures/Drools.assets/image-20200214132448956.png)]

    1.1 名词解释

    税前月收入:即税前工资,指交纳个人所得税之前的总工资

    应纳税所得额:指按照税法规定确定纳税人在一定期间所获得的所有应税收入减除在该纳税期间依法允许减除的各种支出后的余额

    税率:是对征税对象的征收比例或征收额度

    速算扣除数:指为解决超额累进税率分级计算税额的复杂技术问题,而预先计算出的一个数据,可以简化计算过程

    扣税额:是指实际缴纳的税额

    税后工资:是指扣完税后实际到手的工资收入

    1.2 计算规则

    要实现个人所得税计算器,需要了解如下计算规则:(2011)

    规则编号名称描述
    1计算应纳税所得额应纳税所得额为税前工资减去3500
    2设置税率,应纳税所得额<=1500税率为0.03,速算扣除数为0
    3设置税率,应纳税所得额在1500至4500之间税率为0.1,速算扣除数为105
    4设置税率,应纳税所得额在4500志9000之间税率为0.2,速算扣除数为555
    5设置税率,应纳税所得额在9000志35000之间税率为0.25,速算扣除数为1005
    6设置税率,应纳税所得额在35000至55000之间税率为0.3,速算扣除数为2755
    7设置税率,应纳税所得额在55000至80000之间税率为0.35,速算扣除数为5505
    8设置税率,应纳税所得额在80000以上税率为0.45,速算扣除数为13505
    9计算税后工资扣税额=应纳税所得额*税率-速算扣除数 税后工资=税前工资-扣税额

    税前工资:10000

    应缴纳所得税:10000-3500 = 6500

    税率:0.2

    速算扣除数:555

    扣税额:6500 * 0.2 - 555 = 745

    税后工资:10000 - 745 = 9255

    1.3 实现步骤

    本实战案例我们基于Spring Boot整合Drools的方式来实现。

    第一步:创建maven工程calculation并配置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.springframework.boot</groupId>
            <artifactId>spring-boot-starters</artifactId>
            <version>2.0.6.RELEASE</version>
        </parent>
        <groupId>cn.itcast</groupId>
        <artifactId>calculation</artifactId>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
            <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>2.6</version>
            </dependency>
            <!--drools规则引擎-->
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-core</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-compiler</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-templates</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.kie</groupId>
                <artifactId>kie-api</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.kie</groupId>
                <artifactId>kie-spring</artifactId>
                <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>
                <version>7.6.0.Final</version>
            </dependency>
        </dependencies>
        <build>
            <finalName>${project.artifactId}</finalName>
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </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

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

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

    第三步:编写配置类DroolsConfig

    package com.itheima.drools.config;
    import org.kie.api.KieBase;
    import org.kie.api.KieServices;
    import org.kie.api.builder.KieBuilder;
    import org.kie.api.builder.KieFileSystem;
    import org.kie.api.builder.KieRepository;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    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.springframework.context.annotation.Configuration;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternResolver;
    import org.springframework.core.io.Resource;
    import java.io.IOException;
    /**
     * 规则引擎配置类
     */
    @Configuration
    public class DroolsConfig {
        //指定规则文件存放的目录
        private static final String RULES_PATH = "rules/";
        private final KieServices kieServices = KieServices.Factory.get();
        @Bean
        @ConditionalOnMissingBean
        public KieFileSystem kieFileSystem() throws IOException {
            System.setProperty("drools.dateformat","yyyy-MM-dd");
            KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
            ResourcePatternResolver resourcePatternResolver = 
                new PathMatchingResourcePatternResolver();
            Resource[] files = 
                resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
            String path = null;
            for (Resource file : files) {
                path = RULES_PATH + file.getFilename();
                kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
            }
            return kieFileSystem;
        }
        @Bean
        @ConditionalOnMissingBean
        public KieContainer kieContainer() throws IOException {
            KieRepository kieRepository = kieServices.getRepository();
            kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
            KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
            kieBuilder.buildAll();
            return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
        }
        @Bean
        @ConditionalOnMissingBean
        public KieBase kieBase() throws IOException {
            return kieContainer().getKieBase();
        }
        @Bean
        @ConditionalOnMissingBean
        public KModuleBeanFactoryPostProcessor kiePostProcessor() {
            return new KModuleBeanFactoryPostProcessor();
        }
    }
    
    • 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

    第四步:编写实体类Calculation

    package com.itheima.drools.entity;
    
    public class Calculation {
        private double wage;//税前工资
        private double wagemore;//应纳税所得额
        private double cess;//税率
        private double preminus;//速算扣除数
        private double wageminus;//扣税额
        private double actualwage;//税后工资
    
        public double getWage() {
            return wage;
        }
    
        public void setWage(double wage) {
            this.wage = wage;
        }
    
        public double getActualwage() {
            return actualwage;
        }
    
        public void setActualwage(double actualwage) {
            this.actualwage = actualwage;
        }
    
        public double getWagemore() {
            return wagemore;
        }
    
        public void setWagemore(double wagemore) {
            this.wagemore = wagemore;
        }
    
        public double getCess() {
            return cess;
        }
    
        public void setCess(double cess) {
            this.cess = cess;
        }
    
        public double getPreminus() {
            return preminus;
        }
    
        public void setPreminus(double preminus) {
            this.preminus = preminus;
        }
    
        public double getWageminus() {
            return wageminus;
        }
    
        public void setWageminus(double wageminus) {
            this.wageminus = wageminus;
        }
    
        @Override
        public String toString() {
            return "Calculation{" +
                    "wage=" + wage +
                    ", actualwage=" + actualwage +
                    ", wagemore=" + wagemore +
                    ", cess=" + cess +
                    ", preminus=" + preminus +
                    ", wageminus=" + wageminus +
                    '}';
        }
    }
    
    • 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

    第五步:在resources/rules下创建规则文件calculation.drl文件

    package calculation
    import com.itheima.drools.entity.Calculation
    
    rule "个人所得税:计算应纳税所得额"
        enabled true
        salience 3
        no-loop true
        date-effective "2011-09-01" //生效日期
        when
            $cal : Calculation(wage>0)
        then
            $cal.setWagemore($cal.getWage()-3500);
            update($cal);
    end
    
    rule "个人所得税:设置税率-->>应纳税所得额<=1500"
        salience 2
        no-loop true
        activation-group "SETCess_Group"
        when
            $cal : Calculation(wagemore <= 1500)
        then
            $cal.setCess(0.03);
            $cal.setPreminus(0);
            update($cal);
    end
    
    rule "个人所得税:设置税率-->>应纳税所得额在1500至4500之间"
        salience 2
        no-loop true
        activation-group "SETCess_Group"
        when
            $cal : Calculation(wagemore > 1500 && wagemore <= 4500)
        then
            $cal.setCess(0.1);
            $cal.setPreminus(105);
            update($cal);
    end
    
    rule "个人所得税:设置税率-->>应纳税所得额在4500志9000之间"
        salience 2
        no-loop true
        activation-group "SETCess_Group"
        when
            $cal : Calculation(wagemore > 4500 && wagemore <= 9000)
        then
            $cal.setCess(0.2);
            $cal.setPreminus(555);
            update($cal);
    end
    
    rule "个人所得税:设置税率-->>应纳税所得额在9000志35000之间"
        salience 2
        no-loop true
        activation-group "SETCess_Group"
        when
            $cal : Calculation(wagemore > 9000 && wagemore <= 35000)
        then
            $cal.setCess(0.25);
            $cal.setPreminus(1005);
            update($cal);
    end
    
    rule "个人所得税:设置税率-->>应纳税所得额在35000至55000之间"
        salience 2
        no-loop true
        activation-group "SETCess_Group"
        when
            $cal : Calculation(wagemore > 35000 && wagemore <= 55000)
        then
            $cal.setCess(0.3);
            $cal.setPreminus(2755);
            update($cal);
    end
    
    rule "个人所得税:设置税率-->>应纳税所得额在55000至80000之间"
        salience 2
        no-loop true
        activation-group "SETCess_Group"
        when
            $cal : Calculation(wagemore > 55000 && wagemore <= 80000)
        then
            $cal.setCess(0.35);
            $cal.setPreminus(5505);
            update($cal);
    end
    
    rule "个人所得税:设置税率-->>应纳税所得额在80000以上"
        salience 2
        no-loop true
        activation-group "SETCess_Group"
        when
            $cal : Calculation(wagemore > 80000)
        then
            $cal.setCess(0.45);
            $cal.setPreminus(13505);
            update($cal);
    end
    
    rule "个人所得税:计算税后工资"
        salience 1
        when
            $cal : Calculation(wage > 0 && wagemore > 0 && wagemore > 0 && cess > 0)
        then
            $cal.setWageminus($cal.getWagemore()*$cal.getCess()-$cal.getPreminus());
            $cal.setActualwage($cal.getWage()-$cal.getWageminus());
    
            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());
    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
    • 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
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114

    第六步:创建RuleService

    package com.itheima.drools.service;
    
    import com.itheima.drools.entity.Calculation;
    import org.kie.api.KieBase;
    import org.kie.api.runtime.KieSession;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    /**
     * 调用规则引擎,执行规则
     */
    @Service
    public class RuleService {
        @Autowired
        private KieBase kieBase;
    
        //个人所得税计算
        public Calculation calculate(Calculation calculation){
            KieSession kieSession = kieBase.newKieSession();
            kieSession.insert(calculation);
            kieSession.fireAllRules();
            kieSession.dispose();
            return calculation;
        }
    }
    
    • 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.Calculation;
    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;
    
    @RestController
    @RequestMapping("/rule")
    public class RuleController {
        @Autowired
        private RuleService ruleService;
    
        @RequestMapping("/calculate")
        public Calculation calculate(double wage){
            Calculation calculation = new Calculation();
            calculation.setWage(wage);
            calculation = ruleService.calculate(calculation);
            System.out.println(calculation);
            return calculation;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    第八步:创建启动类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

    第九步:导入静态资源文件到resources/static目录下

    2 信用卡申请

    本小节我们需要通过Drools规则引擎来根据规则进行申请人的合法性检查,检查通过后再根据规则确定信用卡额度,最终页面效果如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tHDVUap9-1653749251780)(…/media/pictures/Drools.assets/image-20200214202525859.png)]

    2.1 计算规则

    合法性检查规则如下:

    规则编号名称描述
    1检查学历与薪水1如果申请人既没房也没车,同时学历为大专以下,并且月薪少于5000,那么不通过
    2检查学历与薪水2如果申请人既没房也没车,同时学历为大专或本科,并且月薪少于3000,那么不通过
    3检查学历与薪水3如果申请人既没房也没车,同时学历为本科以上,并且月薪少于2000,同时之前没有信用卡的,那么不通过
    4检查申请人已有的信用卡数量如果申请人现有的信用卡数量大于10,那么不通过

    信用卡额度确定规则:

    规则编号名称描述
    1规则1如果申请人有房有车,或者月收入在20000以上,那么发放的信用卡额度为15000
    2规则2如果申请人没房没车,但月收入在10000~20000之间,那么发放的信用卡额度为6000
    3规则3如果申请人没房没车,月收入在10000以下,那么发放的信用卡额度为3000
    4规则4如果申请人有房没车或者没房但有车,月收入在10000以下,那么发放的信用卡额度为5000
    5规则5如果申请人有房没车或者是没房但有车,月收入在10000~20000之间,那么发放的信用卡额度为8000

    2.2 实现步骤

    第一步:创建maven工程creditCardApply并配置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.springframework.boot</groupId>
            <artifactId>spring-boot-starters</artifactId>
            <version>2.0.6.RELEASE</version>
        </parent>
        <groupId>com.itheima</groupId>
        <artifactId>creditCardApply</artifactId>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
            <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>2.6</version>
            </dependency>
            <!--drools规则引擎-->
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-core</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-compiler</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-templates</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.kie</groupId>
                <artifactId>kie-api</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.kie</groupId>
                <artifactId>kie-spring</artifactId>
                <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>
                <version>7.6.0.Final</version>
            </dependency>
        </dependencies>
        <build>
            <finalName>${project.artifactId}</finalName>
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </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

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

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

    第三步:编写配置类DroolsConfig

    package com.itheima.drools.config;
    import org.kie.api.KieBase;
    import org.kie.api.KieServices;
    import org.kie.api.builder.KieBuilder;
    import org.kie.api.builder.KieFileSystem;
    import org.kie.api.builder.KieRepository;
    import org.kie.api.runtime.KieContainer;
    import org.kie.api.runtime.KieSession;
    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.springframework.context.annotation.Configuration;
    import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
    import org.springframework.core.io.support.ResourcePatternResolver;
    import org.springframework.core.io.Resource;
    import java.io.IOException;
    /**
     * 规则引擎配置类
     */
    @Configuration
    public class DroolsConfig {
        //指定规则文件存放的目录
        private static final String RULES_PATH = "rules/";
        private final KieServices kieServices = KieServices.Factory.get();
        @Bean
        @ConditionalOnMissingBean
        public KieFileSystem kieFileSystem() throws IOException {
            KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
            ResourcePatternResolver resourcePatternResolver =
                    new PathMatchingResourcePatternResolver();
            Resource[] files =
                    resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*");
            String path = null;
            for (Resource file : files) {
                path = RULES_PATH + file.getFilename();
                kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8"));
            }
            return kieFileSystem;
        }
        @Bean
        @ConditionalOnMissingBean
        public KieContainer kieContainer() throws IOException {
            KieRepository kieRepository = kieServices.getRepository();
            kieRepository.addKieModule(kieRepository::getDefaultReleaseId);
            KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem());
            kieBuilder.buildAll();
            return kieServices.newKieContainer(kieRepository.getDefaultReleaseId());
        }
        @Bean
        @ConditionalOnMissingBean
        public KieBase kieBase() throws IOException {
            return kieContainer().getKieBase();
        }
        @Bean
        @ConditionalOnMissingBean
        public KModuleBeanFactoryPostProcessor kiePostProcessor() {
            return new KModuleBeanFactoryPostProcessor();
        }
    }
    
    • 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

    第四步:编写实体类CreditCardApplyInfo

    package com.itheima.drools.entity;
    /**
     * 信用卡申请信息
     */
    public class CreditCardApplyInfo {
        public static final String EDUCATION_1 = "专科以下";
        public static final String EDUCATION_2 = "专科";
        public static final String EDUCATION_3 = "本科";
        public static final String EDUCATION_4 = "本科以上";
    
        private String name;
        private String sex;
        private int age;
        private String education;
        private String telephone;
        private double monthlyIncome = 0;//月收入
        private String address;
    
        private boolean hasHouse = false;//是否有房
        private boolean hasCar = false;//是否有车
        private int hasCreditCardCount = 0;//现持有信用卡数量
    
        private boolean checkResult = true;//审核是否通过
        private double quota = 0;//额度
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        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 String getEducation() {
            return education;
        }
    
        public void setEducation(String education) {
            this.education = education;
        }
    
        public String getTelephone() {
            return telephone;
        }
    
        public void setTelephone(String telephone) {
            this.telephone = telephone;
        }
    
        public double getMonthlyIncome() {
            return monthlyIncome;
        }
    
        public void setMonthlyIncome(double monthlyIncome) {
            this.monthlyIncome = monthlyIncome;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    
        public boolean isHasHouse() {
            return hasHouse;
        }
    
        public void setHasHouse(boolean hasHouse) {
            this.hasHouse = hasHouse;
        }
    
        public boolean isHasCar() {
            return hasCar;
        }
    
        public void setHasCar(boolean hasCar) {
            this.hasCar = hasCar;
        }
    
        public int getHasCreditCardCount() {
            return hasCreditCardCount;
        }
    
        public void setHasCreditCardCount(int hasCreditCardCount) {
            this.hasCreditCardCount = hasCreditCardCount;
        }
    
        public boolean isCheckResult() {
            return checkResult;
        }
    
        public void setCheckResult(boolean checkResult) {
            this.checkResult = checkResult;
        }
    
        public double getQuota() {
            return quota;
        }
    
        public void setQuota(double quota) {
            this.quota = quota;
        }
    
        public String toString() {
            if(checkResult){
                return "审核通过,信用卡额度为:" + quota;
            }else {
                return "审核不通过";
            }
        }
    }
    
    
    • 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
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130

    第五步:在resources/rules下创建规则文件creditCardApply.drl文件

    package com.itheima.creditCardApply
    import com.itheima.drools.entity.CreditCardApplyInfo
    
    //合法性检查
    rule "如果申请人既没房也没车,同时学历为大专以下,并且月薪少于5000,那么不通过"
        salience 10
        no-loop true
        when
            $c:CreditCardApplyInfo(hasCar == false &&
                                    hasHouse == false &&
                                    education == CreditCardApplyInfo.EDUCATION_1 &&
                                    monthlyIncome < 5000)
        then
            $c.setCheckResult(false);
            drools.halt();
    end
    rule "如果申请人既没房也没车,同时学历为大专或本科,并且月薪少于3000,那么不通过"
        salience 10
        no-loop true
        when
            $c:CreditCardApplyInfo(hasCar == false &&
                                    hasHouse == false &&
                                    (education == CreditCardApplyInfo.EDUCATION_2  ||
                                    education == CreditCardApplyInfo.EDUCATION_3) &&
                                    monthlyIncome < 3000)
        then
            $c.setCheckResult(false);
            drools.halt();
    end
    rule "如果申请人既没房也没车,同时学历为本科以上,并且月薪少于2000,同时之前没有信用卡的,那么不通过"
        salience 10
        no-loop true
        when
            $c:CreditCardApplyInfo(hasCar == false &&
                                    hasHouse == false &&
                                    education == CreditCardApplyInfo.EDUCATION_4 &&
                                    monthlyIncome < 2000 &&
                                    hasCreditCardCount == 0)
        then
            $c.setCheckResult(false);
            drools.halt();
    end
    rule "如果申请人现有的信用卡数量大于10,那么不通过"
        salience 10
        no-loop true
        when
            $c:CreditCardApplyInfo(hasCreditCardCount > 10)
        then
            $c.setCheckResult(false);
            drools.halt();
    end
    //--------------------------------------------------------------------------
    //确定额度
    rule "如果申请人有房有车,或者月收入在20000以上,那么发放的信用卡额度为15000"
        salience 1
        no-loop true
        activation-group "quota_group"
        when
            $c:CreditCardApplyInfo(checkResult == true &&
                                    ((hasHouse == true && hasCar == true) ||
                                    (monthlyIncome > 20000)))
        then
            $c.setQuota(15000);
    end
    rule "如果申请人没房没车,但月收入在10000~20000之间,那么发放的信用卡额度为6000"
        salience 1
        no-loop true
        activation-group "quota_group"
        when
            $c:CreditCardApplyInfo(checkResult == true &&
                                    hasHouse == false &&
                                    hasCar == false &&
                                    monthlyIncome >= 10000 &&
                                    monthlyIncome <= 20000)
        then
            $c.setQuota(6000);
    end
    rule "如果申请人没房没车,月收入在10000以下,那么发放的信用卡额度为3000"
        salience 1
        no-loop true
        activation-group "quota_group"
        when
            $c:CreditCardApplyInfo(checkResult == true &&
                                            hasHouse == false &&
                                            hasCar == false &&
                                            monthlyIncome < 10000)
        then
            $c.setQuota(3000);
    end
    rule "如果申请人有房没车或者没房但有车,月收入在10000以下,那么发放的信用卡额度为5000"
        salience 1
        no-loop true
        activation-group "quota_group"
        when
            $c:CreditCardApplyInfo(checkResult == true &&
                                    ((hasHouse == true && hasCar == false) ||
                                    (hasHouse == false && hasCar == true)) &&
                                    monthlyIncome < 10000)
        then
            $c.setQuota(5000);
    end
    rule "如果申请人有房没车或者是没房但有车,月收入在10000~20000之间,那么发放的信用卡额度为8000"
        salience 1
        no-loop true
        activation-group "quota_group"
        when
            $c:CreditCardApplyInfo(checkResult == true &&
                                    ((hasHouse == true && hasCar == false) ||
                                    (hasHouse == false && hasCar == true)) &&
                                    monthlyIncome >= 10000 &&
                                    monthlyIncome <= 20000)
        then
            $c.setQuota(8000);
    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
    • 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
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114

    第六步:创建RuleService

    package com.itheima.drools.service;
    
    import com.itheima.drools.entity.CreditCardApplyInfo;
    import org.kie.api.KieBase;
    import org.kie.api.runtime.KieSession;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    public class RuleService {
        @Autowired
        private KieBase kieBase;
    
        //调用Drools规则引擎实现信用卡申请
        public CreditCardApplyInfo creditCardApply(CreditCardApplyInfo creditCardApplyInfo){
            KieSession session = kieBase.newKieSession();
            session.insert(creditCardApplyInfo);
            session.fireAllRules();
            session.dispose();
            return creditCardApplyInfo;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    第七步:创建RuleController

    package com.itheima.drools.controller;
    
    import com.itheima.drools.entity.CreditCardApplyInfo;
    import com.itheima.drools.service.RuleService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestBody;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @RequestMapping("/rule")
    public class RuleController {
        @Autowired
        private RuleService ruleService;
    
        @RequestMapping("/creditCardApply")
        public CreditCardApplyInfo creditCardApply(@RequestBody 
            CreditCardApplyInfo creditCardApplyInfo){
            creditCardApplyInfo = ruleService.creditCardApply(creditCardApplyInfo);
            return creditCardApplyInfo;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    第八步:创建启动类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

    第九步:导入静态资源文件到resources/static目录下

    3 保险产品准入规则 (学到决策表这里 高级部分跳过)

    3.1 决策表

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

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

    一个决策表的例子如下:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N4jme7Vp-1653749251782)(…/media/pictures/Drools.assets/image-20200217160930138.png)]

    决策表语法:

    关键字说明是否必须
    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.drools</groupId>
        <artifactId>drools-decisiontables</artifactId>
        <version>7.10.0.Final</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bw59eoRQ-1653749251784)(…/media/pictures/Drools.assets/image-20200218105819932.png)]

    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.drools</groupId>
        <artifactId>drools-decisiontables</artifactId>
        <version>7.10.0.Final</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
    </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

    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文件,业务人员可以直接更改这个文件中指标的值,系统不需要做任何变更。

    3.3 实现步骤

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

    第一步:创建maven工程insuranceInfoCheck并配置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.springframework.boot</groupId>
            <artifactId>spring-boot-starters</artifactId>
            <version>2.0.6.RELEASE</version>
        </parent>
        <groupId>com.itheima</groupId>
        <artifactId>insuranceInfoCheck</artifactId>
        <version>1.0-SNAPSHOT</version>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-aop</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
            <dependency>
                <groupId>commons-lang</groupId>
                <artifactId>commons-lang</artifactId>
                <version>2.6</version>
            </dependency>
            <!--drools规则引擎-->
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-core</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-compiler</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-templates</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.kie</groupId>
                <artifactId>kie-api</artifactId>
                <version>7.6.0.Final</version>
            </dependency>
            <dependency>
                <groupId>org.kie</groupId>
                <artifactId>kie-spring</artifactId>
                <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>
                <version>7.6.0.Final</version>
            </dependency>
        </dependencies>
        <build>
            <finalName>${project.artifactId}</finalName>
            <resources>
                <resource>
                    <directory>src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
                <resource>
                    <directory>src/main/resources</directory>
                    <includes>
                        <include>**/*.*</include>
                    </includes>
                    <filtering>false</filtering>
                </resource>
            </resources>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                    </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文件)

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RQXvgCCo-1653749251786)(…/media/pictures/Drools.assets/image-20200218120618384.png)]

    第五步:封装工具类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
  • 相关阅读:
    Docker-JenKins安装及配置!
    使用Arduino开发板实现红外遥控器解码
    最新面试题:用友OC,美团三面已挂
    java入门-基本数据类型
    ARM作业1
    安防监控/视频汇聚平台EasyCVR云端录像不展示该是什么原因?该如何解决?
    告前端同学书
    TCR历史论文多久能发表?
    Unity Shader 溶解效果
    DNS 系列(二):DNS 记录及工作方式,你了解吗?
  • 原文地址:https://blog.csdn.net/qq_39736597/article/details/125024683