BigMarker-抽奖前置规则过滤

需求

在我们的流程设计中,用户执行抽奖时会判断是否已经超过N积分,如果超过N积分则可以在限定范围内进行抽奖。同时如果用户是黑名单范围的羊毛党用户,则只返回固定的奖品ID

模型

  1. 整个规则来说,分为抽奖前、抽奖中、抽奖后,三个阶段执行。本节我们先来处理抽奖前的规则。
  2. 在工程分包上,需要添加 rule 来处理抽奖规则,在添加 raffle 处理抽奖过程。

前置规则判断根据现有的积分决定能抽到什么,以及黑名单

新增实体

RaffleAwardEntity:抽奖结束后要返回一个奖品直接返回一些key交给后续Award有关的列进行处理

RaffleFactorEntity:抽奖因子(参数)抽奖策略接口的参数

RaffleActionEntity:返回一个对象实体,用于你抽奖前后的操作,如抽奖之前是否有解锁,

分为抽奖前过滤规则,抽奖中过滤规则,抽奖后过滤规则(如抽到了但未解锁,返回随机积分)

定义了一个名为RuleActionEntity的泛型类,其中泛型类型T必须是RuleActionEntity.RaffleEntity的子类。同时,该类内部还定义了四个静态内部类:RaffleEntityRaffleBeforeEntityRaffleCenterEntityRaffleAfterEntity,它们都是RaffleEntity的子类。

这些类用于表示不同的抽奖阶段或状态。,RaffleBeforeEntity表示抽奖开始前的状态,RaffleCenterEntity表示抽奖进行中的状态,而RaffleAfterEntity表示抽奖结束后的状态。

重新回答

||

RuleMatterRntity: 用于过滤和过滤接口配合使用

过滤接口

抽奖策略接口——传入因子放回奖品key

RaffleActionEntity:放回一些要用到的参数如权重值策略id还有用于黑名单的奖品id100

@Getter
@AllArgsConstructor
public enum RuleLogicCheckTypeVO {

    ALLOW("0000", "放行;执行后续的流程,不受规则引擎影响"),
    TAKE_OVER("0001","接管;后续的流程,受规则引擎执行结果影响"),
    ;

    private final String code;
    private final String info;

}

控制如何进行下一步这是一个Java枚举类,名为RuleLogicCheckTypeVO。它有两个枚举值:ALLOW和TAKE_OVER。每个枚举值都有一个对应的code和info属性。这个枚举类用于表示规则引擎的逻辑检查类型

public interface ILogicFilter<T extends RuleActionEntity.RaffleEntity> {

    RuleActionEntity<T> filter(RuleMatterEntity ruleMatterEntity);

}

这里抽奖规则过滤接口 用RuleActionEntity要注意基础应为RuleActionEntity规定了,这样就可以返回一个RuleActionEntity的对象,具体是什么取决于具体场景

建立一个工厂方便规则,以及接口实现  annotation方便注入

完整代码详细理解

package org.example.domain.strategy.model.entity;

import lombok.*;
import org.example.domain.strategy.model.vo.RuleLogicCheckTypeVO;

/**
 * @author xy
 * @description 返回一个对象实体,用于返回之后的操作
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class RuleActionEntity<T extends RuleActionEntity.RaffleEntity> {

    private String code= RuleLogicCheckTypeVO.ALLOW.getCode();
    private String info=RuleLogicCheckTypeVO.ALLOW.getInfo();
    private String ruleModel;
    private T data;
    static public class RaffleEntity{


    }

    @EqualsAndHashCode(callSuper = true)
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    /**抽奖前*/
    static public class RaffleBeforeEntity extends RaffleEntity{
        /**策略id*/
        private Long strategyId;
        /**权重值:用于抽奖可以选择权重*/
        private String ruleWeightValueKey;
        /**奖品ID*/
        private Integer awardId;
    }
    /**抽奖中*/
    static public class RaffleCenterEntity extends RaffleEntity{

    }

    /**抽奖后*/
    static public class RaffleAfterEntity extends RaffleEntity{

    }

}

包含了一些属性和方法。这个类使用了Lombok库来简化代码,提供了@Data、@AllArgsConstructor、@NoArgsConstructor和@Builder注解。这个类还定义了一个内部类RaffleEntity,以及三个继承自RaffleEntity的内部类:RaffleBeforeEntity、RaffleCenterEntity和RaffleAfterEntity。这些内部类分别表示抽奖前、抽奖中和抽奖后的操作。还规定了泛型,还有code和info用来输出到控制台以及后续的筛查

