Spring Boot + rule engine Drools, strong!

Click on “Yao Dao Source Code” above and select “Set as Star”

Does she care about the front wave or the back wave?

A wave that can wave is a good wave!

Update articles every day at 10:33, lose a million bits of hair every day…

Source code boutique column

  • Original | Java 2021 Super God Road, very liver~

  • An open source project with detailed annotations in Chinese

  • RPC framework Dubbo source code analysis

  • Network application framework Netty source code analysis

  • Message middleware RocketMQ source code analysis

  • Database middleware Sharding-JDBC and MyCAT source code analysis

  • Job Scheduling Middleware Elastic-Job Source Code Analysis

  • Distributed transaction middleware TCC-Transaction source code analysis

  • Eureka and Hystrix source code analysis

  • Java Concurrency Source Code

Source: JAVA Risun

  • Introduce dependencies

  • Drools configuration class

  • Add business model

  • Define drools rules

  • Add Service layer

  • Add Controller

  • have a test

  • Summarize

bf3684510e8bc771384535529ab979c5.jpeg

Now there is such a demand, online shopping needs to calculate product discounts according to different rules, such as 5% discount for VIP customers, 10% discount for purchases exceeding 1,000 yuan, etc., and these rules may change at any time, or even increase new rules. Faced with this demand, how do you realize it? Could it be that when the calculation rules change, the business code must be modified, retested, and launched.

In fact, we can implement it through a rule engine. Drools is an open source business rule engine that can be easily integrated with spring boot applications. In this article, we will use Drools to realize the above-mentioned requirements.

Introducing dependencies

We create a spring boot application and add drools-related dependencies to the pom, as follows:

<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>

Background management system + user applet based on Spring Boot + MyBatis Plus + Vue & amp; Element, supports RBAC dynamic permissions, multi-tenancy, data permissions, workflow, three-party login, payment, SMS, mall and other functions

  • Project address: https://github.com/YunaiV/ruoyi-vue-pro

  • Video tutorial: https://doc.iocoder.cn/video/

Drools configuration class

Create a configuration java class called DroolsConfig.

@Configuration
public class DroolsConfig {
    // specify the path to the rule file
    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;
    }
}
  • A Spring Bean of KieContainer is defined, and KieContainer is used to load the application under the /resources folder rule files to build the rules engine.

  • Creates a KieFileSystem instance and configures the rule engine and loads the rule’s DRL file from the application’s resource directory.

  • Use KieBuilder instance to build drools module. We can use KieServive singleton instance to create KieBuilder instance.

  • Finally, use KieService to create a KieContainer and configure it as a spring bean.

Background management system + user applet based on Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & amp; Element, supporting RBAC dynamic permissions, multi-tenancy, data permissions, workflow, three-party login, payment, SMS, mall and other functions

  • Project address: https://github.com/YunaiV/yudao-cloud

  • Video tutorial: https://doc.iocoder.cn/video/

Add business model

Create an order object OrderRequest. The fields in this class are then sent as input information to the defined drools rules to calculate the discount amount for a given customer order.

@Getter
@Setter
public class OrderRequest {
    /**
     * client number
     */
    private String customerNumber;
    /**
     * age
     */
    private Integer age;
    /**
     * order amount
     */
    private Integer amount;
    /**
     * Customer type
     */
    private CustomerType customerType;
}

In addition, define an enumeration of customer type CustomerType from which the rules engine will calculate the customer order discount percentage, as shown below.

public enum CustomerType {
    LOYAL, NEW, DISSATISFIED;

    public String getValue() {
        return this.toString();
    }
}

Finally, create an order discount class OrderDiscount to represent the calculated final discount, as shown below.

@Getter
@Setter
public class OrderDiscount {

    /**
     * Discount
     */
    private Integer discount = 0;
}

We will return the calculated discount using the above response object.

Define drools rules

The previous DroolsConfig class specifies the drools rule directory, now we add customer in the /src/main/resources/rules directory -discount.drl file, which defines the corresponding rules.

e907c0a331cdbce6f46c9fe145ee5d93.png

