随着互联网应用的飞速发展,各种业务需求也应运而生,对于不断变更和革新的业务规则而言,项目的开发就很有必要把规则部分独立提取出来,此时Drools的价值就得到了体现。废话不多说,看一个简单的例子。
这里举一个手机话费的例子。
一、定义规则:
首先要分析自己的业务逻辑,根据业务而制定出不同的规则,这里我们假设有3个规则。
1、对于新开户的手机用户送20元话费。
2、在2014年10月到12期间充值的用户,不论金额多少充值满3次就赠送5元话费。
3、当月充值金额达到100以上,每达到一次赠送话费10元。
二、创建Fact对象:
分析这些规则,并把他们抽象成一个Fact对象。
package com.core.drools; import java.util.UUID; /** * EntityRule-Model * @author Candy * */ public class EntityRule { private String username; /** Whether for new account. */ private boolean account; /** The number of add. */ private int addtime; /** The sum of the current account. */ private double currentmoney; /** The totail amount added. */ private double totailaddmoney; /** * Record the serial number of the operation. * @param username * @param currentmoney */ public void getSerialnumber(String username,double currentmoney){ System.out.println("Account:"+username+" Balance:¥"+currentmoney); System.out.println("Serial Number:"+UUID.randomUUID().toString()); }
三、定义规则引擎:
业务和规则都整理清楚了我们就可以开始规则引擎的核心部分啦,这里我定义的是接口和实现类。
package com.core.drools; /** * RuleEngine-Interface * @author Candy * */ public interface RuleEngine { /** * Initializes the rules engine. */ public void init(); /** * Refresh the rules engine. */ public void refresh(); /** * Execute the rules engine. */ public void execute(final EntityRule entityRule); }
package com.core.drools; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.io.Reader; import java.util.ArrayList; import java.util.List; import org.drools.RuleBase; import org.drools.StatefulSession; import org.drools.compiler.DroolsParserException; import org.drools.compiler.PackageBuilder; import org.drools.rule.Package; import org.drools.spi.Activation; /** * RuleEngine-Implements * @author Candy * */ public class RuleEngineImpl implements RuleEngine{ private RuleBase ruleBase; /* * (non-Javadoc) * @see com.core.drools.RuleEngine#init() */ @Override public void init() { /** Sets the system time format. */ System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss"); /** Get the base factory. */ ruleBase =SingleRuleFactory.getRuleBase(); try { /** Get the rule files has bean read. */ PackageBuilder backageBuilder = getPackageBuilderFile(); /** Add the package to the 'RuleBase'. */ ruleBase.addPackages(backageBuilder.getPackages()); } catch (DroolsParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } } /* * (non-Javadoc) * @see com.core.drools.RuleEngine#refresh() */ @Override public void refresh() { ruleBase = SingleRuleFactory.getRuleBase(); Package[] packages = ruleBase.getPackages(); for(Package items :packages){ ruleBase.removePackage(items.getName()); } init(); } /* * (non-Javadoc) * @see com.core.drools.RuleEngine#execute(com.core.drools.EntityRule) */ @Override public void execute(final EntityRule entityRule) { if(null == ruleBase.getPackages() || 0 == ruleBase.getPackages().length) { return; } StatefulSession statefulSession = ruleBase.newStatefulSession(); statefulSession.insert(entityRule); statefulSession.fireAllRules(new org.drools.spi.AgendaFilter() { public boolean accept(Activation activation) { return !activation.getRule().getName().contains("_test"); } }); statefulSession.dispose(); } /** * Read the rule files. * @return * @throws Exception */ private PackageBuilder getPackageBuilderFile()throws Exception { /** Get the rule files. */ List<String> drlFilePath = getRuleFile(); /** Sets the file to 'readers'. */ List<Reader> readers = loadRuleFile(drlFilePath); /** To create the 'backageBuilder'. */ PackageBuilder backageBuilder = new PackageBuilder(); for (Reader r : readers) { backageBuilder.addPackageFromDrl(r); } /** Check if the script has a problem. */ if(backageBuilder.hasErrors()) { throw new Exception(backageBuilder.getErrors().toString()); } return backageBuilder; } /** * Load the script files. * @param drlFilePath * @return * @throws FileNotFoundException */ private List<Reader> loadRuleFile(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; } /** * Get the rule files. * @return */ private List<String> getRuleFile(){ List<String> drlFilePath = new ArrayList<String>(); String path="D:/utils/my/DroolsProject/src/com/core/drools/drools_rule.drl"; drlFilePath.add(path); return drlFilePath; } }
这里定义一个单例的RuleBase工厂类。
package com.core.drools; import org.drools.RuleBase; import org.drools.RuleBaseFactory; /** * To create a singleton factory. * @author Candy * */ public class SingleRuleFactory { private static RuleBase ruleBase; /** * Get the base factory. * @return */ public static RuleBase getRuleBase(){ return null != ruleBase ? ruleBase : RuleBaseFactory.newRuleBase(); } }
四、编写规则文件:
规则文件可以根据自己的业务需求定义多个文件,这里我只定义了一个。
package com.core.drools import com.core.drools.EntityRule; rule accountEntity //One salience 100 lock-on-active true when $entityRule : EntityRule(account == true) then System.out.println("The new account:Present ¥20.0"); $entityRule.setCurrentmoney($entityRule.getCurrentmoney()+20); $entityRule.getSerialnumber($entityRule.getUsername(),$entityRule.getCurrentmoney()); System.out.println("--------------------------------------------------"); end rule billEntity //two salience 99 lock-on-active true date-effective "2014-010-01 00:00:00" date-expires "2014-012-31 23:59:59" when $entityRule : EntityRule(addtime >= 3) then System.out.println("Prepaid phone number reach "+$entityRule.getAddtime() +" times:Present ¥"+$entityRule.getAddtime()/3*5); $entityRule.setCurrentmoney($entityRule.getCurrentmoney()+$entityRule.getAddtime()/3*5); $entityRule.getSerialnumber($entityRule.getUsername(),$entityRule.getCurrentmoney()); System.out.println("--------------------------------------------------"); end rule addMoney //Three salience 98 lock-on-active true when $entityRule : EntityRule(totailaddmoney >= 100) then System.out.println("The account for the month top-up totail amount is " +$entityRule.getTotailaddmoney()+":Present ¥"+(int)$entityRule.getTotailaddmoney()/100*10); $entityRule.setCurrentmoney($entityRule.getCurrentmoney() +(int)$entityRule.getTotailaddmoney()/100 * 10); $entityRule.getSerialnumber($entityRule.getUsername(),$entityRule.getCurrentmoney()); end
五、测试引擎:
package com.test; import java.io.IOException; import com.core.drools.EntityRule; import com.core.drools.RuleEngine; import com.core.drools.RuleEngineImpl; /** * Test Drools * @author Candy * */ public class DroolsTest { public static void main(String[] args) throws IOException { RuleEngine engineImpl =new RuleEngineImpl(); engineImpl.init(); final EntityRule entityRule= new EntityRule(); entityRule.setCurrentmoney(350d); entityRule.setUsername("Candy"); entityRule.setAccount(true); entityRule.setTotailaddmoney(350d); entityRule.setAddtime(7); engineImpl.execute(entityRule); } }
六、测试结果:
The new account:Present ¥20.0
Account:Candy Balance:¥370.0
Serial Number:0fd98593-caa2-444d-a4ff-b4001cfb3260
------------------------------------------------------------------------------
Prepaid phone number reach 7 times:Present ¥10
Account:Candy Balance:¥380.0
Serial Number:a118b211-c28e-4035-aa60-2f417f62b2f3
------------------------------------------------------------------------------
The account for the month top-up totail amount is 350.0: Present ¥30
Account:Candy Balance:¥410.0
Serial Number:2bfc02c2-267f-47a2-9cda-5a4196e2b7cf