現在有這麼個需求,網上購物,需要根據不同的規則計算商品折扣,比如VIP客戶增加5%的折扣,購買金額超過1000元的增加10%的折扣等,而且這些規則可能隨時發生變化,甚至增加新的規則。面對這個需求,你該怎麼實現呢?難道是計算規則一變,就要修改業務程式碼,重新測試,上線嗎。
其實,我們可以通過規則引擎來實現,Drools 就是一個開源的業務規則引擎,可以很容易地與 spring boot 應用程式整合,那本文就用Drools來實現一下上面說的需求吧。
歡迎關注個人公眾號【JAVA旭陽】交流溝通
我們建立一個spring boot應用程式,pom中新增drools相關的依賴,如下:
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-core</artifactId>
<version>7.59.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-compiler</artifactId>
<version>7.59.0.Final</version>
</dependency>
<dependency>
<groupId>org.drools</groupId>
<artifactId>drools-decisiontables</artifactId>
<version>7.59.0.Final</version>
</dependency>
建立一個名為DroolsConfig
的設定 java 類。
@Configuration
public class DroolsConfig {
// 制定規則檔案的路徑
private static final String RULES_CUSTOMER_RULES_DRL = "rules/customer-discount.drl";
private static final KieServices kieServices = KieServices.Factory.get();
@Bean
public KieContainer kieContainer() {
KieFileSystem kieFileSystem = kieServices.newKieFileSystem();
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_CUSTOMER_RULES_DRL));
KieBuilder kb = kieServices.newKieBuilder(kieFileSystem);
kb.buildAll();
KieModule kieModule = kb.getKieModule();
KieContainer kieContainer = kieServices.newKieContainer(kieModule.getReleaseId());
return kieContainer;
}
}
KieContainer
的Spring Bean
,KieContainer
用於通過載入應用程式的/resources
資料夾下的規則檔案來構建規則引擎。KieFileSystem
範例並設定規則引擎並從應用程式的資源目錄載入規則的 DRL
檔案。KieBuilder
範例來構建 drools
模組。我們可以使用KieSerive單例範例來建立 KieBuilder
範例。KieService
建立一個 KieContainer
並將其設定為 spring bean
。建立一個訂單物件OrderRequest
,這個類中的欄位後續回作為輸入資訊傳送給定義的drools
規則中,用來計算給定客戶訂單的折扣金額。
@Getter
@Setter
public class OrderRequest {
/**
* 客戶號
*/
private String customerNumber;
/**
* 年齡
*/
private Integer age;
/**
* 訂單金額
*/
private Integer amount;
/**
* 客戶型別
*/
private CustomerType customerType;
}
此外,定義一個客戶型別CustomerType
的列舉,規則引擎會根據該值計算客戶訂單折扣百分比,如下所示。
public enum CustomerType {
LOYAL, NEW, DISSATISFIED;
public String getValue() {
return this.toString();
}
}
最後,建立一個訂單折扣類 OrderDiscount
,用來表示計算得到的最終的折扣,如下所示。
@Getter
@Setter
public class OrderDiscount {
/**
* 折扣
*/
private Integer discount = 0;
}
我們將使用上述響應物件返回計算出的折扣。
前面的DroolsConfig
類中指定drools
規則的目錄,現在我們在/src/main/resources/rules
目錄下新增customer-discount.drl
檔案,在裡面定義對應的規則。
這個drl
檔案雖然不是java檔案,但還是很容易看懂的。
orderDiscount
的全域性引數,可以在多個規則之間共用。drl
檔案可以包含一個或多個規則。我們可以使用mvel
語法來指定規則。此外,每個規則使用rule
關鍵字進行描述。when-then
語法來定義規則的條件。完整的規則原始碼如下:
import com.alvin.drools.model.OrderRequest;
import com.alvin.drools.model.CustomerType;
global com.alvin.drools.model.OrderDiscount orderDiscount;
dialect "mvel"
// 規則1: 根據年齡判斷
rule "Age based discount"
when
// 當客戶年齡在20歲以下或者50歲以上
OrderRequest(age < 20 || age > 50)
then
// 則新增10%的折扣
System.out.println("==========Adding 10% discount for Kids/ senior customer=============");
orderDiscount.setDiscount(orderDiscount.getDiscount() + 10);
end
// 規則2: 根據客戶型別的規則
rule "Customer type based discount - Loyal customer"
when
// 當客戶型別是LOYAL
OrderRequest(customerType.getValue == "LOYAL")
then
// 則增加5%的折扣
System.out.println("==========Adding 5% discount for LOYAL customer=============");
orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end
rule "Customer type based discount - others"
when
OrderRequest(customerType.getValue != "LOYAL")
then
System.out.println("==========Adding 3% discount for NEW or DISSATISFIED customer=============");
orderDiscount.setDiscount(orderDiscount.getDiscount() + 3);
end
rule "Amount based discount"
when
OrderRequest(amount > 1000L)
then
System.out.println("==========Adding 5% discount for amount more than 1000$=============");
orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end
建立一個名為OrderDiscountService
的服務類,如下:。
@Service
public class OrderDiscountService {
@Autowired
private KieContainer kieContainer;
public OrderDiscount getDiscount(OrderRequest orderRequest) {
OrderDiscount orderDiscount = new OrderDiscount();
// 開啟對談
KieSession kieSession = kieContainer.newKieSession();
// 設定折扣物件
kieSession.setGlobal("orderDiscount", orderDiscount);
// 設定訂單物件
kieSession.insert(orderRequest);
// 觸發規則
kieSession.fireAllRules();
// 中止對談
kieSession.dispose();
return orderDiscount;
}
}
KieContainer
範例並建立一個KieSession
範例。OrderDiscount
型別的全域性引數,它將儲存規則執行結果。insert()
方法將請求物件傳遞給 drl
檔案。fireAllRules()
方法觸發所有規則。KieSession
的dispose()
方法終止對談。建立一個名為OrderDiscountController
的Controller
類,具體程式碼如下:
@RestController
public class OrderDiscountController {
@Autowired
private OrderDiscountService orderDiscountService;
@PostMapping("/get-discount")
public ResponseEntity<OrderDiscount> getDiscount(@RequestBody OrderRequest orderRequest) {
OrderDiscount discount = orderDiscountService.getDiscount(orderRequest);
return new ResponseEntity<>(discount, HttpStatus.OK);
}
}
執行 spring boot
應用程式並通過傳送客戶訂單請求 JSON 來存取 REST API 端點。
LOYAL
客戶型別,我們應該根據我們定義的規則獲得 20%
的折扣。我們通過drools
規則引擎簡單實現了這樣一個折扣的業務,現在產品經理說要你加一條規則,比如地址是杭州的折扣加10%,你就直接改這個drl檔案,其他時間用來摸魚就好了,哈哈~~。更多關於drools
的用法大家可以去官網探索。
歡迎關注個人公眾號【JAVA旭陽】交流溝通
本文來自部落格園,作者:JAVA旭陽,轉載請註明原文連結:https://www.cnblogs.com/alvinscript/p/17205498.html