@EqualsAndHashCode(callSuper = true)
//,用于自动生成 equals 和 hashCode 方法。当一个类继承了另一个类时,
// 如果想让子类的 equals 和 hashCode 方法同时考虑父类的属性,就需要在子类上使用这个注解
//将callSuper属性设置为true。这样,在生成的equals和hashCode方法中,会先调用父类的相应方法,然后再考虑子类的字段

/**
 * @author xy
 * @description
 */
@Slf4j
public abstract class AbstractRaffleStrategy implements IRaffleStrategy {

    //策略仓储服务-》domain层像一个大厨,仓储层提供米面油盐
    protected IStrategyRepository repository;
    //策略调度服务-》只负责抽奖处理,通过调用接口的方式,隔离职责,不需要使用方关心或者调用抽奖的初始化
    protected IStrategyDispatch strategyDispatch;


    public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) {
        this.repository = repository;
        this.strategyDispatch = strategyDispatch;
    }

    @Override
    public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {

        // 1. 参数校验
        String userId = raffleFactorEntity.getUserId();
        Long strategyId = raffleFactorEntity.getStrategyId();
        if (null == strategyId || StringUtils.isBlank(userId)) {
            throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
        }

        // 2. 策略查询 得到了 id 模型 即strategy策略表的内容
        StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId);

        // 3. 抽奖前 - 规则过滤
        RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = this.doCheckRaffleBeforeLogic(RaffleFactorEntity.builder().userId(userId).strategyId(strategyId).build(), strategy.ruleModels());

        if (RuleLogicCheckTypeVO.TAKE_OVER.getCode().equals(ruleActionEntity.getCode())) {
            if (DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode().equals(ruleActionEntity.getRuleModel())) {
                // 黑名单返回固定的奖品ID
                return RaffleAwardEntity.builder()
                        .awardId(ruleActionEntity.getData().getAwardId())
                        .build();
            } else if (DefaultLogicFactory.LogicModel.RULE_WIGHT.getCode().equals(ruleActionEntity.getRuleModel())) {
                // 权重根据返回的信息进行抽奖
                RuleActionEntity.RaffleBeforeEntity raffleBeforeEntity = ruleActionEntity.getData();
                String ruleWeightValueKey = raffleBeforeEntity.getRuleWeightValueKey();
                Integer awardId = strategyDispatch.getRandomAwardId(strategyId, ruleWeightValueKey);
                return RaffleAwardEntity.builder()
                        .awardId(awardId)
                        .build();
            }
        }

        // 4. 默认抽奖流程
        Integer awardId = strategyDispatch.getRandomAwardId(strategyId);

        return RaffleAwardEntity.builder()
                .awardId(awardId)
                .build();
    }

    protected abstract RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> doCheckRaffleBeforeLogic(RaffleFactorEntity build, String ...logics);
}

AbstractRaffleStrategy,实现了IRaffleStrategy接口。它主要用于处理抽奖策略的逻辑。在这个类中,定义了一些成员变量,如repositorystrategyDispatch,分别用于存储策略数据和执行抽奖操作。同时,提供了一个构造函数,用于初始化这两个成员变量。

performRaffle方法是这个类的核心方法,用于执行抽奖操作。它首先对输入参数进行校验,然后查询策略信息,接着根据策略规则进行过滤。如果满足某些条件,可以直接返回奖品ID;否则,按照默认的抽奖流程进行抽奖。最后,返回抽奖结果。

