Drools小示例

  • 一、Drools实战
    • 1.1 个人所得税计算器
      • 1.1.1 名词解释
      • 1.1.2 计算规则
      • 1.1.3 实现步骤
    • 1.2 信用卡申请
      • 1.2.1 计算规则
      • 1.2.2 实现步骤
    • 1.3 保险产品准入规则
      • 1.3.1 决策表
      • 1.3.2 规则介绍
      • 1.3.3 实现步骤

一、Drools实战

1.1 个人所得税计算器

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

1.1.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.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>

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

server:port: 8080
spring:application:name: calculation

第三步:编写配置类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@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic KieBase kieBase() throws IOException {return kieContainer().getKieBase();}@Bean@ConditionalOnMissingBeanpublic KModuleBeanFactoryPostProcessor kiePostProcessor() {return new KModuleBeanFactoryPostProcessor();}
}

第四步:编写实体类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;}@Overridepublic String toString() {return "Calculation{" +"wage=" + wage +", actualwage=" + actualwage +", wagemore=" + wagemore +", cess=" + cess +", preminus=" + preminus +", wageminus=" + wageminus +'}';}
}

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

package calculation
import com.itheima.drools.entity.Calculationrule "个人所得税:计算应纳税所得额"enabled truesalience 3no-loop truedate-effective "2011-09-01" //生效日期when$cal : Calculation(wage>0)then$cal.setWagemore($cal.getWage()-3500);update($cal);
endrule "个人所得税:设置税率-->>应纳税所得额<=1500"salience 2no-loop trueactivation-group "SETCess_Group"when$cal : Calculation(wagemore <= 1500)then$cal.setCess(0.03);$cal.setPreminus(0);update($cal);
endrule "个人所得税:设置税率-->>应纳税所得额在1500至4500之间"salience 2no-loop trueactivation-group "SETCess_Group"when$cal : Calculation(wagemore > 1500 && wagemore <= 4500)then$cal.setCess(0.1);$cal.setPreminus(105);update($cal);
endrule "个人所得税:设置税率-->>应纳税所得额在4500志9000之间"salience 2no-loop trueactivation-group "SETCess_Group"when$cal : Calculation(wagemore > 4500 && wagemore <= 9000)then$cal.setCess(0.2);$cal.setPreminus(555);update($cal);
endrule "个人所得税:设置税率-->>应纳税所得额在9000志35000之间"salience 2no-loop trueactivation-group "SETCess_Group"when$cal : Calculation(wagemore > 9000 && wagemore <= 35000)then$cal.setCess(0.25);$cal.setPreminus(1005);update($cal);
endrule "个人所得税:设置税率-->>应纳税所得额在35000至55000之间"salience 2no-loop trueactivation-group "SETCess_Group"when$cal : Calculation(wagemore > 35000 && wagemore <= 55000)then$cal.setCess(0.3);$cal.setPreminus(2755);update($cal);
endrule "个人所得税:设置税率-->>应纳税所得额在55000至80000之间"salience 2no-loop trueactivation-group "SETCess_Group"when$cal : Calculation(wagemore > 55000 && wagemore <= 80000)then$cal.setCess(0.35);$cal.setPreminus(5505);update($cal);
endrule "个人所得税:设置税率-->>应纳税所得额在80000以上"salience 2no-loop trueactivation-group "SETCess_Group"when$cal : Calculation(wagemore > 80000)then$cal.setCess(0.45);$cal.setPreminus(13505);update($cal);
endrule "个人所得税:计算税后工资"salience 1when$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

第六步:创建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 {@Autowiredprivate KieBase kieBase;//个人所得税计算public Calculation calculate(Calculation calculation){KieSession kieSession = kieBase.newKieSession();kieSession.insert(calculation);kieSession.fireAllRules();kieSession.dispose();return calculation;}
}

第七步:创建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 {@Autowiredprivate 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;}
}

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

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

1.2 信用卡申请

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

1.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

1.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>

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

server:port: 8080
spring:application:name: creditCardApply

第三步:编写配置类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@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic 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@ConditionalOnMissingBeanpublic KieBase kieBase() throws IOException {return kieContainer().getKieBase();}@Bean@ConditionalOnMissingBeanpublic KModuleBeanFactoryPostProcessor kiePostProcessor() {return new KModuleBeanFactoryPostProcessor();}
}

第四步:编写实体类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 "审核不通过";}}
}

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

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

第六步:创建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 {@Autowiredprivate KieBase kieBase;//调用Drools规则引擎实现信用卡申请public CreditCardApplyInfo creditCardApply(CreditCardApplyInfo creditCardApplyInfo){KieSession session = kieBase.newKieSession();session.insert(creditCardApplyInfo);session.fireAllRules();session.dispose();return creditCardApplyInfo;}
}

第七步:创建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 {@Autowiredprivate RuleService ruleService;@RequestMapping("/creditCardApply")public CreditCardApplyInfo creditCardApply(@RequestBody CreditCardApplyInfo creditCardApplyInfo){creditCardApplyInfo = ruleService.creditCardApply(creditCardApplyInfo);return creditCardApplyInfo;}
}

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

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

1.3 保险产品准入规则

1.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 65535agenda-group "sign"when$person : PersonInfoEntity(sex != "男")thenlistRules.add("性别不对");
endrule "personCheck_11"salience 65534agenda-group "sign"when$person : PersonInfoEntity(age < 22 || age > 25)thenlistRules.add("年龄不合适");
endrule "personCheck_12"salience 65533agenda-group "sign"when$person : PersonInfoEntity(salary < 10000)thenlistRules.add("工资太低了");
end

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

