Easy Rules是一个轻量级的Java规则引擎,它允许开发者将业务规则从代码中解耦出来,使规则的管理和执行更加灵活。
现在让我们一起利用Spring Boot结合Easy Rules和MyBatis技术栈,可以实现一个高效且易于维护的优惠券系统例子。
1. 添加依赖项
在 pom.xml
文件中确保包含以下依赖项:
<dependencies><!-- Spring Boot Starter Web --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- MyBatis Framework --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>3.0.1</version></dependency><!-- MySQL Connector --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!-- Easy Rules Core --><dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-core</artifactId><version>4.4.0</version></dependency><!-- Easy Rules Support for Spring --><dependency><groupId>org.jeasy</groupId><artifactId>easy-rules-support-spring</artifactId><version>4.4.0</version></dependency><!-- Lombok (Optional, for reducing boilerplate code) --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- Test Dependencies --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency>
</dependencies>
2. 配置 MyBatis 和数据库连接
在 application.properties
文件中配置数据库连接信息和 MyBatis 设置:
# 数据库配置
spring.datasource.url=jdbc:mysql://localhost:3306/coupon_system?useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver# MyBatis 配置
mybatis.type-aliases-package=com.example.couponsystemdb.model
mybatis.mapper-locations=classpath*:mapper/*.xml
3. 定义业务实体类
我们需要定义一些业务实体类来表示购物车、商品和优惠券信息。
ShoppingCart.java
package com.example.couponsystemdb.model;import lombok.Data;
import java.util.ArrayList;
import java.util.List;@Data
publicclass ShoppingCart {privatedouble totalPrice = 0; // 购物车总价格privatefinal List<Item> items = new ArrayList<>(); // 商品列表/*** 向购物车添加商品* @param item 商品对象*/public void addItem(Item item) {items.add(item);totalPrice += item.getPrice();}/*** 应用折扣* @param discount 折扣比例(例如 0.10 表示 10% 折扣)*/public void applyDiscount(double discount) {totalPrice -= totalPrice * discount;}
}
Item.java
package com.example.couponsystemdb.model;import lombok.Data;@Data
publicclass Item {private String name; // 商品名称private String category; // 商品类别privatedouble price; // 商品价格/*** 构造函数* @param name 商品名称* @param category 商品类别* @param price 商品价格*/public Item(String name, String category, double price) {this.name = name;this.category = category;this.price = price;}
}
CouponRule.java
这个类用于从数据库加载规则信息。
package com.example.couponsystemdb.model;import lombok.Data;@Data
public class CouponRule {private Long id; // 规则IDprivate String ruleName; // 规则名称private String description; // 规则描述private String conditionExpression; // 条件表达式private String actionExpression; // 动作表达式
}
4. 创建数据库表和初始化数据
创建一个名为 coupon_system
的数据库,并在其中创建 coupon_rule
表。然后插入一些初始规则数据。
SQL 脚本
CREATE DATABASE coupon_system;USE coupon_system;CREATETABLE coupon_rule (idBIGINT AUTO_INCREMENT PRIMARY KEY,rule_name VARCHAR(255) NOTNULL,description TEXT,condition_expression TEXTNOTNULL,action_expression TEXTNOTNULL
);INSERTINTO coupon_rule (rule_name, description, condition_expression, action_expression) VALUES
('Total Price Discount Rule', 'Offers a 10% discount if the total price exceeds 1000',
'cart.getTotalPrice() > 1000',
'cart.applyDiscount(0.10); System.out.println("Applied 10% discount for total price exceeding 1000");'),('Category Discount Rule', 'Offers an additional 5% discount on Electronics category',
'cart.getItems().stream().anyMatch(item -> item.getCategory().equals("Electronics"))',
'cart.applyDiscount(0.05); System.out.println("Applied 5% discount for purchasing electronics");');
5. 定义动态规则
我们将使用 Easy Rules 的 DynamicRule
类来从数据库加载规则并执行。
DynamicCouponRule.java
package com.example.couponsystemdb.rule;import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.core.DynamicRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
publicclass DynamicCouponRule extends DynamicRule {@Autowiredprivate CouponService couponService;/*** 评估条件* @param facts 事实对象* @return 是否满足条件* @throws Exception 异常*/@Override@Conditionpublic boolean evaluate(Facts facts) throws Exception {returnsuper.evaluate(facts);}/*** 执行动作* @param facts 事实对象* @throws Exception 异常*/@Override@Actionpublic void execute(Facts facts) throws Exception {super.execute(facts);}/*** 从数据库设置规则* @param ruleId 规则ID*/public void setRuleFromDatabase(Long ruleId) {CouponRule couponRule = couponService.getCouponRuleById(ruleId);setName(couponRule.getRuleName());setDescription(couponRule.getDescription());setConditionExpression(couponRule.getConditionExpression());setActionExpression(couponRule.getActionExpression());}
}
6. 配置规则引擎
我们需要配置规则引擎并将规则注册到 Spring 上下文中。
EasyRulesConfig.java
package com.example.couponsystemdb.config;import org.jeasy.rules.api.RulesEngine;
import org.jeasy.rules.core.DefaultRulesEngine;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
publicclass EasyRulesConfig {/*** 配置规则引擎* @return 规则引擎实例*/@Beanpublic RulesEngine rulesEngine() {returnnew DefaultRulesEngine();}
}
7. 创建 Service 层
创建一个服务层来处理与数据库的交互。
CouponService.java
package com.example.couponsystemdb.service;import com.example.couponsystemdb.mapper.CouponRuleMapper;
import com.example.couponsystemdb.model.CouponRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
publicclass CouponService {@Autowiredprivate CouponRuleMapper couponRuleMapper;/*** 根据规则ID获取规则* @param id 规则ID* @return 规则对象*/public CouponRule getCouponRuleById(Long id) {return couponRuleMapper.selectById(id);}
}
8. 创建 Mapper 接口
使用 MyBatis 映射器接口来操作数据库。
CouponRuleMapper.java
package com.example.couponsystemdb.mapper;import com.example.couponsystemdb.model.CouponRule;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper
public interface CouponRuleMapper {/*** 根据规则ID查询规则* @param id 规则ID* @return 规则对象*/@Select("SELECT * FROM coupon_rule WHERE id = #{id}")CouponRule selectById(Long id);
}
9. 编写主应用程序类
最后,在主应用程序类中使用规则引擎来处理购物车中的商品。
CouponSystemApplication.java
package com.example.couponsystemdb;import com.example.couponsystemdb.model.ShoppingCart;
import com.example.couponsystemdb.model.Item;
import com.example.couponsystemdb.rule.DynamicCouponRule;
import org.jeasy.rules.api.Facts;
import org.jeasy.rules.api.Rules;
import org.jeasy.rules.api.RulesEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
publicclass CouponSystemApplication implements CommandLineRunner {@Autowiredprivate RulesEngine rulesEngine; // 规则引擎@Autowiredprivate DynamicCouponRule dynamicCouponRule; // 动态规则@Autowiredprivate CouponService couponService; // 优惠券服务public static void main(String[] args) {SpringApplication.run(CouponSystemApplication.class, args);}/*** 应用启动时运行的方法* @param args 命令行参数* @throws Exception 异常*/@Overridepublic void run(String... args) throws Exception {ShoppingCart cart = new ShoppingCart(); // 创建购物车cart.addItem(new Item("Laptop", "Electronics", 1200)); // 添加商品cart.addItem(new Item("Book", "Books", 30)); // 添加商品Facts facts = new Facts(); // 创建事实对象facts.put("cart", cart); // 将购物车放入事实对象Rules rules = new Rules(); // 创建规则集合// 从数据库加载规则并注册到规则引擎Long[] ruleIds = {1L, 2L}; // 数据库中的规则IDfor (Long ruleId : ruleIds) {dynamicCouponRule.setRuleFromDatabase(ruleId); // 从数据库设置规则rules.register(dynamicCouponRule); // 注册规则}rulesEngine.fire(rules, facts); // 执行规则引擎System.out.println("Final price after discounts: " + cart.getTotalPrice()); // 输出最终价格}
}
运行应用程序
保存所有文件并在终端中运行以下命令启动应用程序:
mvn spring-boot:run
你应该会看到以下输出:
Applied 10% discount for total price exceeding 1000
Applied 5% discount for purchasing electronics
Final price after discounts: 1071.0
总结
这个示例展示了如何在 Spring Boot 应用程序中集成 Easy Rules 和 MyBatis,以便通过数据库灵活配置优惠券规则。通过这种方式,你可以在不修改代码的情况下添加新的规则。以下是关键点总结:
数据库配置:使用 MyBatis 和 MySQL 来存储和管理规则。
动态规则:使用 Easy Rules 的
DynamicRule
类来加载和执行从数据库获取的规则。服务层:通过服务层来处理与数据库的交互。
规则引擎配置:配置规则引擎并注册动态规则。
关注我!Java从此不迷路!