• [Drools]JAVA规则引擎 -- Drools 2


    上一篇文章 http://blog.csdn.net/quzishen/archive/2011/01/25/6163012.aspx 描述了一些常用的drools的语法标签和一个模拟实例即发送积分的场景,这一片优化了一下代码,在此贴一下,希望有这方面使用经验的朋友多多交流沟通,指正不足。

    通常而言,习惯上我们将规则放到文件系统中,比如以drl结尾的规则文件,现在我们要扩充一下,使其放到数据库中,以供多台服务器同时使用,同时依然保留文件系统的支持。

    先看下一个接口:

    [java] view plain copy
     
     
    1. /** 
    2.  * 规则接口 
    3.  * @author quzishen 
    4.  */  
    5. public interface PointRuleEngine {  
    6.       
    7.     /** 
    8.      * 初始化规则引擎 
    9.      */  
    10.     public void initEngine();  
    11.       
    12.     /** 
    13.      * 刷新规则引擎中的规则 
    14.      */  
    15.     public void refreshEnginRule();  
    16.       
    17.     /** 
    18.      * 执行规则引擎 
    19.      * @param pointDomain 积分Fact 
    20.      */  
    21.     public void executeRuleEngine(final PointDomain pointDomain);  
    22. }  

    实现过程没有任何难度,两种方式封装过程只在于读取规则的方式不同,代码很简单:

    [java] view plain copy
     
     
    1. package com.drools.demo.point;  
    2.   
    3. 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;  
    4. import java.io.FileNotFoundException;  
    5. import java.io.FileReader;  
    6. import java.io.Reader;  
    7. import java.io.StringReader;  
    8. import java.util.ArrayList;  
    9. import java.util.List;  
    10. import org.drools.RuleBase;  
    11. import org.drools.StatefulSession;  
    12. import org.drools.compiler.PackageBuilder;  
    13. import org.drools.spi.Activation;  
    14.   
    15. /** 
    16.  * 规则接口实现类 
    17.  *  
    18.  * @author quzishen 
    19.  */  
    20. public class PointRuleEngineImpl implements PointRuleEngine {  
    21.     // ~~~ instance filed begin  
    22.     /** RuleBase */  
    23.     private RuleBase ruleBase;  
    24.     // ~~~ instance filed end  
    25.   
    26.     /* 
    27.      * (non-Javadoc) 
    28.      * @see com.drools.demo.point.PointRuleEngine#initEngine() 
    29.      */  
    30.     public void initEngine() {  
    31.         // 设置时间格式  
    32.         System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");  
    33.         try {  
    34.             synchronized (this) {  
    35.                 ruleBase = RuleBaseFacatory.getRuleBase();  
    36.                 // 优先从DB加载规则,如果没有加载到或者加载错误,则从文件系统加载  
    37.                 PackageBuilder backageBuilder = getPackBuilderFromDrlDB();  
    38.                 backageBuilder = null == backageBuilder ? getPackageBuilderFromDrlFile()  
    39.                         : backageBuilder;  
    40.   
    41.                 ruleBase.addPackages(backageBuilder.getPackages());  
    42.             }  
    43.         } catch (Exception e) {  
    44.             e.printStackTrace();  
    45.         }  
    46.     }  
    47.   
    48.     /* 
    49.      * (non-Javadoc) 
    50.      * @see com.drools.demo.point.PointRuleEngine#refreshEnginRule() 
    51.      */  
    52.     public void refreshEnginRule() {  
    53.         ruleBase = RuleBaseFacatory.getRuleBase();  
    54.         synchronized (ruleBase) {  
    55.             // 删除所有的添加的Package  
    56.             org.drools.rule.Package[] packages = ruleBase.getPackages();  
    57.             for (org.drools.rule.Package pg : packages) {  
    58.                 ruleBase.removePackage(pg.getName());  
    59.             }  
    60.               
    61.             // 重新初始化规则引擎  
    62.             initEngine();  
    63.         }  
    64.     }  
    65.       
    66.     /* 
    67.      * (non-Javadoc) 
    68.      * @see com.drools.demo.point.PointRuleEngine#executeRuleEngine(com.drools.demo.point.PointDomain) 
    69.      */  
    70.     public void executeRuleEngine(final PointDomain pointDomain) {  
    71.         if (null == ruleBase.getPackages() || 0 == ruleBase.getPackages().length) {  
    72.             return;  
    73.         }  
    74.   
    75.         StatefulSession statefulSession = ruleBase.newStatefulSession();  
    76.         statefulSession.insert(pointDomain);  
    77.   
    78.         // fire  
    79.         statefulSession.fireAllRules(new org.drools.spi.AgendaFilter() {  
    80.             public boolean accept(Activation activation) {  
    81.                 return !activation.getRule().getName().contains("_test");  
    82.             }  
    83.         });  
    84.   
    85.         statefulSession.dispose();  
    86.     }  
    87.   
    88.     /** 
    89.      * 从Drl规则文件中读取规则 
    90.      *  
    91.      * @return 
    92.      * @throws Exception 
    93.      */  
    94.     private PackageBuilder getPackageBuilderFromDrlFile() {  
    95.         // 装载规则文件  
    96.         List<Reader> readers;  
    97.         try {  
    98.             readers = buildReadersFromDrlFile();  
    99.             // 装载PackageBuilder  
    100.             return buildPackageBuilder(readers);  
    101.         } catch (FileNotFoundException e) {  
    102.             e.printStackTrace();  
    103.             return null;  
    104.         } catch (Exception e) {  
    105.             e.printStackTrace();  
    106.             return null;  
    107.         }  
    108.     }  
    109.   
    110.     /** 
    111.      * 从Drl规则DB中读取规则 
    112.      *  
    113.      * @return 
    114.      * @throws Exception 
    115.      */  
    116.     private PackageBuilder getPackBuilderFromDrlDB() {  
    117.         // 装载规则  
    118.         List<Reader> readers = buildReadersFromDrlDB();  
    119.   
    120.         // 装载PackageBuilder  
    121.         try {  
    122.             return buildPackageBuilder(readers);  
    123.         } catch (Exception e) {  
    124.             e.printStackTrace();  
    125.             return null;  
    126.         }  
    127.     }  
    128.   
    129.     /** 
    130.      * 装载db中的规则到List<Reader> 
    131.      *  
    132.      * @return 
    133.      */  
    134.     private List<Reader> buildReadersFromDrlDB() {  
    135.         List<Reader> readers = new ArrayList<Reader>();  
    136.         // 获取脚本  
    137.         List<DroolsRuleDomain> drlRuleDomains = getRuleFromDB();  
    138.   
    139.         if (null == drlRuleDomains) {  
    140.             return readers;  
    141.         }  
    142.   
    143.         for (DroolsRuleDomain droolsRuleDomain : drlRuleDomains) {  
    144.             String ruleContext = droolsRuleDomain.getRuleContext();  
    145.   
    146.             Reader br = new StringReader(ruleContext);  
    147.             readers.add(br);  
    148.         }  
    149.         return readers;  
    150.     }  
    151.   
    152.     /** 
    153.      * 装载PackageBuilder 
    154.      *  
    155.      * @param readers 
    156.      * @return 
    157.      * @throws Exception 
    158.      */  
    159.     private PackageBuilder buildPackageBuilder(List<Reader> readers)  
    160.             throws Exception {  
    161.         if (null == readers || 0 == readers.size()) {  
    162.             return null;  
    163.         }  
    164.   
    165.         PackageBuilder backageBuilder = new PackageBuilder();  
    166.         for (Reader r : readers) {  
    167.             backageBuilder.addPackageFromDrl(r);  
    168.         }  
    169.   
    170.         // 检查脚本是否有问题  
    171.         if (backageBuilder.hasErrors()) {  
    172.             throw new Exception(backageBuilder.getErrors().toString());  
    173.         }  
    174.   
    175.         return backageBuilder;  
    176.     }  
    177.   
    178.     /** 
    179.      * 装载规则文件到Reader中 
    180.      *  
    181.      * @return 
    182.      * @throws FileNotFoundException 
    183.      */  
    184.     private List<Reader> buildReadersFromDrlFile() throws FileNotFoundException {  
    185.         // 获取脚本文件  
    186.         List<String> drlFilePath = getRuleDrlFile();  
    187.         // 装载脚本文件  
    188.         return readRuleFromDrlFile(drlFilePath);  
    189.     }  
    190.   
    191.     /** 
    192.      * 从规则文件中读取规则 
    193.      *  
    194.      * @param drlFilePath 脚本文件路径 
    195.      * @return 
    196.      * @throws FileNotFoundException 
    197.      */  
    198.     private List<Reader> readRuleFromDrlFile(List<String> drlFilePath)  
    199.             throws FileNotFoundException {  
    200.         if (null == drlFilePath || 0 == drlFilePath.size()) {  
    201.             return null;  
    202.         }  
    203.   
    204.         List<Reader> readers = new ArrayList<Reader>();  
    205.   
    206.         for (String ruleFilePath : drlFilePath) {  
    207.             readers.add(new FileReader(new File(ruleFilePath)));  
    208.         }  
    209.   
    210.         return readers;  
    211.     }  
    212.   
    213.     /** 
    214.      * 从数据库中获取规则脚本内容 
    215.      *  
    216.      * @return 
    217.      */  
    218.     private List<DroolsRuleDomain> getRuleFromDB() {  
    219.         // 测试代码  
    220.         List<DroolsRuleDomain> droolsRuleDomains = new ArrayList<DroolsRuleDomain>();  
    221.           
    222.         DroolsRuleDomain d1 = new DroolsRuleDomain();  
    223.         d1.setId(1);  
    224.         d1.setRuleContext("package com.drools.demo.point" + "/n" +   
    225.                 "import com.drools.demo.point.PointDomain;" + "/n" +   
    226.                 "rule birthdayPoint" + "/n" +   
    227.                 "// 过生日,则加10分,并且将当月交易比数翻倍后再计算积分" + "/n" +   
    228.                 "salience 100" + "/n" +   
    229.                 "lock-on-active true" + "/n" +   
    230.                 "when" + "/n" +   
    231.                 "$pointDomain : PointDomain(birthDay == true)" + "/n" +   
    232.                 "then" + "/n" +   
    233.                 "$pointDomain.setPoint($pointDomain.getPoint()+10);" + "/n" +   
    234.                 "$pointDomain.recordPointLog($pointDomain.getUserName(),/"birthdayPoint/");" + "/n" +   
    235.                 "end");  
    236.           
    237.         d1.setRuleName("testRule");  
    238.         d1.setVersion(1);  
    239.           
    240.         droolsRuleDomains.add(d1);  
    241.   
    242.         return droolsRuleDomains;  
    243.     }  
    244.   
    245.     /** 
    246.      * 获取规则文件 
    247.      *  
    248.      * @return 
    249.      */  
    250.     private List<String> getRuleDrlFile() {  
    251.         List<String> drlFilePath = new ArrayList<String>();  
    252.         drlFilePath  
    253.                 .add("D:/workspace2/DroolsDemo/src/com/drools/demo/point/addpoint.drl");  
    254.         drlFilePath  
    255.                 .add("D:/workspace2/DroolsDemo/src/com/drools/demo/point/subpoint.drl");  
    256.   
    257.         return drlFilePath;  
    258.     }  
    259. }  

    其中的getRuleFromDB() 和 getRuleDrlFile() 两个方法即可以重写以接入个人系统,现在其中编写的是测试代码。

    其他的文件与上篇文章相同:

    RuleBaseFacatory

    [java] view plain copy
     
     
    1. package com.drools.demo.point;  
    2.   
    3. import org.drools.RuleBase;  
    4. import org.drools.RuleBaseFactory;  
    5.   
    6. /** 
    7.  * RuleBaseFacatory 单实例RuleBase生成工具 
    8.  * @author quzishen 
    9.  */  
    10. public class RuleBaseFacatory {  
    11.     private static RuleBase ruleBase;  
    12.       
    13.     public static RuleBase getRuleBase(){  
    14.         return null != ruleBase ? ruleBase : RuleBaseFactory.newRuleBase();  
    15.     }  
    16. }  

    DroolsRuleDomain

    [java] view plain copy
     
     
    1. package com.drools.demo.point;  
    2.   
    3. /** 
    4.  * 规则内容domain 
    5.  *  
    6.  * @author quzishen 
    7.  */  
    8. public class DroolsRuleDomain {  
    9.     /** 数据库记录ID */  
    10.     private long id;  
    11.     /** 规则名称 */  
    12.     private String ruleName;  
    13.     /** 规则正文  */  
    14.     private String ruleContext;  
    15.     /** 规则版本 */  
    16.     private int version;  
    17.     /** 规则脚本状态 */  
    18.     private int status;  
    19.   
    20.     public long getId() {  
    21.         return id;  
    22.     }  
    23.   
    24.     public void setId(long id) {  
    25.         this.id = id;  
    26.     }  
    27.   
    28.     public String getRuleName() {  
    29.         return ruleName;  
    30.     }  
    31.   
    32.     public void setRuleName(String ruleName) {  
    33.         this.ruleName = ruleName;  
    34.     }  
    35.   
    36.     public String getRuleContext() {  
    37.         return ruleContext;  
    38.     }  
    39.   
    40.     public void setRuleContext(String ruleContext) {  
    41.         this.ruleContext = ruleContext;  
    42.     }  
    43.   
    44.     public int getVersion() {  
    45.         return version;  
    46.     }  
    47.   
    48.     public void setVersion(int version) {  
    49.         this.version = version;  
    50.     }  
    51.   
    52.     public int getStatus() {  
    53.         return status;  
    54.     }  
    55.   
    56.     public void setStatus(int status) {  
    57.         this.status = status;  
    58.     }  
    59.       
    60. }  

    PointDomain

    [java] view plain copy
     
     
    1. package com.drools.demo.point;  
    2.   
    3.   
    4. /** 
    5.  * 积分计算对象 
    6.  * @author quzishen 
    7.  */  
    8. public class PointDomain {  
    9.     // 用户名  
    10.     private String userName;  
    11.     // 是否当日生日  
    12.     private boolean birthDay;  
    13.     // 增加积分数目  
    14.     private long point;  
    15.     // 当月购物次数  
    16.     private int buyNums;  
    17.     // 当月退货次数  
    18.     private int backNums;  
    19.     // 当月购物总金额  
    20.     private double buyMoney;  
    21.     // 当月退货总金额  
    22.     private double backMondy;  
    23.     // 当月信用卡还款次数  
    24.     private int billThisMonth;  
    25.       
    26.     /** 
    27.      * 记录积分发送流水,防止重复发放 
    28.      * @param userName 用户名 
    29.      * @param type 积分发放类型 
    30.      */  
    31.     public void recordPointLog(String userName, String type){  
    32.         System.out.println("增加对"+userName+"的类型为"+type+"的积分操作记录.");  
    33.     }  
    34.   
    35.     public String getUserName() {  
    36.         return userName;  
    37.     }  
    38.   
    39.     public void setUserName(String userName) {  
    40.         this.userName = userName;  
    41.     }  
    42.   
    43.     public boolean isBirthDay() {  
    44.         return birthDay;  
    45.     }  
    46.   
    47.     public void setBirthDay(boolean birthDay) {  
    48.         this.birthDay = birthDay;  
    49.     }  
    50.   
    51.     public long getPoint() {  
    52.         return point;  
    53.     }  
    54.   
    55.     public void setPoint(long point) {  
    56.         this.point = point;  
    57.     }  
    58.   
    59.     public int getBuyNums() {  
    60.         return buyNums;  
    61.     }  
    62.   
    63.     public void setBuyNums(int buyNums) {  
    64.         this.buyNums = buyNums;  
    65.     }  
    66.   
    67.     public int getBackNums() {  
    68.         return backNums;  
    69.     }  
    70.   
    71.     public void setBackNums(int backNums) {  
    72.         this.backNums = backNums;  
    73.     }  
    74.   
    75.     public double getBuyMoney() {  
    76.         return buyMoney;  
    77.     }  
    78.   
    79.     public void setBuyMoney(double buyMoney) {  
    80.         this.buyMoney = buyMoney;  
    81.     }  
    82.   
    83.     public double getBackMondy() {  
    84.         return backMondy;  
    85.     }  
    86.   
    87.     public void setBackMondy(double backMondy) {  
    88.         this.backMondy = backMondy;  
    89.     }  
    90.   
    91.     public int getBillThisMonth() {  
    92.         return billThisMonth;  
    93.     }  
    94.   
    95.     public void setBillThisMonth(int billThisMonth) {  
    96.         this.billThisMonth = billThisMonth;  
    97.     }  
    98.   
    99. }  

    addpoint.drl

    [java] view plain copy
     
     
    1. package com.drools.demo.point  
    2.   
    3. import com.drools.demo.point.PointDomain;  
    4.   
    5. rule birthdayPoint  
    6.     // 过生日,则加10分,并且将当月交易比数翻倍后再计算积分  
    7.     salience 100  
    8.     lock-on-active true  
    9.     when  
    10.         $pointDomain : PointDomain(birthDay == true)  
    11.     then  
    12.         $pointDomain.setPoint($pointDomain.getPoint()+10);  
    13.         $pointDomain.setBuyNums($pointDomain.getBuyNums()*2);  
    14.         $pointDomain.setBuyMoney($pointDomain.getBuyMoney()*2);  
    15.         $pointDomain.setBillThisMonth($pointDomain.getBillThisMonth()*2);  
    16.           
    17.         $pointDomain.recordPointLog($pointDomain.getUserName(),"birthdayPoint");  
    18. end  
    19.   
    20. rule billThisMonthPoint  
    21.     // 2011-01-08 - 2011-08-08每月信用卡还款3次以上,每满3笔赠送30分  
    22.     salience 99  
    23.     lock-on-active true  
    24.     date-effective "2011-01-08 23:59:59"  
    25.     date-expires "2011-08-08 23:59:59"  
    26.     when  
    27.         $pointDomain : PointDomain(billThisMonth >= 3)  
    28.     then  
    29.         $pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBillThisMonth()/3*30);  
    30.         $pointDomain.recordPointLog($pointDomain.getUserName(),"billThisMonthPoint");  
    31. end  
    32.   
    33. rule buyMoneyPoint  
    34.     // 当月购物总金额100以上,每100元赠送10分  
    35.     salience 98  
    36.     lock-on-active true  
    37.     when  
    38.         $pointDomain : PointDomain(buyMoney >= 100)  
    39.     then  
    40.         $pointDomain.setPoint($pointDomain.getPoint()+ (int)$pointDomain.getBuyMoney()/100 * 10);  
    41.         $pointDomain.recordPointLog($pointDomain.getUserName(),"buyMoneyPoint");  
    42. end  
    43.   
    44. rule buyNumsPoint  
    45.     // 当月购物次数5次以上,每五次赠送50分  
    46.     salience 97  
    47.     lock-on-active true  
    48.     when  
    49.         $pointDomain : PointDomain(buyNums >= 5)  
    50.     then  
    51.         $pointDomain.setPoint($pointDomain.getPoint()+$pointDomain.getBuyNums()/5 * 50);  
    52.         $pointDomain.recordPointLog($pointDomain.getUserName(),"buyNumsPoint");  
    53. end  
    54.   
    55. rule allFitPoint  
    56.     // 特别的,如果全部满足了要求,则额外奖励100分  
    57.     salience 96  
    58.     lock-on-active true  
    59.     when  
    60.         $pointDomain:PointDomain(buyNums >= 5 && billThisMonth >= 3 && buyMoney >= 100)  
    61.     then  
    62.         $pointDomain.setPoint($pointDomain.getPoint()+ 100);  
    63.         $pointDomain.recordPointLog($pointDomain.getUserName(),"allFitPoint");  
    64. end  

    subpoint.drl 与上一篇相同,请参见上一篇,此处省略篇幅略

    测试代码

    Test

    [java] view plain copy
     
     
    1. package com.drools.demo.point;  
    2.   
    3. import java.io.BufferedReader;  
    4. import java.io.IOException;  
    5. import java.io.InputStream;  
    6. import java.io.InputStreamReader;  
    7.   
    8.   
    9. public class Test {  
    10.   
    11.     /** 
    12.      * @param args 
    13.      * @throws IOException  
    14.      */  
    15.     public static void main(String[] args) throws IOException {  
    16.         PointRuleEngine pointRuleEngine = new PointRuleEngineImpl();  
    17.         boolean isStart = false;  
    18.         while(true){  
    19.             InputStream is = System.in;  
    20.             BufferedReader br = new BufferedReader(new InputStreamReader(is));  
    21.             String input = br.readLine();  
    22.               
    23.             if (null != input && "s".equals(input)){  
    24.                 System.out.println("初始化规则引擎...");  
    25.                 pointRuleEngine.initEngine();  
    26.                 isStart = true;  
    27.                 System.out.println("初始化规则引擎结束.");  
    28.             } else if ("e".equals(input)){  
    29.                 if (!isStart) {  
    30.                     System.out.println("需要输入s启动");  
    31.                 } else {  
    32.                     final PointDomain pointDomain = new PointDomain();  
    33.                     pointDomain.setUserName("hello kity");  
    34.                     pointDomain.setBackMondy(100d);  
    35.                     pointDomain.setBuyMoney(500d);  
    36.                     pointDomain.setBackNums(1);  
    37.                     pointDomain.setBuyNums(5);  
    38.                     pointDomain.setBillThisMonth(5);  
    39.                     pointDomain.setBirthDay(true);  
    40.                     pointDomain.setPoint(0l);  
    41.                       
    42.                     pointRuleEngine.executeRuleEngine(pointDomain);  
    43.                       
    44.                     System.out.println("执行完毕BillThisMonth:"+pointDomain.getBillThisMonth());  
    45.                     System.out.println("执行完毕BuyMoney:"+pointDomain.getBuyMoney());  
    46.                     System.out.println("执行完毕BuyNums:"+pointDomain.getBuyNums());  
    47.                       
    48.                     System.out.println("执行完毕规则引擎决定发送积分:"+pointDomain.getPoint());  
    49.                 }  
    50.             } else if ("r".equals(input)){  
    51.                 System.out.println("刷新规则文件...");  
    52.                 pointRuleEngine.refreshEnginRule();  
    53.                 isStart = true;  
    54.                 System.out.println("刷新规则文件结束.");  
    55.             } else if ("q".equals(input)) {  
    56.                 System.exit(0);  
    57.             }  
    58.         }  
    59.     }  
    60.   
    61. }  
     
     
  • 相关阅读:
    过去式和过去进行式
    现在式和现在进行式
    英文文法的最基本规则
    Vue 标签中的ref属性和refs
    APICloud
    小程序
    React 传值 组件传值 之间的关系
    css clip样式 属性功能及作用
    小程序点击预览 为什么显示空白
    小程序
  • 原文地址:https://www.cnblogs.com/duyinqiang/p/6171226.html
Copyright © 2020-2023  润新知