Implement Dynamic Discount Rules in Spring Boot with Drools
This guide shows how to integrate the Drools rule engine into a Spring Boot application to calculate e‑commerce discounts dynamically, covering Maven dependencies, configuration, model definitions, DRL rule creation, service and controller layers, and a simple test scenario demonstrating rule‑driven discount computation.
Introduction
When an e‑commerce system needs to calculate discounts based on flexible business rules—such as extra 5 % for VIP customers or an additional 10 % for orders over 1000 CNY—hard‑coding the logic would require code changes, retesting and redeployment each time a rule changes. Using a rule engine like Drools allows the rules to be externalised and modified without touching the business code.
Adding Maven Dependencies
Create a Spring Boot project and add the following Drools dependencies to
pom.xml:
<code><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></code>Drools Configuration Class
Create a
DroolsConfigclass that registers a
KieContainerbean and loads the DRL files from
src/main/resources/rules:
<code>@Configuration
public class DroolsConfig {
// 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();
return kieServices.newKieContainer(kieModule.getReleaseId());
}
}</code>Defines a Spring bean of type
KieContainerthat loads the DRL file from the classpath.
Creates a
KieFileSystemto write the rule file.
Builds the Drools module with
KieBuilder.
Exposes the container as a Spring bean.
Business Model Classes
Define the request object, an enum for customer type, and a DTO for the discount result.
<code>@Getter @Setter
public class OrderRequest {
private String customerNumber;
private Integer age;
private Integer amount;
private CustomerType customerType;
}</code> <code>public enum CustomerType {
LOYAL, NEW, DISSATISFIED;
public String getValue() { return this.toString(); }
}</code> <code>@Getter @Setter
public class OrderDiscount {
private Integer discount = 0;
}</code>Drools Rules (customer-discount.drl)
The DRL file contains four rules that adjust a global
orderDiscountobject.
<code>import com.alvin.drools.model.OrderRequest;
import com.alvin.drools.model.CustomerType;
global com.alvin.drools.model.OrderDiscount orderDiscount;
dialect "mvel"
// Rule 1: Age based discount
rule "Age based discount"
when
OrderRequest(age < 20 || age > 50)
then
System.out.println("==========Adding 10% discount for Kids/ senior customer=============");
orderDiscount.setDiscount(orderDiscount.getDiscount() + 10);
end
// Rule 2: Loyal customer discount
rule "Customer type based discount - Loyal customer"
when
OrderRequest(customerType.getValue == "LOYAL")
then
System.out.println("==========Adding 5% discount for LOYAL customer=============");
orderDiscount.setDiscount(orderDiscount.getDiscount() + 5);
end
// Rule 3: Other customer types
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 4: Amount based discount
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</code>Service Layer
The
OrderDiscountServiceobtains a
KieSession, injects the global discount object, inserts the request, fires all rules and returns the calculated discount.
<code>@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;
}
}</code>Controller
Expose a REST endpoint that receives an
OrderRequestJSON and returns the calculated
OrderDiscount.
<code>@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);
}
}</code>Testing
Run the Spring Boot application and POST a JSON payload such as:
<code>{
"customerNumber": "C001",
"age": 18,
"amount": 1200,
"customerType": "LOYAL"
}</code>For a loyal customer younger than 20 with an order amount greater than 1000, the rules above produce a total discount of 20 % (10 % age discount + 5 % loyal‑customer discount + 5 % amount discount).
Conclusion
By integrating Drools with Spring Boot we can externalise discount logic into a DRL file, allowing business users or product managers to add or modify rules—such as a new rule for customers in a specific city—without changing Java code, thus speeding up iteration and reducing deployment risk.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.