手记

使用Spring Expression Language (SpEL) 创建简易规则引擎

Spring 表达式语言(SpEL)是一种强大的功能,它允许在运行时动态地查询和操作对象。在这篇文章里,我们将探讨如何在 Spring Boot 3 应用程序中利用 SpEL 来定义和评估从数据库中提取的业务规则。我们将通过一个电商应用中的折扣规则示例来重点说明。

Spring Expression Language 概览 (SpEL)

SpEL 允许开发人员在对象上执行表达式,使其特别适合创建灵活的业务规则,从而使这些规则可以根据数据库中的数据变化。

场景

想象一个电商平台,在该平台上,您希望根据如客户年龄和会员等级等条件来应用折扣。这些条件将存储在数据库中,SpEL(表达式语言)将根据这些条件动态计算以确定应适用的折扣优惠。

如何设置 Spring Boot 3 项目 1. 首先,创建一个Spring Boot项目吧

可以使用Spring Initializr创建一个新的Spring Boot项目,包括以下依赖。

  • Spring Web
  • Spring Data JPA
  • H2 Database(简化起见)
2. 在pom.xml中添加依赖项

这里是一个 Spring Boot 3 版本的 pom.xml 示例:

    <project xmlns="http://maven.apache.org/POM/4.0.0"  
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">  
        <modelVersion>4.0.0</modelVersion>  
        <groupId>com.example</groupId>  
        <artifactId>discount-rules</artifactId>  
        <version>0.0.1-SNAPSHOT</version>  
        <packaging>jar</packaging>  
        <name>discount-rules</name>  
        <description>一个展示 Spring Boot 3 功能的示例项目</description>  
        <parent>  
            <groupId>org.springframework.boot</groupId>  
            <artifactId>spring-boot-starter-parent</artifactId>  
            <version>3.0.0</version>  
            <relativePath/> <!-- 从仓库中查找父项目 -->  
        </parent>  
        <properties>  
            <java.version>17</java.version>  
        </properties>  
        <dependencies>  
            <dependency>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-starter-data-jpa</artifactId>  
            </dependency>  
            <dependency>  
                <groupId>com.h2database</groupId>  
                <artifactId>h2</artifactId>  
                <scope>运行时</scope>  
            </dependency>  
            <dependency>  
                <groupId>org.springframework.boot</groupId>  
                <artifactId>spring-boot-starter-web</artifactId>  
            </dependency>  
        </dependencies>  
        <build>  
            <plugins>  
                <plugin>  
                    <groupId>org.springframework.boot</groupId>  
                    <artifactId>spring-boot-maven-plugin</artifactId>  
                </plugin>  
            </plugins>  
        </build>  
    </project>
定义数据库对象

创建一个类来表示折扣规则。

    import jakarta.persistence.Entity;  
    import jakarta.persistence.GeneratedValue;  
    import jakarta.persistence.Id;  

    @Entity  
    public class DiscountRule {  
        @Id  
        @GeneratedValue  
        private Long id;  
        private String condition; // SpEL 表达式  
        private double discountPercentage; // 折扣率

        // 构造器  
        public DiscountRule() {}  

        public DiscountRule(String condition, double discountPercentage) {  
            this.condition = condition;  
            this.discountPercentage = discountPercentage;  
        }  

        // getter 和 setter 方法  
        public Long getId() {  
            return id;  
        }  

        public void setId(Long id) {  
            this.id = id;  
        }  

        public String getCondition() {  
            return condition;  
        }  

        public void setCondition(String condition) {  
            this.condition = condition;  
        }  

        public double getDiscountPercentage() {  
            return discountPercentage;  
        }  

        public void setDiscountPercentage(double discountPercentage) {  
            this.discountPercentage = discountPercentage;  
        }  
    }
创建仓库(Repository)

现在,让我们创建一个 Spring Data JPA Repository 来管理 DiscountRule

    import org.springframework.data.jpa.repository.JpaRepository;  

    public interface DiscountRuleRepository extends JpaRepository<DiscountRule, Long> {  
    }
样本数据:

这里有一些示例折扣规则,你可能会把这些规则存进数据库。

