全套代码及资料全部完整提供,点此处下载
前面我们编写的规则文件都是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坐标:
org.drools drools-decisiontables 7.10.0.Final
通过下图可以发现,由于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文件
org.drools drools-decisiontables 7.10.0.Final
junit junit 4.12
第二步:创建实体类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 list = new ArrayList();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: 保险公司是: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文件,业务人员可以直接更改这个文件中指标的值,系统不需要做任何变更。
本案例还是基于Spring Boot整合Drools的架构来实现。

第一步:创建maven工程insuranceInfoCheck并配置pom.xml文件
4.0.0 org.springframework.boot spring-boot-starters 2.0.6.RELEASE com.itheima insuranceInfoCheck 1.0-SNAPSHOT org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-starter-test commons-lang commons-lang 2.6 org.drools drools-core 7.6.0.Final org.drools drools-compiler 7.6.0.Final org.drools drools-templates 7.6.0.Final org.kie kie-api 7.6.0.Final org.kie kie-spring org.springframework spring-tx org.springframework spring-beans org.springframework spring-core org.springframework spring-context 7.6.0.Final ${project.artifactId} src/main/java **/*.xml false src/main/resources **/*.* false org.apache.maven.plugins maven-compiler-plugin 2.3.2 1.8 1.8
第二步:创建/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 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 insuranceInfoCheck(InsuranceInfo insuranceInfo) throws Exception{KieSession session = KieSessionUtils.getKieSessionFromXLS("D:\\rules.xls");session.getAgenda().getAgendaGroup("sign").setFocus();session.insert(insuranceInfo);List 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 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);}
}
全套代码及资料全部完整提供,点此处下载