因項目須要,看了下drools規則引擎。寫了一個比較簡單的drools的drl規則和決策表實現的例子。java
規則說明:api
網絡商城要舉辦活動(獎勵額外積分),網絡
訂單原價金額在session
100如下, 不加分 maven
100-500 加100分 函數
500-1000 加500分 oop
1000 以上 加1000分單元測試
1.創建最基本的Drools項目結構並引入必須的類庫。(這裏採用junit來執行單元測試)。建立一個Java Project,創建maven形式的源碼包。測試
2.定義實體類Order.javaui
1 import java.util.Date; 2 3 public class Order { 4 private Date bookingDate;// 下單日期 5 6 private int amout;// 訂單原價金額 7 8 private User user;// 下單人 9 10 private int score;//積分 11 12 public Order(Date bookingDate,int amout, User user, int score){ 13 this.bookingDate = bookingDate; 14 this.amout = amout; 15 this.user = user; 16 this.score = score; 17 } 18 19 public Order(){ 20 } 21 22 //省略get、set方法53 54 }
3.定義實體User.java
public class User { private String name;// 姓名 private int level;// 用戶級別 public User(){ } public User(String name, int level){ this.name = name; this.level = level; } //省略get、set方法 }
4.編寫規則文件point-rules.drl
package drools import com.wang.drools.point.Order import com.wang.drools.point.User rule "zero" no-loop true //只檢查一次 lock-on-active true salience 9 //值越大 ,優先級越高 when //購物金額100如下不加分 $s : Order(amout <= 100); then $s.setScore(0); update($s); end rule "add100" no-loop true //只檢查一次 lock-on-active true salience 8 //值越大 ,優先級越高 when //購物金額100以上500如下加100積分 $s : Order(amout > 100 && amout <= 500); then $s.setScore(100); update($s); end rule "add500" no-loop true //只檢查一次 lock-on-active true salience 6 //值越大 ,優先級越高 when //購物金額500以上1000如下加500積分 $s : Order(amout > 500 && amout <= 1000); then $s.setScore(500); update($s); end rule "add1000" no-loop true //只檢查一次 lock-on-active true salience 5 //值越大 ,優先級越高 when //購物金額1000以上加1000積分 $s : Order(amout > 1000); then $s.setScore(1000); update($s); end
說明:rule表示規則的開始,salience表示規則的優先級,當有多條規則同時存在是,優先級越高的越先被匹配執行。lock-on-active表示執行過一次以後就再也不執行,防止後續的條件執行過程當中改變變量的值致使從新知足該規則以後再次執行對應的操做。When表示匹配的規則,then表示匹配規則以後執行的動做。
5.測試drl規則TestPoint.java
import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.kie.api.io.ResourceType; import org.kie.internal.KnowledgeBase; import org.kie.internal.KnowledgeBaseFactory; import org.kie.internal.builder.KnowledgeBuilder; import org.kie.internal.builder.KnowledgeBuilderErrors; import org.kie.internal.builder.KnowledgeBuilderFactory; import org.kie.internal.definition.KnowledgePackage; import org.kie.internal.io.ResourceFactory; import org.kie.internal.runtime.StatefulKnowledgeSession; @SuppressWarnings("deprecation") public class TestPoint { /** * 計算額外積分金額 規則以下: 訂單原價金額 * 100如下, 不加分 * 100-500 加100分 * 500-1000 加500分 * 1000 以上 加1000分 * * @param args * @throws Exception */ public static void main(String[] args) throws Exception { KnowledgeBuilder builder = KnowledgeBuilderFactory.newKnowledgeBuilder(); builder.add(ResourceFactory.newClassPathResource("point/point-rules.drl"), ResourceType.DRL); if (builder.hasErrors()) { System.out.println("規則中存在錯誤,錯誤消息以下:"); KnowledgeBuilderErrors kbuidlerErrors = builder.getErrors(); for (Iterator<?> iter = kbuidlerErrors.iterator(); iter.hasNext();) { System.out.println(iter.next()); } return; } Collection<KnowledgePackage> packages = builder.getKnowledgePackages(); KnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase(); kbase.addKnowledgePackages(packages); StatefulKnowledgeSession session = kbase.newStatefulKnowledgeSession(); List<Order> orderList = getInitData(); for (int i = 0; i < orderList.size(); i++) { Order o = orderList.get(i); session.insert(o); session.fireAllRules(); // 執行完規則後, 執行相關的邏輯 addScore(o); } session.dispose(); } private static void addScore(Order o){ System.out.println("用戶" + o.getUser().getName() + "享受額外增長積分: " + o.getScore()); } private static List<Order> getInitData() throws Exception { List<Order> orderList = new ArrayList<Order>(); DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); { Order order = new Order(); order.setAmout(80); order.setBookingDate(df.parse("2015-07-01")); User user = new User(); user.setLevel(1); user.setName("Name1"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(200); order.setBookingDate(df.parse("2015-07-02")); User user = new User(); user.setLevel(2); user.setName("Name2"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(800); order.setBookingDate(df.parse("2015-07-03")); User user = new User(); user.setLevel(3); user.setName("Name3"); order.setUser(user); orderList.add(order); } { Order order = new Order(); order.setAmout(1500); order.setBookingDate(df.parse("2015-07-04")); User user = new User(); user.setLevel(4); user.setName("Name4"); order.setUser(user); orderList.add(order); } return orderList; } }
6.創建等同於drl規則文件的xsl文件 point.xsl
說明:
7.在META-INF文件夾下的kmodule.xml文件中配置ksession信息。
說明:1.packages = 「xxxx」 配置xsl所在包的名稱
2.<ksession name="ksession-calXSL"/> 配置ksession的名稱(方便在項目中調用)
8.測試xsl決策表文件正確性 TestPointXML.java
import java.util.Date; import org.kie.api.KieServices; import org.kie.api.runtime.KieContainer; import org.kie.api.runtime.KieSession; /*** * 使用決策表實現規則引擎 * * @author wyx * */ public class TestPointXSL { public static void main(String[] args) { KieServices ks = KieServices.Factory.get(); KieContainer kc = ks.getKieClasspathContainer(); KieSession kSession = kc.newKieSession("ksession-pointXML"); User user = new User(); user.setName("張學友"); user.setLevel(1); Order order = new Order(new Date(),100,user,0); kSession.insert(order); kSession.fireAllRules(); kSession.dispose(); System.out.println(order.getScore()); } }
9.有個很方便的文件解析能夠幫助咱們很快知道xsl文件是否書寫正確 GenerationRules.java
直接能將xsl文件解析成drl規則打印在控制檯,方便查看、修改
import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import org.drools.decisiontable.InputType; import org.drools.decisiontable.SpreadsheetCompiler; import org.junit.Test; /*** * * 解析決策樹文件 * * @author wyx * */ public class GenerationRules { @Test public void compile() throws FileNotFoundException { File file = new File( "F:\\icore\\drools\\src\\main\\resources\\pointXML\\point.xls"); InputStream is = new FileInputStream(file); SpreadsheetCompiler converter = new SpreadsheetCompiler(); String drl = converter.compile(is, InputType.XLS); System.out.println("\n\n" + drl); } }
關鍵字 |
說明 |
是否必須 |
RuleSet |
在這個單元的右邊單元中包含ruleset的名稱 |
必須,只能有一個(若是爲空則使用默認值) |
Sequential |
右邊的單元能夠是true或false,若是是true則確保規則按照從表格的上面到下面的順序執行(規則觸發是從上朝下,若是是false就是亂序) |
可選 |
Import |
要導入規則庫中的類的列表(逗號隔開) |
可選 |
Variables |
緊跟在右邊的單元格包含global聲明。格式是類型跟着變量名(全局變量定義,多個用逗號隔開) |
可選 |
Functions |
緊跟在右邊的單元格包含能夠用在規則代碼段中的函數聲明。Drools支持在DRL中定義函數,容許邏輯在規則中嵌入 |
可選 |
RuleTable |
一個以RuleTable開頭的單元格表明一個規則 表定義的開始。實際的規則表從下一行開始。規則表的讀取遵循從左到右,從上到下的順序,知道出現空行 |
至少一個,若是有多個,所有加入到同一個RuleSet中 |
CONDITION |
說明該列用於規則的條件表達式 |
每一個規則表至少一個 |
ACTION |
說明該列用於規則表的推論部分 |
每一個規則表至少一個 |
PRIORITY |
說明該列值將用來設定改行規則的’salience’值,覆蓋‘Sequential’標記 |
可選 |
NAME |
說明該列規則的名字將使用該列所指定名字 |
可選 |
UNLOOP |
若是單元格這一列上有值,則no-loop屬性被設置 |
可選 |
Worksheet |
默認只有第一個工做表被認爲是決策表 |
N/A |