随着網際網路應用的飛速發展,各種業務需求也應運而生,對于不斷變更和革新的業務規則而言,項目的開發就很有必要把規則部分獨立提取出來,此時Drools的價值就得到了展現。廢話不多說,看一個簡單的例子。
這裡舉一個手機話費的例子。
一、定義規則:
首先要分析自己的業務邏輯,根據業務而制定出不同的規則,這裡我們假設有3個規則。
1、對于新開戶的手機使用者送20元話費。
2、在2014年10月到12期間充值的使用者,不論金額多少充值滿3次就贈送5元話費。
3、當月充值金額達到100以上,每達到一次贈送話費10元。
二、建立Fact對象:
分析這些規則,并把他們抽象成一個Fact對象。
package com.core.drools;
import java.util.UUID;
public class EntityRule {
private String username;
private boolean account;
private int addtime;
private double currentmoney;
private double totailaddmoney;
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;
public interface RuleEngine {
public void init();
public void refresh();
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;
public class RuleEngineImpl implements RuleEngine{
private RuleBase ruleBase;
@Override
public void init() {
System.setProperty("drools.dateformat", "yyyy-MM-dd HH:mm:ss");
ruleBase =SingleRuleFactory.getRuleBase();
try {
PackageBuilder backageBuilder = getPackageBuilderFile();
ruleBase.addPackages(backageBuilder.getPackages());
} catch (DroolsParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void refresh() {
ruleBase = SingleRuleFactory.getRuleBase();
Package[] packages = ruleBase.getPackages();
for(Package items :packages){
ruleBase.removePackage(items.getName());
}
init();
}
@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();
}
private PackageBuilder getPackageBuilderFile()throws Exception {
List drlFilePath = getRuleFile();
List readers = loadRuleFile(drlFilePath);
PackageBuilder backageBuilder = new PackageBuilder();
for (Reader r : readers) {
backageBuilder.addPackageFromDrl(r);
}
if(backageBuilder.hasErrors()) {
throw new Exception(backageBuilder.getErrors().toString());
}
return backageBuilder;
}
private List loadRuleFile(List drlFilePath)
throws FileNotFoundException {
if (null == drlFilePath || 0 == drlFilePath.size()) {
return null;
}
List readers = new ArrayList();
for (String ruleFilePath : drlFilePath) {
readers.add(new FileReader(new File(ruleFilePath)));
}
return readers;
}
private List getRuleFile(){
List drlFilePath = new ArrayList();
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;
public class SingleRuleFactory {
private static RuleBase ruleBase;
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;
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