Spring Boot中实现规则引擎源码教程

在软件开发中,我们经常需要应用一组规则或条件来过滤和处理数据。使用传统的 if 和 else 条件管理这些规则可能会变得繁琐且难以维护。规则引擎提供了一种更灵活、更有条理的方法来定义和执行这些规则。在本文中,我们将探讨如何使用 Java 函数式编程原理在 Spring Boot 项目中构建一个简单的规则引擎。

什么是规则引擎?
规则引擎是一个专家系统程序,它对输入数据运行规则,如果任何条件匹配,则执行相应的操作。
规则引擎负责管理一组规则,并将它们应用于一组对象。它根据定义的规则过滤对象并返回过滤结果。

案例
在这个应用程序中,首先我将创建一个UserController.java类并创建一个返回用户列表的Rest端点。


import com.example.spring_boot_rule_engine_demo.model.User; 
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.List;


@RestController
@RequestMapping("/user")
public class UserController {
    
    @GetMapping
    public List<User> getAllUser(){
        return userData();
    }

    private List<User> userData() {
        List<User> users = new ArrayList<>();
        User user1 = new User(
"sumit", 33);
        User user2 = new User(
"agam", 13);
        User user3 = new User(
"mohit", 23);
        User user4 = new User(
"kailash", 43);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        users.add(user4);
        return users;
    }

}

现在,我们要求只获取年龄大于 30 岁、姓名以 sum 开头的用户。
因此,现在我们需要创建两条规则,并在向客户端返回响应前应用这两条规则。

定义规则:
首先,我们将使用一个名为 Rule 的枚举来定义规则。枚举中的每条规则都代表我们要评估的特定条件或标准。

import com.example.spring_boot_rule_engine_demo.model.User;

import java.util.function.Predicate;

public enum Rule implements TestRule {

    AGE_GREATER_THAN_30(user -> user.getAge() > 30),
    NAME_STARTS_WITH_SUM(user -> user.getName().startsWith("sum"));

    private final Predicate<User> predicate;

    Rule(Predicate<User> predicate) {
        this.predicate = predicate;
    }

    public Predicate<User> getPredicate() {
        return predicate;
    }
}

让我创建一个 TestRule 接口来定义不需要实现的方法。

import java.util.function.Predicate;

public interface TestRule {
    <T> Predicate<T> getPredicate();
}

创建自己的规则引擎:
接下来,我们创建 RuleEngine 类。该类将处理规则的管理和执行。它维护一个规则列表,并提供添加新规则和根据这些规则过滤对象的方法。

实现过滤逻辑
在 RuleEngine 类的过滤方法中,我们遍历对象列表,并使用 Java 8 Stream API 中的 allMatch 方法应用每条规则。该方法会检查给定对象是否通过了所有规则。如果所有规则都通过,我们就会将该对象添加到过滤列表中。

import com.example.spring_boot_rule_engine_demo.rule.TestRule;

import java.util.ArrayList;
import java.util.List;

public class RuleEngine<T> {
    private List<TestRule> rules;

    public RuleEngine() {
        this.rules = new ArrayList<>();
    }

    public void addRule(TestRule rule) {
        rules.add(rule);
    }

    public List<T> filter(List<T> items) {
        List<T> filteredItems = new ArrayList<>();
        for (T item : items) {
            if (rules.stream().allMatch(rule -> rule.getPredicate().test(item))) {
                filteredItems.add(item);
            }
        }
        return filteredItems;
    }
}
public class User {

    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User() {

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


在 UserController.java 类中创建的获取所有用户 API 中,我们演示了规则引擎的用法。我们创建了一个用户对象列表,并用两条规则初始化了规则引擎:AGE_GREATER_THAN_30 和 NAME_STARTS_WITH_SUM。然后,我们调用规则引擎的过滤器方法,并传递用户对象列表。规则引擎会对每个用户应用规则,并返回过滤后的列表。

最后,我们遍历过滤后的列表,返回符合指定规则的用户列表。


import com.example.spring_boot_rule_engine_demo.engine.RuleEngine;
import com.example.spring_boot_rule_engine_demo.model.User;
import com.example.spring_boot_rule_engine_demo.rule.Rule;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.List;


@RestController
@RequestMapping("/user")
public class UserController {
    
    @GetMapping
    public List<User> getAllUser(){
        RuleEngine<User> ruleEngine = new RuleEngine<>();
        ruleEngine.addRule(Rule.AGE_GREATER_THAN_30);
        ruleEngine.addRule(Rule.NAME_STARTS_WITH_SUM);
        List<User> filteredUser = ruleEngine.filter(userData());
        return filteredUser;
    }

    private List<User> userData() {
        List<User> users = new ArrayList<>();
        User user1 = new User(
"sumit", 33);
        User user2 = new User(
"agam", 13);
        User user3 = new User(
"mohit", 23);
        User user4 = new User(
"kailash", 43);
        users.add(user1);
        users.add(user2);
        users.add(user3);
        users.add(user4);
        return users;
    }

}

源码:Github