<dependency><groupId>org.drools</groupId><artifactId>drools-decisiontables</artifactId><version>7.10.0.Final</version>
</dependency>

通过下图可以发现,由于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);

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

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

基于决策表的入门案例:

第一步:创建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>

第二步:创建实体类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;}
}

第三步:创建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.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万元需配合契调转线下出单

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

1.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>

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

server:port: 8080
spring:application:name: insuranceInfoCheck

第三步:创建实体类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省略
}

第四步:创建决策表文件(也可以直接使用实战资料中提供的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文件解析为Stringpublic static String getDRL (String realPath) throws FileNotFoundException {File file = new File(realPath); // 例如:C:\\abc.xlsInputStream 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));}
}

第六步:创建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;}
}

第七步:创建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 {@Autowiredprivate 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;}}
}

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

规则引擎Drools示例:个人所得税计算器、信用卡申请、保险产品准入规则相关推荐

  1. 规则引擎drools系列(一)

    规则引擎 Drools 1. 问题引出 现有一个在线申请信用卡的业务场景,用户需要录入个人信息,如下图所示: //此处为伪代码 ​ //检查用户信息合法性,返回true表示检查通过,返回false表示 ...

  2. 小明历险记:规则引擎drools教程一

    小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看. 小明的烦恼 活动规则是根据用户购买订单的金 ...

  3. 规则引擎drools【一】

    小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看. 一.小明的烦恼--线上活动规则频繁变更 活 ...

  4. 规则引擎 Drools

    规则引擎 Drools 文章目录 规则引擎 Drools 1. 问题引出 2. 规则引擎概述 2.1 什么是规则引擎 2.2 使用规则引擎的优势 2.3 规则引擎应用场景 2.4 Drools介绍 3 ...

  5. 【转】什么是规则引擎(Drools、OpenL Tablets、Easy Rules、RuleBook)

    什么是规则引擎(Drools.OpenL Tablets.Easy Rules.RuleBook) 发表于:2021年1月23日 分类:Drools, 规则引擎 标签:Drools, Easy-Rul ...

  6. 规则引擎 Drools学习详解

    1.规则引擎概述 1.1 什么是规则引擎 规则引擎,全称为业务规则管理系统,英文名为BRMS(即Business Rule Management System).规则引擎的主要思想是将应用程序中的业务 ...

  7. springboot中使用规则引擎Drools

    文章目录 规则引擎的场景 规则引擎介绍 使用规则引擎的优势 规则引擎应用场景 rools介绍 Drools入门案例 规则引擎构成 Drools基础语法 springboot使用规则引擎 规则引擎的场景 ...

  8. java排班_使用java规则引擎Drools自动排班前言.doc

    使用java规则引擎Drools自动排班前言 使用java规则引擎Drools自动排班前言本文以一个经简化的运输车队自动排班需求为例,详细讲解了如何使用java规则引擎Drools进行商业规则的形式语 ...

  9. 【Drools一】值得打工人学习的规则引擎Drools

    本文主要对Drools的使用业务场景做简单介绍. 规则引擎 规则引擎:全称为业务规则管理系统,英文名为BRMS(即Business Rule Management System).规则引擎的主要思想是 ...

最新文章

  1. ThinkPHP多应用/多模块配置
  2. SpringSecurity鉴权流程分析 附源码注释,xdm,一起来看看吧
  3. guava集合操作类的使用_使用Guava进行测试集合的实现
  4. Struts1中execute实现过滤控制
  5. linux下gdb调试程序
  6. [kuangbin带你飞]专题五 并查集 A - Wireless Network
  7. C ++中的初始化程序列表– std :: initializer_list
  8. 使用jxls技术导入Excel模版数据(转自其他博客)
  9. 一二线城市知名 IT 互联网公司名单!
  10. 小程序消息提示框标题字数限制
  11. 【高数】高数第八章节——向量代数与空间解析几何空间直角坐标系
  12. 如何统计网页的浏览量?Gate
  13. C# 将Excel导出PDF
  14. 数据分析师必备的python包
  15. 从普通大专到阿里只用了8个月,我是如何在迷茫期后面试阿里拿到Offer,定级阿里P7的?
  16. CODEFORCES 272C Dima and Staircase 细节理解题+简单技巧
  17. Python lambda 介绍
  18. Linux下使用KVM虚拟机运行MacOS和Checkra1n越狱工具
  19. 照书写轮子——图的五种常见接口的实现(DFS、BFS、最小生成树问题、最短路径问题、关键路径问题)
  20. 布局Mac,QQ浏览器全面出击

热门文章

  1. Git推送错误: failed to push some refs to ‘git@gitee.com:XXXXXX’
  2. 半导体物理·笔记之④晶体中原子的电子状态——能带
  3. php怎么转mp4,php使用memcoder将视频转成mp4格式的方法
  4. Web安全学习day01
  5. Xdebug中文文档-基础特性
  6. 人工智能换脸python_AI换脸(手把手教你实现吴彦祖变苏大强)
  7. 物联网为什么需要5G?
  8. [从头读历史] 第241节 根据天时定历法
  9. 使用Requests库进行网页爬取
  10. JavaScript 值得一读的书籍