在这个Java代码中,使用protected关键字来修饰成员变量(如repositorystrategyDispatch)和方法(如doCheckRaffleBeforeLogicprotected关键字允许子类和同一个包中的其他类访问这些成员。这意味着,当我们创建一个继承自AbstractRaffleStrategy的子类时,这个子类可以直接访问父类中的protected成员,而无需通过公共接口(即public方法)。

package org.example.domain.strategy.service.raffle;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.example.domain.strategy.model.entity.RaffleFactorEntity;
import org.example.domain.strategy.model.entity.RuleActionEntity;
import org.example.domain.strategy.model.entity.RuleMatterEntity;
import org.example.domain.strategy.model.vo.RuleLogicCheckTypeVO;
import org.example.domain.strategy.repository.IStrategyRepository;
import org.example.domain.strategy.service.amory.IStrategyDispatch;
import org.example.domain.strategy.service.rule.ILogicFilter;
import org.example.domain.strategy.service.rule.factory.DefaultLogicFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author xy
 * @description
 */
@Slf4j
@Service
public class DefaultRaffleStrategy extends AbstractRaffleStrategy{

    @Resource
    private DefaultLogicFactory logicFactory;

    public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) {
        super(repository, strategyDispatch);
    }


    @Override
    protected RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, String... logics) {

        Map<String, ILogicFilter<RuleActionEntity.RaffleBeforeEntity>> logicFilterGroup = logicFactory.openLogicFilter();


        // 黑名单规则优先过滤
        String ruleBackList = Arrays.stream(logics)
                .filter(str -> str.contains(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()))
                .findFirst()
                .orElse(null);

        if (StringUtils.isNotBlank(ruleBackList)) {
            ILogicFilter<RuleActionEntity.RaffleBeforeEntity> logicFilter = logicFilterGroup.get(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode());
            RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
            ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
            ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId());
            ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
            ruleMatterEntity.setRuleModel(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode());
            RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = logicFilter.filter(ruleMatterEntity);
            if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) {
                return ruleActionEntity;
            }
        }

        // 顺序过滤剩余规则
        List<String> ruleList = Arrays.stream(logics)
                .filter(s -> !s.equals(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()))
                .collect(Collectors.toList());


        RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = null;
        for (String ruleModel : ruleList) {
            ILogicFilter<RuleActionEntity.RaffleBeforeEntity> logicFilter = logicFilterGroup.get(ruleModel);
            RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
            ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
            ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId());
            ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
            ruleMatterEntity.setRuleModel(ruleModel);
            ruleActionEntity = logicFilter.filter(ruleMatterEntity);
            // 非放行结果则顺序过滤
            log.info("抽奖前规则过滤 userId: {} ruleModel: {} code: {} info: {}", raffleFactorEntity.getUserId(), ruleModel, ruleActionEntity.getCode(), ruleActionEntity.getInfo());
            if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) return ruleActionEntity;
        }

        return ruleActionEntity;
    }
}

这段代码是一个名为`DefaultRaffleStrategy`的Java类,它继承了`AbstractRaffleStrategy`抽象类。这个类主要用于处理抽奖策略的逻辑。在这个类中,定义了一个名为`doCheckRaffleBeforeLogic`的方法,该方法接收一个`RaffleFactorEntity`对象和一个可变参数`logics`,用于检查抽奖前的逻辑。

方法首先创建一个名为`logicFilterGroup`的映射,用于存储不同类型的逻辑过滤器。然后,它会检查传入的`logics`数组中是否包含黑名单规则(`RULE_BLACKLIST`),如果包含,则使用相应的逻辑过滤器对用户进行过滤。如果过滤结果不是允许(`ALLOW`),则直接返回过滤结果。

接下来,方法会过滤剩余的规则,并依次应用这些规则。对于每个规则,它会从`logicFilterGroup`中获取相应的逻辑过滤器,然后使用该过滤器对用户进行过滤。如果过滤结果不是允许(`ALLOW`),则立即返回过滤结果。

最后,如果所有规则都通过了过滤,方法将返回最后一个规则的过滤结果。

  • 25
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
uni-app 是一种基于 Vue.js 的跨平台应用开发框架,它可以帮助开发者快速构建同时运行在 iOS、Android、Web 等平台的应用。在 uni-app 中实现转盘抽奖功能,通常会使用组件和一些交互效果库来模拟。以下是一个简单的步骤概述: 1. **创建组件**: 首先,你需要在项目中创建一个新的组件,比如名为 `SpinWheel` 的.vue文件,用于显示转盘并处理旋转事件。 ```html <template> <view class="spin-wheel"> <image :src="wheelImage" /> <indicator-dots :dots="dots"></indicator-dots> </view> </template> <script> import IndicatorDots from '@/components/IndicatorDots.vue'; export default { components: { IndicatorDots }, data() { return { wheelImage: 'path/to/your/spin_wheel_image', dots: [], // 数字点数组,对应奖品位置 }; }, methods: { spin() { // 在这里编写旋转转盘的逻辑,可能包含随机选择一个数字点 } }, }; </script> ``` 2. **动画效果**: 使用 Vue 的动画库(如 vant-weapp 或者自己编写 CSS 动画)来模拟转盘的旋转和停止动画。 3. **旋转逻辑**: 当用户触发抽奖时,调用 `spin` 方法,这个方法内部可能需要生成一个随机数,然后根据这个随机数选择对应的奖品点。 4. **事件监听**: 可能还需要添加点击或滑动事件监听器,以便在指针停止时触发结果展示。 5. **结果展示**: 结果可以显示在组件内部或者其他页面,比如弹出层或者通知。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值