Although this drl file is not a java file, it is still easy to understand.

  • We use a global parameter called orderDiscount that can be shared between multiple rules. Pay attention to Gongzhong account: code ape technology column, reply keywords: 1111 Get Ali’s internal java performance tuning manual!

  • A drl file can contain one or more rules. We can use the mvel syntax to specify rules. Additionally, each rule is described using the rule keyword.

  • Each rule uses when-then syntax to define the conditions of the rule.

  • Based on the input value of the order request, we are adding a discount to the result. Each rule adds an additional discount to the global result variable if the rule expression matches.

The complete rule source code is as follows:

import com.alvin.drools.model.OrderRequest;
import com.alvin.drools.model.CustomerType;
global com.alvin.drools.model.OrderDiscount orderDiscount;

dialect "mvel"

// Rule 1: Judging by age
rule "Age based discount"
    when
        // When the customer's age is under 20 or over 50
        OrderRequest(age < 20 || age > 50)
    then
        // add 10% discount
        System.out.println("===========Adding 10% discount for Kids/ senior customer===============");
        orderDiscount.setDiscount(orderDiscount.getDiscount() + 10);
end

// Rule 2: Rules based on customer type
rule "Customer type based discount - Loyal customer"
    when
        // When the customer type is LOYAL
        OrderRequest(customerType. getValue == "LOYAL")
    then
        // add 5% discount
        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

Add Service layer

Create a service class called OrderDiscountService, as follows:.

@Service
public class OrderDiscountService {

    @Autowired
    private KieContainer kieContainer;

    public OrderDiscount getDiscount(OrderRequest orderRequest) {
        OrderDiscount orderDiscount = new OrderDiscount();
        // start the session
        KieSession kieSession = kieContainer. newKieSession();
        // set discount object
        kieSession.setGlobal("orderDiscount", orderDiscount);
        // set the order object
        kieSession.insert(orderRequest);
        // trigger rule
        kieSession.fireAllRules();
        // abort the session
        kieSession.dispose();
        return order Discount;
    }
}
  • Inject a KieContainer instance and create a KieSession instance.

  • A global parameter of type OrderDiscount is set, which will save the rule execution result.

  • Use the insert() method to pass the request object to the drl file.

  • Call the fireAllRules() method to fire all rules.

  • Finally, terminate the session by calling the dispose() method of KieSession.

Add Controller

Create a Controller class named OrderDiscountController, the specific code is as follows:

@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);
    }
}

Test it

Run the spring boot application and access the REST API endpoint by sending the customer order request JSON.

  • For LOYAL customer type with age < 20 and amount > 1000, we should get discount of 20% according to the rules we defined.

d43e8d1e23fef5892595f06c1b1bc03d.png
e24efbdd0fb1b023a02e786fc8cf3444.png

Summary

We have simply implemented such a discount business through the drools rule engine. Now the product manager asks you to add a rule, for example, if the address is Hangzhou plus 10% discount, you can directly change the drl file. Others Just spend time fishing, haha~~. You can go to the official website to explore more about the usage of drools.

Welcome to join my knowledge planet, discuss architecture and exchange source code together. How to join, Long press the QR code below:

28509a516825619f03decb5c25b76f41.png

The source code has been updated on Knowledge Planet and the analysis is as follows:

8e75bfe033346aceb811ee159523ac2f.jpeg

e0d6e78069e11b2e35b39ba446054369.jpeg

f8d7044b2c0857ed3d2a2b519a040d2a.jpeg

\

The recently updated series “Introduction to Taro SpringBoot 2.X” has more than 101 articles, covering MyBatis, Redis, MongoDB, ES, sub-database and sub-table, read-write separation, SpringMVC, Webflux, permissions, WebSocket, Dubbo, RabbitMQ, RocketMQ , Kafka, performance testing, etc.

Provides a SpringBoot example with nearly 3W lines of code, and an e-commerce microservice project with more than 4W lines of code.

How to get it: Click “Looking“, follow the official account and reply to 666 to receive, more content will be provided one after another.

If the article is helpful, please read it and forward it.
Thank you for your support (*^__^*)