填充数据库内容

你可以用 CommandLineRunner 在应用启动时用这些规则来填充数据库。

导入 org.springframework.boot.CommandLineRunner;  
导入 org.springframework.stereotype.Component;  

导入 java.util.Arrays;  

@Component  
public class 数据初始化类 implements CommandLineRunner {  

    private final 折扣规则存储库 repository;  

    public 数据初始化类(折扣规则存储库 repository) {  
        this.repository = repository;  
    }  

    @Override  
    public void run(String... args) throws Exception {  
        repository.saveAll(Arrays.asList(  
            new 折扣规则对象("顾客年龄大于60", 10),  
            new 折扣规则对象("会员等级等于'GOLD'", 15),  
            new 折扣规则对象("会员等级等于'SILVER'", 5),  
            new 折扣规则对象("总金额大于100", 20)  
        ));  
    }  
}
SpEL规则评估

创建一个服务来获取和评估折扣规则,基于当前订单。

    import org.springframework.beans.factory.annotation.Autowired;  
    import org.springframework.expression.ExpressionParser;  
    import org.springframework.expression.spel.standard.SpelExpressionParser;  
    import org.springframework.expression.spel.support.StandardEvaluationContext;  
    import org.springframework.stereotype.Service;  

    import java.util.List;  

    @Service  
    public class 折扣服务 {  

        @Autowired  
        private 折扣规则仓库 discountRuleRepository;  

        public double 计算折扣(订单 order) {  
            List<折扣规则> rules = discountRuleRepository.findAll();  
            double totalDiscount = 0;  

            ExpressionParser parser = new SpelExpressionParser();  
            for (折扣规则 rule : rules) {  
                StandardEvaluationContext context = new StandardEvaluationContext(order);  
                boolean isMatch = parser.parseExpression(rule.getCondition()).getValue(context, Boolean.class);  
                if (isMatch) {  
                    totalDiscount += order.getTotalAmount() * (rule.getDiscountPercentage() / 100);  
                }  
            }  
            return totalDiscount;  
        }  
    }
示例订单类(ExampleOrder类)

这里有一个简单的 Order 类,表示你的应用中的一个订单。

    public class Order {  
        private double totalAmount;  
        private int customerAge;  
        private String membershipLevel;  

        // 获取器和设置器方法  
        public double getTotalAmount() {  
            return totalAmount;  
        }  

        public void setTotalAmount(double totalAmount) {  
            this.totalAmount = totalAmount;  
        }  

        public int getCustomerAge() {  
            return customerAge;  
        }  

        public void setCustomerAge(int customerAge) {  
            this.customerAge = customerAge;  
        }  

        public String getMembershipLevel() {  
            return membershipLevel;  
        }  

        public void setMembershipLevel(String membershipLevel) {  
            this.membershipLevel = membershipLevel;  
        }  
    }
创建一个RESTful控制器

创建一个REST控制器来提供一个根据订单计算折扣的接口。

示例

要测试这个应用,你可以使用比如 Postman 或 curl。下面是一个发送请求的例子:

求你了:
    POST /api/discount  
    Content-Type: application/json  

    /* 请求体,包含总金额、客户年龄和会员等级 */
    {  
        "总金额": 150,  
        "客户年龄": 65,  
        "会员等级": "金卡"  
    }
请参阅预期回复

按照数据库里的这些规则,预期的回复会是这样的。

  • 60岁以上折扣:150的10% = 15.00元
  • 金卡会员折扣:150的15% = 22.50元
  • 消费满100元折扣:150的20% = 30.00元

总折扣 = 15.00 + 22.50 + 30.00 ,= 67.5.

结尾

通过在 Spring Boot 3 应用程序中使用 Spring 表达式语言(SpEL),您可以在运行时根据存储在数据库中的数据动态创建灵活的业务规则。这种方法使业务逻辑更加灵活,使实现复杂规则变得更加容易,无需将其硬编码到应用程序中。

阅读更多

通过这种设置,您的电子商务应用程序可以根据不断变化的业务规则动态调整折扣,确保它能及时响应客户的需求。

0人推荐
随时随地看视频
慕课网APP