营销系统规则引擎

一、系统介绍

        规则引擎是一个用于执行营销规则的模块,其包括营销规则配置、规则校验等功能。规则引擎可以根据预先设定的条件和逻辑,自动化地执行特点的营销策略,帮助企业更好地吸引客户,增加销售和提高客户满意度。

        规则引擎功能列表:

              1、规则装配 - 根据活动类型组装不同营销规则

              2、逻辑设计 - 支持与、或、非等复杂逻辑关系。

              3、配置校验 - 支持对活动规则进行自动化校验。

二、技术实现

1.UserCenterRegistryActivityRule - 个人中心注册活动规则

class UserCenterRegistryActivityRule extends ActivityRule{

    public UserCenterRegistryActivityRule(){
        super("region_rule&channel_rule&(user_group_rule|user_tag_rule)");
    }

    public String rootRulePath(){
        return "usercenter_registry_activity";
    }
}

2.ActivityRule - 活动规则抽象

public abstract class ActivityRule implements RuleItem{
    /**
     * 规则表达式
     */
    private String ruleExpression;
    /**
     * 规则项配置校验
     */
    @Autowired
    private Map ruleItemMap;
    
    public ActivityRule(String ruleExpression){
        this.ruleExpression = ruleExpression;
    }

    /**
     * 规则项校验
     */
    public boolean apply(CalculateRequest request, PeContext peContext) {
        Stack opStack = new Stack<>();
        Stack resStack = new Stack<>();
        Set opChSet = Set.of('(', ')', '&', '|');
        int i = 0;
        // 处理右括号
        while (i < ruleExpression.length()) {
            char ch = ruleExpression.charAt(i);
            switch (ch) {
                case '(':
                    opStack.push(ch);
                    i++;
                    break;
                case ')': 
                    while (opStack.peek() != '(') {
                        Character opChar = opStack.peek();
                        if (opChar == '&') {
                            boolean right = resStack.pop();
                            boolean left = resStack.pop();
                            resStack.push(left && right);
                        } else if (opChar == '|') {
                            boolean right = resStack.pop();
                            boolean left = resStack.pop();
                            resStack.push(left || right);
                        }
                        opStack.pop();
                    }
                    break;
                case '&': // 操作符
                    opStack.push('&');
                    i++;
                    break;
                case '|':
                    opStack.push('|');
                    i++;
                    break;
                default: // 操作数
                    int j = i;
                    while (j < ruleExpression.length() && !opChSet.contains(ruleExpression.charAt(j))) {
                        j++;
                    }
                    String rule = ruleExpression.substring(i, j);
                    resStack.push(ruleItemMap.get(rule).apply(request, peContext));
                    i = j;
            }
        }
        // 处理结果
        while (!opStack.isEmpty()) {
            Character opChar = opStack.peek();
            if (opChar == '&') {
                boolean right = resStack.pop();
                boolean left = resStack.pop();
                resStack.push(left && right);
            } else if (opChar == '|') {
                boolean right = resStack.pop();
                boolean left = resStack.pop();
                resStack.push(left || right);
            }
            opStack.pop();
        }

        return resStack.pop();
    }

    
    default String rootRulePath();


    /**
     * 规则配置校验
     */
    public PathError validate(String rulePath) {
        if (rulePath == null){
            rulePath = rootRulePath();
        }
        PathError pathError = PathError.of(null, rulePath);
        for (Map.Entry entry : ruleItemMap.entrySet()) {
            String ruleItemPath = entry.getKey();
            RuleItem ruleItem = entry.getValue();
            PathError ruleItemError = ruleItem.validate(ruleItemPath);
            if (ruleItemError != null) {
                return pathError.with(ruleItemError);
            }
        }
        return null;
    }
}

3.UserGroupRuleItem - 用户组规则项

class UserGroupRuleItem extends RuleItem{

    private List groupsLimit;

    @Override
    public PathError validate(String rulePath){
        PathError pathError = PathError.of(null, rulePath);
        if (groupsLimit == null || groupsLimit.size() == 0){
            return pathError.withPath("groupsLimit").withError("groupsLimit不能为空");
        }
        return null;
    }


    @Overrider
    public boolean apply(CalculateRequest req, PeContext context){
        UserService userService = SpringUtil.getBean(UserService.class);
        // 判断用户是否符合用户组规则
        List userGroups = userService.getUserGroups(req.getUserId());
        if (groupsLimit.stream().anyMatch(userGroups::contains)){
            return true;
        }
        retrun false;
    }
}

4.RuleItem - 规则项定义

interface RuleItem {
    // 规则配置校验
    default PathError validate(String rulePath) {

        PathError pathError = new PathError(null, rulePath);

        // 校验规则字段
        Field[] fields = FieldUtils.getSpecFields(getClass(), RuleItem.class);

        if (fields.length == 0) {
            return null;
        }

        try {
            for (Field ruleField : fields) {
                RuleItem rule = (Rule) FieldUtils.getField(this, ruleField);
                if (rule == null){
                    continue;
                }
                String fieldName = ruleField.getName();
                // 规则字段校验失败
                PathError fieldPathError = rule.validate(fieldName);
                // 返回字段校验失败结果
                if (fieldPathError != null) {
                    return pathError.with(fieldPathError);
                }
            }
        } catch (Exception e) {
            throw new AppException(ErrorCode.SYSTEM_ERROR, String.format("校验Rule错误: %s", e.getMessage()));
        }

        return null;

    }

    // 规则应用
    default boolean apply(CalculateRequest request, PeContext peContext){
        return true;
    };

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class PathError{
        
        private String error;
        
        private List paths;
        
        public PathError with(PathError other){
              this.error = other.error;
              this.paths.addAll(other.paths);
              return this;
        }
        
        public PathError withError(String error){
            this.error = error;
            return this;
        }

        public PathError withPath(String path){
            this.paths.add(path);
            return this;
        }

    }
}

你可能感兴趣的:(营销活动,java)