[Drools]JAVA规则引擎 -- Drools 2
上一篇文章 http://blog.csdn.net/quzishen/archive/2011/01/25/6163012.aspx 描述了一些常用的drools的语法标签和一个模拟实例即发送积分的场景,这一片优化了一下代码,在此贴一下,希望有这方面使用经验的朋友多多交流沟通,指正不足。
通常而言,习惯上我们将规则放到文件系统中,比如以drl结尾的规则文件,现在我们要扩充一下,使其放到数据库中,以供多台服务器同时使用,同时依然保留文件系统的支持。
先看下一个接口:
- /**
- * 规则接口
- * @author quzishen
- */
- public interface PointRuleEngine {
- /**
- * 初始化规则引擎
- */
- public void initEngine();
- /**
- * 刷新规则引擎中的规则
- */
- public void refreshEnginRule();
- /**
- * 执行规则引擎
- * @param pointDomain 积分Fact
- */
- public void executeRuleEngine(final PointDomain pointDomain);
- }
实现过程没有任何难度,两种方式封装过程只在于读取规则的方式不同,代码很简单:
- package com.drools.demo.point;
- import <a href="http://lib.csdn.net/base/17" class='replace_word' title="Java EE知识库" target='_blank' style='color:#df3434; font-weight:bold;'>Java</a>.io.File;
- import java.io.FileNotFoundException;
- import java.io.FileReader;
- import java.io.Reader;
- import java.io.StringReader;
- import java.util.ArrayList;
- import java.util.List;
- import org.drools.RuleBase;
- import org.drools.StatefulSession;
- import org.drools.compiler.PackageBuilder;
- import org.drools.spi.Activation;
- /**
- * 规则接口实现类
- *
- * @author quzishen
- */
- public class PointRuleEngineImpl implements PointRuleEngine {
- // ~~~ instance filed begin
- /** RuleBase */
- private RuleBase ruleBase;
- // ~~~ instance filed end
- /*
- * (non-Javadoc)
- * @see com.drools.demo.point.PointRuleEngine#initEngine()
- */
- public void initEngine() {
- // 设置时间格式
- System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
- try {
- synchronized (this) {
- ruleBase = RuleBaseFacatory.getRuleBase();
- // 优先从DB加载规则,如果没有加载到或者加载错误,则从文件系统加载
- PackageBuilder backageBuilder = getPackBuilderFromDrlDB();
- backageBuilder = null == backageBuilder ? getPackageBuilderFromDrlFile()
- : backageBuilder;
- ruleBase.addPackages(backageBuilder.getPackages());
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- /*
- * (non-Javadoc)
- * @see com.drools.demo.point.PointRuleEngine#refreshEnginRule()
- */
- public void refreshEnginRule() {
- ruleBase = RuleBaseFacatory.getRuleBase();
- synchronized (ruleBase) {
- // 删除所有的添加的Package
- org.drools.rule.Package[] packages = ruleBase.getPackages();
- for (org.drools.rule.Package pg : packages) {
- ruleBase.removePackage(pg.getName());
- }
- // 重新初始化规则引擎
- initEngine();
- }
- }
- /*
- * (non-Javadoc)
- * @see com.drools.demo.point.PointRuleEngine#executeRuleEngine(com.drools.demo.point.PointDomain)
- */
- public void executeRuleEngine(final PointDomain pointDomain) {
- if (null == ruleBase.getPackages() || 0 == ruleBase.getPackages().length) {
- return;
- }
- StatefulSession statefulSession = ruleBase.newStatefulSession();
- statefulSession.insert(pointDomain);
- // fire
- statefulSession.fireAllRules(new org.drools.spi.AgendaFilter() {
- public boolean accept(Activation activation) {
- return !activation.getRule().getName().contains("_test");
- }
- });
- statefulSession.dispose();
- }
- /**
- * 从Drl规则文件中读取规则
- *
- * @return
- * @throws Exception
- */
- private PackageBuilder getPackageBuilderFromDrlFile() {
- // 装载规则文件
- List<Reader> readers;
- try {
- readers = buildReadersFromDrlFile();
- // 装载PackageBuilder
- return buildPackageBuilder(readers);
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- return null;
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 从Drl规则DB中读取规则
- *
- * @return
- * @throws Exception
- */
- private PackageBuilder getPackBuilderFromDrlDB() {
- // 装载规则
- List<Reader> readers = buildReadersFromDrlDB();
- // 装载PackageBuilder
- try {
- return buildPackageBuilder(readers);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 装载db中的规则到List<Reader>
- *
- * @return
- */
- private List<Reader> buildReadersFromDrlDB() {
- List<Reader> readers = new ArrayList<Reader>();
- // 获取脚本
- List<DroolsRuleDomain> drlRuleDomains = getRuleFromDB();
- if (null == drlRuleDomains) {
- return readers;
- }
- for (DroolsRuleDomain droolsRuleDomain : drlRuleDomains) {
- String ruleContext = droolsRuleDomain.getRuleContext();
- Reader br = new StringReader(ruleContext);
- readers.add(br);
- }
- return readers;
- }
- /**
- * 装载PackageBuilder
- *
- * @param readers
- * @return
- * @throws Exception
- */
- private PackageBuilder buildPackageBuilder(List<Reader> readers)
- throws Exception {
- if (null == readers || 0 == readers.size()) {
- return null;
- }
- PackageBuilder backageBuilder = new PackageBuilder();
- for (Reader r : readers) {
- backageBuilder.addPackageFromDrl(r);
- }
- // 检查脚本是否有问题
- if (backageBuilder.hasErrors()) {
- throw new Exception(backageBuilder.getErrors().toString());
- }
- return backageBuilder;
- }
- /**
- * 装载规则文件到Reader中
- *
- * @return
- * @throws FileNotFoundException
- */
- private List<Reader> buildReadersFromDrlFile() throws FileNotFoundException {
- // 获取脚本文件
- List<String> drlFilePath = getRuleDrlFile();
- // 装载脚本文件
- return readRuleFromDrlFile(drlFilePath);
- }
- /**
- * 从规则文件中读取规则
- *
- * @param drlFilePath 脚本文件路径
- * @return
- * @throws FileNotFoundException
- */
- private List<Reader> readRuleFromDrlFile(List<String> drlFilePath)
- throws FileNotFoundException {
- if (null == drlFilePath || 0 == drlFilePath.size()) {
- return null;
- }
- List<Reader> readers = new ArrayList<Reader>();
- for (String ruleFilePath : drlFilePath) {
- readers.add(new FileReader(new File(ruleFilePath)));
- }
- return readers;
- }
- /**
- * 从数据库中获取规则脚本内容
- *
- * @return
- */
- private List<DroolsRuleDomain> getRuleFromDB() {
- // 测试代码
- List<DroolsRuleDomain> droolsRuleDomains = new ArrayList<DroolsRuleDomain>();
- DroolsRuleDomain d1 = new DroolsRuleDomain();
- d1.setId(1);
- d1.setRuleContext("package com.drools.demo.point" + "/n" +
- "import com.drools.demo.point.PointDomain;" + "/n" +
- "rule birthdayPoint" + "/n" +
- "// 过生日,则加10分,并且将当月交易比数翻倍后再计算积分" + "/n" +
- "salience 100" + "/n" +
- "lock-on-active true" + "/n" +
- "when" + "/n" +
- "$pointDomain : PointDomain(birthDay == true)" + "/n" +
- "then" + "/n" +
- "$pointDomain.setPoint($pointDomain.getPoint()+10);" + "/n" +
- "$pointDomain.recordPointLog($pointDomain.getUserName(),/"birthdayPoint/");" + "/n" +
- "end");
- d1.setRuleName("testRule");
- d1.setVersion(1);
- droolsRuleDomains.add(d1);
- return droolsRuleDomains;
- }
- /**
- * 获取规则文件
- *
- * @return
- */
- private List<String> getRuleDrlFile() {
- List<String> drlFilePath = new ArrayList<String>();
- drlFilePath
- .add("D:/workspace2/DroolsDemo/src/com/drools/demo/point/addpoint.drl");
- drlFilePath
- .add("D:/workspace2/DroolsDemo/src/com/drools/demo/point/subpoint.drl");
- return drlFilePath;
- }
- }
其中的getRuleFromDB() 和 getRuleDrlFile() 两个方法即可以重写以接入个人系统,现在其中编写的是测试代码。
其他的文件与上篇文章相同:
RuleBaseFacatory
- package com.drools.demo.point;
- import org.drools.RuleBase;
- import org.drools.RuleBaseFactory;
- /**
- * RuleBaseFacatory 单实例RuleBase生成工具
- * @author quzishen
- */
- public class RuleBaseFacatory {
- private static RuleBase ruleBase;
- public static RuleBase getRuleBase(){
- return null != ruleBase ? ruleBase : RuleBaseFactory.newRuleBase();
- }
- }
DroolsRuleDomain
- package com.drools.demo.point;
- /**
- * 规则内容domain
- *
- * @author quzishen
- */
- public class DroolsRuleDomain {
- /** 数据库记录ID */
- private long id;
- /** 规则名称 */
- private String ruleName;
- /** 规则正文 */
- private String ruleContext;
- /** 规则版本 */
- private int version;
- /** 规则脚本状态 */
- private int status;
- public long getId() {
- return id;
- }
- public void setId(long id) {
- this.id = id;
- }
- public String getRuleName() {
- return ruleName;
- }
- public void setRuleName(String ruleName) {
- this.ruleName = ruleName;
- }
- public String getRuleContext() {
- return ruleContext;
- }
- public void setRuleContext(String ruleContext) {
- this.ruleContext = ruleContext;
- }
- public int getVersion() {
- return version;
- }
- public void setVersion(int version) {
- this.version = version;
- }
- public int getStatus() {
- return status;
- }
- public void setStatus(int status) {
- this.status = status;
- }
- }
PointDomain
- package com.drools.demo.point;
- /**
- * 积分计算对象
- * @author quzishen
- */
- public class PointDomain {
- // 用户名
- private String userName;
- // 是否当日生日
- private boolean birthDay;
- // 增加积分数目
- private long point;
- // 当月购物次数
- private int buyNums;
- // 当月退货次数
- private int backNums;
- // 当月购物总金额
- private double buyMoney;
- // 当月退货总金额
- private double backMondy;
- // 当月信用卡还款次数
- private int billThisMonth;
- /**
- * 记录积分发送流水,防止重复发放
- * @param userName 用户名
- * @param type 积分发放类型
- */
- public void recordPointLog(String userName, String type){
- System.out.println("增加对"+userName+"的类型为"+type+"的积分操作记录.");
- }
- public String getUserName() {
- return userName;
- }
- public void setUserName(String userName) {
- this.userName = userName;
- }
- public boolean isBirthDay() {
- return birthDay;
- }
- public void setBirthDay(boolean birthDay) {
- this.birthDay = birthDay;
- }
- public long getPoint() {
- return point;
- }
- public void setPoint(long point) {
- this.point = point;
- }
- public int getBuyNums() {
- return buyNums;
- }
- public void setBuyNums(int buyNums) {
- this.buyNums = buyNums;
- }
- public int getBackNums() {
- return backNums;
- }
- public void setBackNums(int backNums) {
- this.backNums = backNums;
- }
- public double getBuyMoney() {
- return buyMoney;
- }
- public void setBuyMoney(double buyMoney) {
- this.buyMoney = buyMoney;
- }
- public double getBackMondy() {
- return backMondy;
- }
- public void setBackMondy(double backMondy) {
- this.backMondy = backMondy;
- }
- public int getBillThisMonth() {
- return billThisMonth;
- }
- public void setBillThisMonth(int billThisMonth) {
- this.billThisMonth = billThisMonth;
- }
- }
addpoint.drl
- package com.drools.demo.point
- import com.drools.demo.point.PointDomain;
- rule birthdayPoint
- // 过生日,则加10分,并且将当月交易比数翻倍后再计算积分
- salience 100
- lock-on-active true
- when
- $pointDomain : PointDomain(birthDay == true)
- then
- $pointDomain.setPoint($pointDomain.getPoint()+10);
- $pointDomain.setBuyNums($pointDomain.getBuyNums()*2);
- $pointDomain.setBuyMoney($pointDomain.getBuyMoney()*2);
- $pointDomain.setBillThisMonth($pointDomain.getBillThisMonth()*2);
- $pointDomain.recordPointLog($pointDomain.getUserName(),"birthdayPoint");
- end
- rule billThisMonthPoint
- // 2011-01-08 - 2011-08-08每月信用卡还款3次以上,每满3笔赠送30分
- salience 99
- lock-on-active true
- date-effective "2011-01-08 23:59:59"
- date-expires "2011-08-08 23:59:59"
- when
- $pointDomain : PointDomain(billThisMonth >= 3)
- then
- $pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBillThisMonth()/3*30);
- $pointDomain.recordPointLog($pointDomain.getUserName(),"billThisMonthPoint");
- end
- rule buyMoneyPoint
- // 当月购物总金额100以上,每100元赠送10分
- salience 98
- lock-on-active true
- when
- $pointDomain : PointDomain(buyMoney >= 100)
- then
- $pointDomain.setPoint($pointDomain.getPoint()+ (int)$pointDomain.getBuyMoney()/100 * 10);
- $pointDomain.recordPointLog($pointDomain.getUserName(),"buyMoneyPoint");
- end
- rule buyNumsPoint
- // 当月购物次数5次以上,每五次赠送50分
- salience 97
- lock-on-active true
- when
- $pointDomain : PointDomain(buyNums >= 5)
- then
- $pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBuyNums()/5 * 50);
- $pointDomain.recordPointLog($pointDomain.getUserName(),"buyNumsPoint");
- end
- rule allFitPoint
- // 特别的,如果全部满足了要求,则额外奖励100分
- salience 96
- lock-on-active true
- when
- $pointDomain:PointDomain(buyNums >= 5 && billThisMonth >= 3 && buyMoney >= 100)
- then
- $pointDomain.setPoint($pointDomain.getPoint()+ 100);
- $pointDomain.recordPointLog($pointDomain.getUserName(),"allFitPoint");
- end
subpoint.drl 与上一篇相同,请参见上一篇,此处省略篇幅略
测试代码
Test
- package com.drools.demo.point;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- public class Test {
- /**
- * @param args
- * @throws IOException
- */
- public static void main(String[] args) throws IOException {
- PointRuleEngine pointRuleEngine = new PointRuleEngineImpl();
- boolean isStart = false;
- while(true){
- InputStream is = System.in;
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
- String input = br.readLine();
- if (null != input && "s".equals(input)){
- System.out.println("初始化规则引擎...");
- pointRuleEngine.initEngine();
- isStart = true;
- System.out.println("初始化规则引擎结束.");
- } else if ("e".equals(input)){
- if (!isStart) {
- System.out.println("需要输入s启动");
- } else {
- final PointDomain pointDomain = new PointDomain();
- pointDomain.setUserName("hello kity");
- pointDomain.setBackMondy(100d);
- pointDomain.setBuyMoney(500d);
- pointDomain.setBackNums(1);
- pointDomain.setBuyNums(5);
- pointDomain.setBillThisMonth(5);
- pointDomain.setBirthDay(true);
- pointDomain.setPoint(0l);
- pointRuleEngine.executeRuleEngine(pointDomain);
- System.out.println("执行完毕BillThisMonth:"+pointDomain.getBillThisMonth());
- System.out.println("执行完毕BuyMoney:"+pointDomain.getBuyMoney());
- System.out.println("执行完毕BuyNums:"+pointDomain.getBuyNums());
- System.out.println("执行完毕规则引擎决定发送积分:"+pointDomain.getPoint());
- }
- } else if ("r".equals(input)){
- System.out.println("刷新规则文件...");
- pointRuleEngine.refreshEnginRule();
- isStart = true;
- System.out.println("刷新规则文件结束.");
- } else if ("q".equals(input)) {
- System.exit(0);
- }
- }
- }
- }
[Drools]JAVA规则引擎 -- Drools 2的更多相关文章
- [Drools]JAVA规则引擎 -- Drools
Drools是一个基于Java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效. 本文所使用的de ...
- [Drools]JAVA规则引擎 -- Drools- 转http://blog.csdn.net/quzishen/article/details/6163012
[Drools]JAVA规则引擎 -- Drools 标签: java引擎exceptiongetterstringsetter 2011-01-25 14:33 113340人阅读 评论(35) 收 ...
- Java规则引擎drools:drt动态生成规则并附上具体项目逻辑
一 整合 由于本人的码云太多太乱了,于是决定一个一个的整合到一个springboot项目里面. 附上自己的项目地址https://github.com/247292980/spring-boot 以整 ...
- JAVA规则引擎 -- Drools
Drools是一个基于java的规则引擎,开源的,可以将复杂多变的规则从硬编码中解放出来,以规则脚本的形式存放在文件中,使得规则的变更不需要修正代码重启机器就可以立即在线上环境生效. 本文所使用的de ...
- 小明历险记:规则引擎drools教程一
小明是一家互联网公司的软件工程师,他们公司为了吸引新用户经常会搞活动,小明常常为了做活动加班加点很烦躁,这不今天呀又来了一个活动需求,我们大家一起帮他看看. 小明的烦恼 活动规则是根据用户购买订单的金 ...
- 规则引擎 drools
https://www.jianshu.com/p/725811f420db 深入了解Drools 简单介绍 笔者正在做风控系统,风控系统里边存在非常多的规则(比如:age < 16 || ag ...
- 开源规则引擎 drools
java语言开发的开源业务规则引擎 DROOLS(JBOSS RULES )具有一个易于访问企业策略.易于调整以及易于管理的开源业务规则引擎,符合业内标准,速度快.效率高.业务分析师或审核人员可以利用 ...
- 规则引擎drools封装
一.前言 网上规则引擎drools介绍很多,并且有很多细致的说明,作者也不敢托大说自己的好用,但作者经过2个项目使用过规则引擎后,自己对规则引擎的理解并进行封装,对规则内容及如何使用,有自己的一番实践 ...
- 开源规则引擎 Drools 学习笔记 之 -- 1 cannot be cast to org.drools.compiler.kie.builder.impl.InternalKieModule
直接进入正题 我们在使用开源规则引擎 Drools 的时候, 启动的时候可能会抛出如下异常: Caused by: java.lang.ClassCastException: cn.com.cheng ...
随机推荐
- CloudEra Email Search
http://blog.cloudera.com/blog/2013/09/email-indexing-using-cloudera-search/ http://blog.cloudera.com ...
- HTML5 服务器发送事件(Server-Sent Events)介绍
w3cschool菜鸟教程 Server-Sent 事件 - 单向消息传递 Server-Sent 事件指的是网页自动获取来自服务器的更新. 以前也可能做到这一点,前提是网页不得不询问是否有可用的更新 ...
- paip.QQ音乐导出歌单总结
paip.QQ音乐导出歌单总结 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/attilax ...
- network is unreachable 解决方案之一
请按http://blog.csdn.net/oxiaoxio/article/details/41775183 一文中的设置方法设置:
- istream类的公有成员函数
1 eatwhite 2 get 3 getline 4 gcount 5 ignore 6 operator>> 7 peek 8 read 9 seekg 10 tellg 1 eat ...
- POJ 1556 计算几何+最短路
代码1: #include<iostream> #include<stdio.h> #include<string> #include<string.h> ...
- 黑马程序员 Java基础<十八>---> 网路编程
--------------- ASP.Net+Android+IO开发S..Net培训.期待与您交流! --------------- 第一 概述 一.概述: 1.网络模型:OSI参考模型和TCP ...
- VM 443端口冲突解决办法
netstat -aon|findstr "443" 找到占用443的进程号: tasklist|findstr "2016" 根据进程号2016找到占用443 ...
- @property和@synthesize
main.m #import <Foundation/Foundation.h> #import "Student.h" int main(int argc, cons ...
- java list 去除 重复值
一: Hastset根据hashcode判断是否重复,数据不会重复 Java代码 /** List order not maintained **/ public static void remove ...