提交 d10092a1 编写于 作者: 鲸落和鲨掉's avatar 鲸落和鲨掉

添加 抽奖中规则过滤(锁定奖品)、 改写抽奖模式为责任链模式

上级 b647fac1
...@@ -28,5 +28,10 @@ ...@@ -28,5 +28,10 @@
where strategy_id = #{strategy_id} where strategy_id = #{strategy_id}
</select> </select>
<select id="queryStrategyAwardRuleModels" parameterType="java.lang.Long" resultMap="dataMap">
select rule_models from strategy_award
where strategy_id = #{strategyId} and award_id = #{awardId}
</select>
</mapper> </mapper>
package cn.bugstack.test.domain;
import cn.bugstack.domain.strategy.service.armory.IStrategyArmory;
import cn.bugstack.domain.strategy.service.rule.chain.ILogicChain;
import cn.bugstack.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.bugstack.domain.strategy.service.rule.chain.impl.RuleWeightLogicChain;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils;
import javax.annotation.Resource;
/**
* @ClassName: LogicChainTest
* @Description:
* @Author: zhaoyongfeng
* @Date: 2024/11/18 22:49
*/
@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class LogicChainTest {
@Resource
private IStrategyArmory strategyArmory;
@Resource
private RuleWeightLogicChain ruleWeightLogicChain;
@Resource
private DefaultChainFactory defaultChainFactory;
@Before
public void setUp() {
// 策略装配 100001、100002、100003
log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100001L));
// log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100002L));
// log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100003L));
}
@Test
public void test_LogicChain_rule_blacklist() {
ILogicChain logicChain = defaultChainFactory.openLogicChain(100001L);
Integer awardId = logicChain.logic("user001", 100001L);
log.info("测试结果:{}", awardId);
}
@Test
public void test_LogicChain_rule_weight() {
// 通过反射 mock 规则中的值
ReflectionTestUtils.setField(ruleWeightLogicChain, "userScore", 4900L);
ILogicChain logicChain = defaultChainFactory.openLogicChain(100001L);
Integer awardId = logicChain.logic("xiaofuge", 100001L);
log.info("测试结果:{}", awardId);
}
@Test
public void test_LogicChain_rule_default() {
ILogicChain logicChain = defaultChainFactory.openLogicChain(100001L);
Integer awardId = logicChain.logic("xiaofuge", 100001L);
log.info("测试结果:{}", awardId);
}
}
...@@ -2,8 +2,10 @@ package cn.bugstack.test.domain; ...@@ -2,8 +2,10 @@ package cn.bugstack.test.domain;
import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity; import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity;
import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity; import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity;
import cn.bugstack.domain.strategy.service.IRaffleStrategy; import cn.bugstack.domain.strategy.IRaffleStrategy;
import cn.bugstack.domain.strategy.service.rule.impl.RuleWeightLogicFilter; import cn.bugstack.domain.strategy.service.armory.IStrategyArmory;
import cn.bugstack.domain.strategy.service.rule.chain.impl.DefaultLogicChain;
import cn.bugstack.domain.strategy.service.rule.chain.impl.RuleWeightLogicChain;
import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.junit.Before; import org.junit.Before;
...@@ -14,7 +16,6 @@ import org.springframework.test.context.junit4.SpringRunner; ...@@ -14,7 +16,6 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.util.ReflectionTestUtils;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.security.PrivateKey;
/** /**
* @ClassName: RaffleStrategyTest * @ClassName: RaffleStrategyTest
...@@ -26,14 +27,27 @@ import java.security.PrivateKey; ...@@ -26,14 +27,27 @@ import java.security.PrivateKey;
@Slf4j @Slf4j
@RunWith(SpringRunner.class) @RunWith(SpringRunner.class)
public class RaffleStrategyTest { public class RaffleStrategyTest {
@Resource
private IStrategyArmory strategyArmory;
@Resource @Resource
private IRaffleStrategy raffleStrategy; private IRaffleStrategy raffleStrategy;
@Resource @Resource
private RuleWeightLogicFilter ruleWeightLogicFilter; private RuleWeightLogicChain ruleWeightLogicChain;
@Resource
private DefaultLogicChain defaultLogicChain;
@Before @Before
public void setUp() { public void setUp() {
ReflectionTestUtils.setField(ruleWeightLogicFilter, "userScore", 4500L); // 策略装配 100001、100002、100003
log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100001L));
/* log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100002L));
log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100003L));*/
// 通过反射 mock 规则中的值
ReflectionTestUtils.setField(ruleWeightLogicChain, "userScore", 40500L);
ReflectionTestUtils.setField(defaultLogicChain, "userRaffleCount", 10L);
} }
@Test @Test
public void test_performRaffle() { public void test_performRaffle() {
RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder() RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder()
...@@ -60,6 +74,24 @@ public class RaffleStrategyTest { ...@@ -60,6 +74,24 @@ public class RaffleStrategyTest {
log.info("测试结果:{}", JSON.toJSONString(raffleAwardEntity)); log.info("测试结果:{}", JSON.toJSONString(raffleAwardEntity));
} }
/**
* 次数错校验,抽奖n次后解锁。100003 策略,你可以通过调整 @Before 的 setUp 方法中个人抽奖次数来验证。比如最开始设置0,之后设置10
* ReflectionTestUtils.setField(ruleLockLogicFilter, "userRaffleCount", 10L);
*/
@Test
public void test_raffle_center_rule_lock(){
RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder()
.userId("xiaofuge")
.strategyId(100003L)
.build();
RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(raffleFactorEntity);
log.info("请求参数:{}", JSON.toJSONString(raffleFactorEntity));
log.info("测试结果:{}", JSON.toJSONString(raffleAwardEntity));
}
} }
package cn.bugstack.domain.strategy.service.raffle; package cn.bugstack.domain.strategy;
import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity; import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity;
import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity; import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity;
import cn.bugstack.domain.strategy.model.entity.RuleActionEntity; import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
import cn.bugstack.domain.strategy.model.entity.StrategyEntity; import cn.bugstack.domain.strategy.model.entity.StrategyEntity;
import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO; import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import cn.bugstack.domain.strategy.model.valobj.StrategyAwardRuleModelVO;
import cn.bugstack.domain.strategy.repository.IStrategyRepository; import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.domain.strategy.service.IRaffleStrategy;
import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch; import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch;
import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory; import cn.bugstack.domain.strategy.service.rule.chain.ILogicChain;
import cn.bugstack.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.bugstack.types.enums.ResponseCode; import cn.bugstack.types.enums.ResponseCode;
import cn.bugstack.types.exception.AppException; import cn.bugstack.types.exception.AppException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -27,10 +28,13 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy { ...@@ -27,10 +28,13 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy {
protected IStrategyRepository repository; protected IStrategyRepository repository;
// 策略调度服务 -> 只负责抽奖处理,通过新增接口的方式,隔离职责,不需要使用方关心或者调用抽奖的初始化 // 策略调度服务 -> 只负责抽奖处理,通过新增接口的方式,隔离职责,不需要使用方关心或者调用抽奖的初始化
protected IStrategyDispatch strategyDispatch; protected IStrategyDispatch strategyDispatch;
// 抽奖的责任链 -> 从抽奖的规则中,解耦出前置规则为责任链处理
private final DefaultChainFactory defaultChainFactory;
public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) { public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory) {
this.repository = repository; this.repository = repository;
this.strategyDispatch = strategyDispatch; this.strategyDispatch = strategyDispatch;
this.defaultChainFactory = defaultChainFactory;
} }
@Override @Override
...@@ -42,37 +46,35 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy { ...@@ -42,37 +46,35 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy {
throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo()); throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
} }
// 2. 策略查询 // 2. 获取抽奖责任链 - 前置规则的责任链处理
StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId); ILogicChain logicChain = defaultChainFactory.openLogicChain(strategyId);
// 3. 抽奖前 - 规则过滤 // 3. 通过责任链获得,奖品ID
RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = this.doCheckRaffleBeforeLogic(RaffleFactorEntity.builder().userId(userId).strategyId(strategyId).build(), strategy.ruleModels()); Integer awardId = logicChain.logic(userId, strategyId);
if (RuleLogicCheckTypeVO.TAKE_OVER.getCode().equals(ruleActionEntity.getCode())) { // 4. 查询奖品规则「抽奖中(拿到奖品ID时,过滤规则)、抽奖后(扣减完奖品库存后过滤,抽奖中拦截和无库存则走兜底)」
if (DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode().equals(ruleActionEntity.getRuleModel())) { StrategyAwardRuleModelVO strategyAwardRuleModelVO = repository.queryStrategyAwardRuleModelVO(strategyId, awardId);
// 黑名单返回固定的奖品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. 默认抽奖流程 // 5. 抽奖中 - 规则过滤
Integer awardId = strategyDispatch.getRandomAwardId(strategyId); RuleActionEntity<RuleActionEntity.RaffleCenterEntity> ruleActionCenterEntity = this.doCheckRaffleCenterLogic(RaffleFactorEntity.builder()
.userId(userId)
.strategyId(strategyId)
.awardId(awardId)
.build(), strategyAwardRuleModelVO.raffleCenterRuleModelList());
if (RuleLogicCheckTypeVO.TAKE_OVER.getCode().equals(ruleActionCenterEntity.getCode())){
log.info("【临时日志】中奖中规则拦截,通过抽奖后规则 rule_luck_award 走兜底奖励。");
return RaffleAwardEntity.builder()
.awardDesc("中奖中规则拦截,通过抽奖后规则 rule_luck_award 走兜底奖励。")
.build();
}
return RaffleAwardEntity.builder() return RaffleAwardEntity.builder()
.awardId(awardId) .awardId(awardId)
.build(); .build();
} }
protected abstract RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, String... logics);
protected abstract RuleActionEntity<RuleActionEntity.RaffleCenterEntity> doCheckRaffleCenterLogic(RaffleFactorEntity raffleFactorEntity, String... logics);
} }
package cn.bugstack.domain.strategy.service; package cn.bugstack.domain.strategy;
import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity; import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity;
......
...@@ -21,5 +21,8 @@ public class RaffleFactorEntity { ...@@ -21,5 +21,8 @@ public class RaffleFactorEntity {
private String userId; private String userId;
/** 策略ID */ /** 策略ID */
private Long strategyId; private Long strategyId;
/** 奖品ID */
private Integer awardId;
} }
...@@ -48,12 +48,50 @@ public class RuleActionEntity<T extends RuleActionEntity.RaffleEntity> { ...@@ -48,12 +48,50 @@ public class RuleActionEntity<T extends RuleActionEntity.RaffleEntity> {
} }
// 抽奖之中 // 抽奖之中
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
static public class RaffleCenterEntity extends RaffleEntity { static public class RaffleCenterEntity extends RaffleEntity {
/**
* 策略ID
*/
private Long strategyId;
/**
* 权重值Key;用于抽奖时可以选择权重抽奖。
*/
private String ruleWeightValueKey;
/**
* 奖品ID;
*/
private Integer awardId;
} }
// 抽奖之后 // 抽奖之后
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
static public class RaffleAfterEntity extends RaffleEntity { static public class RaffleAfterEntity extends RaffleEntity {
/**
* 策略ID
*/
private Long strategyId;
/**
* 权重值Key;用于抽奖时可以选择权重抽奖。
*/
private String ruleWeightValueKey;
/**
* 奖品ID;
*/
private Integer awardId;
} }
......
package cn.bugstack.domain.strategy.model.valobj; package cn.bugstack.domain.strategy.model.valobj;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor;
/** /**
* @ClassName: RuleLogicCheckTypeVO * @ClassName: RuleLogicCheckTypeVO
......
package cn.bugstack.domain.strategy.model.valobj;
import cn.bugstack.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory;
import cn.bugstack.types.common.Constants;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: StrategyAwardRuleModelVO
* @Description:
* @Author: zhaoyongfeng
* @Date: 2024/11/18 20:39
*/
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StrategyAwardRuleModelVO {
private String ruleModels;
/**
* 获取抽奖中规则;或者使用 lambda 表达式
* <p>
* List<String> ruleModelList = Arrays.stream(ruleModels.split(Constants.SPLIT))
* .filter(DefaultLogicFactory.LogicModel::isCenter)
* .collect(Collectors.toList());
* return ruleModelList;
* <p>
* List<String> collect = Arrays.stream(ruleModelValues).filter(DefaultLogicFactory.LogicModel::isCenter).collect(Collectors.toList());
*/
public String[] raffleCenterRuleModelList() {
List<String> ruleModelList = new ArrayList<>();
String[] ruleModelValues = ruleModels.split(Constants.SPLIT);
for (String ruleModelValue : ruleModelValues) {
if (DefaultLogicFactory.LogicModel.isCenter(ruleModelValue)) {
ruleModelList.add(ruleModelValue);
}
}
return ruleModelList.toArray(new String[0]);
}
public String[] raffleAfterRuleModelList() {
List<String> ruleModelList = new ArrayList<>();
String[] ruleModelValues = ruleModels.split(Constants.SPLIT);
for (String ruleModelValue : ruleModelValues) {
if (DefaultLogicFactory.LogicModel.isAfter(ruleModelValue)) {
ruleModelList.add(ruleModelValue);
}
}
return ruleModelList.toArray(new String[0]);
}
}
...@@ -3,6 +3,7 @@ package cn.bugstack.domain.strategy.repository; ...@@ -3,6 +3,7 @@ package cn.bugstack.domain.strategy.repository;
import cn.bugstack.domain.strategy.model.entity.StrategyAwardEntity; import cn.bugstack.domain.strategy.model.entity.StrategyAwardEntity;
import cn.bugstack.domain.strategy.model.entity.StrategyEntity; import cn.bugstack.domain.strategy.model.entity.StrategyEntity;
import cn.bugstack.domain.strategy.model.entity.StrategyRuleEntity; import cn.bugstack.domain.strategy.model.entity.StrategyRuleEntity;
import cn.bugstack.domain.strategy.model.valobj.StrategyAwardRuleModelVO;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -11,7 +12,7 @@ public interface IStrategyRepository { ...@@ -11,7 +12,7 @@ public interface IStrategyRepository {
List<StrategyAwardEntity> queryStrategyAwardList(Long strategyId); List<StrategyAwardEntity> queryStrategyAwardList(Long strategyId);
void storeStrategyAwardSearchRateTable(String key, Integer rateRange, Map<Integer, Integer> strategyAwardSearchRateTable); void storeStrategyAwardSearchRateTable(String key, int rateRange, Map<Integer, Integer> strategyAwardSearchRateTable);
Integer getStrategyAwardAssemble(String key, Integer rateKey); Integer getStrategyAwardAssemble(String key, Integer rateKey);
...@@ -24,6 +25,8 @@ public interface IStrategyRepository { ...@@ -24,6 +25,8 @@ public interface IStrategyRepository {
StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleModel); StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleModel);
String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel); String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel);
String queryStrategyRuleValue(Long strategyId, String ruleModel);
StrategyAwardRuleModelVO queryStrategyAwardRuleModelVO(Long strategyId, Integer awardId);
} }
package cn.bugstack.domain.strategy.service.annotation; package cn.bugstack.domain.strategy.service.annotation;
import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory; import cn.bugstack.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
...@@ -21,3 +22,4 @@ public @interface LogicStrategy { ...@@ -21,3 +22,4 @@ public @interface LogicStrategy {
} }
package cn.bugstack.domain.strategy.service.raffle; package cn.bugstack.domain.strategy.service.raffle;
import cn.bugstack.domain.strategy.AbstractRaffleStrategy;
import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity; import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity;
import cn.bugstack.domain.strategy.model.entity.RuleActionEntity; import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity; import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity;
import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO; import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import cn.bugstack.domain.strategy.repository.IStrategyRepository; import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch; import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch;
import cn.bugstack.domain.strategy.service.rule.ILogicFilter; import cn.bugstack.domain.strategy.service.rule.filter.ILogicFilter;
import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory; import cn.bugstack.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
...@@ -31,54 +33,38 @@ public class DefaultRaffleStrategy extends AbstractRaffleStrategy { ...@@ -31,54 +33,38 @@ public class DefaultRaffleStrategy extends AbstractRaffleStrategy {
@Resource @Resource
private DefaultLogicFactory logicFactory; private DefaultLogicFactory logicFactory;
public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) {
super(repository, strategyDispatch);
}
@Override public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory) {
protected RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, String... logics) { super(repository, strategyDispatch, defaultChainFactory);
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)) { @Override
ILogicFilter<RuleActionEntity.RaffleBeforeEntity> logicFilter = logicFilterGroup.get(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()); protected RuleActionEntity<RuleActionEntity.RaffleCenterEntity> doCheckRaffleCenterLogic(RaffleFactorEntity raffleFactorEntity, String... logics) {
RuleMatterEntity ruleMatterEntity = new RuleMatterEntity(); if (logics == null || 0 == logics.length) return RuleActionEntity.<RuleActionEntity.RaffleCenterEntity>builder()
ruleMatterEntity.setUserId(raffleFactorEntity.getUserId()); .code(RuleLogicCheckTypeVO.ALLOW.getCode())
ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId()); .info(RuleLogicCheckTypeVO.ALLOW.getInfo())
ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId()); .build();
ruleMatterEntity.setRuleModel(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode());
RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = logicFilter.filter(ruleMatterEntity);
if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) {
return ruleActionEntity;
}
}
// 顺序过滤剩余规则 Map<String, ILogicFilter<RuleActionEntity.RaffleCenterEntity>> logicFilterGroup = logicFactory.openLogicFilter();
List<String> ruleList = Arrays.stream(logics)
.filter(s -> !s.equals(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()))
.collect(Collectors.toList());
RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> ruleActionEntity = null; RuleActionEntity<RuleActionEntity.RaffleCenterEntity> ruleActionEntity = null;
for (String ruleModel : ruleList) { for (String ruleModel : logics) {
ILogicFilter<RuleActionEntity.RaffleBeforeEntity> logicFilter = logicFilterGroup.get(ruleModel); ILogicFilter<RuleActionEntity.RaffleCenterEntity> logicFilter = logicFilterGroup.get(ruleModel);
RuleMatterEntity ruleMatterEntity = new RuleMatterEntity(); RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
ruleMatterEntity.setUserId(raffleFactorEntity.getUserId()); ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId()); ruleMatterEntity.setAwardId(raffleFactorEntity.getAwardId());
ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId()); ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
ruleMatterEntity.setRuleModel(ruleModel); ruleMatterEntity.setRuleModel(ruleModel);
ruleActionEntity = logicFilter.filter(ruleMatterEntity); ruleActionEntity = logicFilter.filter(ruleMatterEntity);
// 非放行结果则顺序过滤 // 非放行结果则顺序过滤
log.info("抽奖规则过滤 userId: {} ruleModel: {} code: {} info: {}", raffleFactorEntity.getUserId(), ruleModel, ruleActionEntity.getCode(), ruleActionEntity.getInfo()); log.info("抽奖规则过滤 userId: {} ruleModel: {} code: {} info: {}", raffleFactorEntity.getUserId(), ruleModel, ruleActionEntity.getCode(), ruleActionEntity.getInfo());
if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) return ruleActionEntity; if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) return ruleActionEntity;
} }
return ruleActionEntity; return ruleActionEntity;
} }
} }
package cn.bugstack.domain.strategy.service.rule.chain;
import lombok.extern.slf4j.Slf4j;
/**
* @ClassName: AbstractLogicChain
* @Description: 抽奖策略责任链,判断走那种抽奖策略。如;默认抽象、权重抽奖、黑名单抽奖
* @Author: zhaoyongfeng
* @Date: 2024/11/18 22:03
*/
@Slf4j
public abstract class AbstractLogicChain implements ILogicChain {
private ILogicChain next;
@Override
public ILogicChain next() {
return next;
}
@Override
public ILogicChain appendNext(ILogicChain next) {
this.next = next;
return next;
}
protected abstract String ruleModel();
}
package cn.bugstack.domain.strategy.service.rule.chain;
/*
* @return
* @author zhaoyongfeng
* @description 抽奖策略规则责任链接口
*
* @param null
*/
public interface ILogicChain extends ILogicChainArmory{
/**
* 责任链接口
*
* @param userId 用户ID
* @param strategyId 策略ID
* @return 奖品ID
*/
Integer logic(String userId, Long strategyId);
}
package cn.bugstack.domain.strategy.service.rule.chain;
/*
* @return
* @author zhaoyongfeng
* @description 责任链装配
*
* @param null
*/
public interface ILogicChainArmory {
ILogicChain next();
ILogicChain appendNext(ILogicChain next);
}
package cn.bugstack.domain.strategy.service.rule.chain.factory;
import cn.bugstack.domain.strategy.model.entity.StrategyEntity;
import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.domain.strategy.service.rule.chain.ILogicChain;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* @ClassName: DefaultLogicFactory
* @Description:
* @Author: zhaoyongfeng
* @Date: 2024/11/17 16:05
*/
@Service
public class DefaultChainFactory {
private final Map<String, ILogicChain> logicChainGroup;
protected IStrategyRepository repository;
public DefaultChainFactory(Map<String, ILogicChain> logicChainGroup, IStrategyRepository repository) {
this.logicChainGroup = logicChainGroup;
this.repository = repository;
}
/**
* 通过策略ID,构建责任链
*
* @param strategyId 策略ID
* @return LogicChain
*/
public ILogicChain openLogicChain(Long strategyId) {
StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId);
String[] ruleModels = strategy.ruleModels();
// 如果未配置策略规则,则只装填一个默认责任链
if (null == ruleModels || 0 == ruleModels.length) return logicChainGroup.get("default");
// 按照配置顺序装填用户配置的责任链;rule_blacklist、rule_weight 「注意此数据从Redis缓存中获取,如果更新库表,记得在测试阶段手动处理缓存」
ILogicChain logicChain = logicChainGroup.get(ruleModels[0]);
ILogicChain current = logicChain;
for (int i = 1; i < ruleModels.length; i++) {
ILogicChain nextChain = logicChainGroup.get(ruleModels[i]);
current = current.appendNext(nextChain);
}
// 责任链的最后装填默认责任链
current.appendNext(logicChainGroup.get("default"));
return logicChain;
}
}
package cn.bugstack.domain.strategy.service.rule.chain.impl;
import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.domain.strategy.service.rule.chain.AbstractLogicChain;
import cn.bugstack.types.common.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @ClassName: RuleBackListLogicFilter
* @Description: 【抽奖前规则】黑名单用户过滤规则
* @Author: zhaoyongfeng
* @Date: 2024/11/17 16:07
*/
@Slf4j
@Component("rule_blacklist")
public class BackListLogicChain extends AbstractLogicChain {
@Resource
private IStrategyRepository repository;
@Override
public Integer logic(String userId, Long strategyId) {
log.info("抽奖责任链-黑名单开始 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());
// 查询规则值配置
String ruleValue = repository.queryStrategyRuleValue(strategyId, ruleModel());
String[] splitRuleValue = ruleValue.split(Constants.COLON);
Integer awardId = Integer.parseInt(splitRuleValue[0]);
// 黑名单抽奖判断
String[] userBlackIds = splitRuleValue[1].split(Constants.SPLIT);
for (String userBlackId : userBlackIds) {
if (userId.equals(userBlackId)) {
log.info("抽奖责任链-黑名单接管 userId: {} strategyId: {} ruleModel: {} awardId: {}", userId, strategyId, ruleModel(), awardId);
return awardId;
}
}
// 过滤其他责任链
log.info("抽奖责任链-黑名单放行 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());
return next().logic(userId, strategyId);
}
@Override
protected String ruleModel() {
return "rule_blacklist";
}
}
package cn.bugstack.domain.strategy.service.rule.chain.impl;
import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch;
import cn.bugstack.domain.strategy.service.rule.chain.AbstractLogicChain;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @ClassName: RuleLockLogicFilter
* @Description:
* @Author: zhaoyongfeng
* @Date: 2024/11/18 20:25
*/
@Slf4j
@Component("default")
public class DefaultLogicChain extends AbstractLogicChain {
@Resource
protected IStrategyDispatch strategyDispatch;
@Override
public Integer logic(String userId, Long strategyId) {
Integer awardId = strategyDispatch.getRandomAwardId(strategyId);
log.info("抽奖责任链-默认处理 userId: {} strategyId: {} ruleModel: {} awardId: {}", userId, strategyId, ruleModel(), awardId);
return awardId;
}
@Override
protected String ruleModel() {
return "default";
}
}
package cn.bugstack.domain.strategy.service.rule.impl; package cn.bugstack.domain.strategy.service.rule.chain.impl;
import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity;
import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import cn.bugstack.domain.strategy.repository.IStrategyRepository; import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.domain.strategy.service.annotation.LogicStrategy; import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch;
import cn.bugstack.domain.strategy.service.rule.ILogicFilter; import cn.bugstack.domain.strategy.service.rule.chain.AbstractLogicChain;
import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory;
import cn.bugstack.types.common.Constants; import cn.bugstack.types.common.Constants;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
...@@ -20,66 +16,74 @@ import java.util.*; ...@@ -20,66 +16,74 @@ import java.util.*;
* @Date: 2024/11/17 16:08 * @Date: 2024/11/17 16:08
*/ */
@Slf4j @Slf4j
@Component @Component("rule_weight")
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_WIGHT) public class RuleWeightLogicChain extends AbstractLogicChain {
public class RuleWeightLogicFilter implements ILogicFilter<RuleActionEntity.RaffleBeforeEntity> {
@Resource @Resource
private IStrategyRepository repository; private IStrategyRepository repository;
public Long userScore = 4500L; public Long userScore = 4500L;
@Resource
protected IStrategyDispatch strategyDispatch;
// 根据用户ID查询用户抽奖消耗的积分值,本章节我们先写死为固定的值。后续需要从数据库中查询。
/** /**
* 权重规则过滤; * 权重责任链过滤;
* 1. 权重规则格式;4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108,109 * 1. 权重规则格式;4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108,109
* 2. 解析数据格式;判断哪个范围符合用户的特定抽奖范围 * 2. 解析数据格式;判断哪个范围符合用户的特定抽奖范围
*
* @param ruleMatterEntity 规则物料实体对象
* @return 规则过滤结果
*/ */
@Override @Override
public RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> filter(RuleMatterEntity ruleMatterEntity) { public Integer logic(String userId, Long strategyId) {
log.info("规则过滤-权重范围 userId:{} strategyId:{} ruleModel:{}", ruleMatterEntity.getUserId(), ruleMatterEntity.getStrategyId(), ruleMatterEntity.getRuleModel()); log.info("抽奖责任链-权重开始 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());
String userId = ruleMatterEntity.getUserId(); String ruleValue = repository.queryStrategyRuleValue(strategyId, ruleModel());
Long strategyId = ruleMatterEntity.getStrategyId();
String ruleValue = repository.queryStrategyRuleValue(ruleMatterEntity.getStrategyId(), ruleMatterEntity.getAwardId(), ruleMatterEntity.getRuleModel());
// 1. 根据用户ID查询用户抽奖消耗的积分值,本章节我们先写死为固定的值。后续需要从数据库中查询。 // 1. 根据用户ID查询用户抽奖消耗的积分值,本章节我们先写死为固定的值。后续需要从数据库中查询。
Map<Long, String> analyticalValueGroup = getAnalyticalValue(ruleValue); Map<Long, String> analyticalValueGroup = getAnalyticalValue(ruleValue);
if (null == analyticalValueGroup || analyticalValueGroup.isEmpty()) { if (null == analyticalValueGroup || analyticalValueGroup.isEmpty()) return null;
return RuleActionEntity.<RuleActionEntity.RaffleBeforeEntity>builder()
.code(RuleLogicCheckTypeVO.ALLOW.getCode())
.info(RuleLogicCheckTypeVO.ALLOW.getInfo())
.build();
}
// 2. 转换Keys值,并默认排序 // 2. 转换Keys值,并默认排序
List<Long> analyticalSortedKeys = new ArrayList<>(analyticalValueGroup.keySet()); List<Long> analyticalSortedKeys = new ArrayList<>(analyticalValueGroup.keySet());
Collections.sort(analyticalSortedKeys); Collections.sort(analyticalSortedKeys);
// 3. 找出最小符合的值,也就是【4500 积分,能找到 4000:102,103,104,105】、【5000 积分,能找到 5000:102,103,104,105,106,107】 // 3. 找出最小符合的值,也就是【4500 积分,能找到 4000:102,103,104,105】、【5000 积分,能找到 5000:102,103,104,105,106,107】
/* 找到最后一个符合的值[如用户传了一个 5900 应该返回正确结果为 5000],如果使用 Lambda findFirst 需要注意使用 sorted 反转结果
* Long nextValue = null;
* for (Long analyticalSortedKeyValue : analyticalSortedKeys) {
* if (userScore >= analyticalSortedKeyValue){
* nextValue = analyticalSortedKeyValue;
* }
* }
*
* Long nextValue = analyticalSortedKeys.stream()
* .filter(key -> userScore >= key)
* .max(Comparator.naturalOrder())
* .orElse(null);
*/
Long nextValue = analyticalSortedKeys.stream() Long nextValue = analyticalSortedKeys.stream()
.filter(key -> userScore >= key) .sorted(Comparator.reverseOrder())
.filter(analyticalSortedKeyValue -> userScore >= analyticalSortedKeyValue)
.findFirst() .findFirst()
.orElse(null); .orElse(null);
// 4. 权重抽奖
if (null != nextValue) { if (null != nextValue) {
return RuleActionEntity.<RuleActionEntity.RaffleBeforeEntity>builder() Integer awardId = strategyDispatch.getRandomAwardId(strategyId, analyticalValueGroup.get(nextValue));
.data(RuleActionEntity.RaffleBeforeEntity.builder() log.info("抽奖责任链-权重接管 userId: {} strategyId: {} ruleModel: {} awardId: {}", userId, strategyId, ruleModel(), awardId);
.strategyId(strategyId) return awardId;
.ruleWeightValueKey(analyticalValueGroup.get(nextValue))
.build())
.ruleModel(DefaultLogicFactory.LogicModel.RULE_WIGHT.getCode())
.code(RuleLogicCheckTypeVO.TAKE_OVER.getCode())
.info(RuleLogicCheckTypeVO.TAKE_OVER.getInfo())
.build();
} }
return RuleActionEntity.<RuleActionEntity.RaffleBeforeEntity>builder() // 5. 过滤其他责任链
.code(RuleLogicCheckTypeVO.ALLOW.getCode()) log.info("抽奖责任链-权重放行 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());
.info(RuleLogicCheckTypeVO.ALLOW.getInfo()) return next().logic(userId, strategyId);
.build(); }
@Override
protected String ruleModel() {
return "rule_weight";
} }
private Map<Long, String> getAnalyticalValue(String ruleValue) { private Map<Long, String> getAnalyticalValue(String ruleValue) {
......
package cn.bugstack.domain.strategy.service.rule; package cn.bugstack.domain.strategy.service.rule.filter;
import cn.bugstack.domain.strategy.model.entity.RuleActionEntity; import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity; import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity;
......
package cn.bugstack.domain.strategy.service.rule.factory; package cn.bugstack.domain.strategy.service.rule.filter.factory;
import cn.bugstack.domain.strategy.model.entity.RuleActionEntity; import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
import cn.bugstack.domain.strategy.service.annotation.LogicStrategy; import cn.bugstack.domain.strategy.service.annotation.LogicStrategy;
import cn.bugstack.domain.strategy.service.rule.ILogicFilter; import cn.bugstack.domain.strategy.service.rule.filter.ILogicFilter;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Getter; import lombok.Getter;
import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.annotation.AnnotationUtils;
...@@ -14,12 +14,13 @@ import java.util.concurrent.ConcurrentHashMap; ...@@ -14,12 +14,13 @@ import java.util.concurrent.ConcurrentHashMap;
/** /**
* @ClassName: DefaultLogicFactory * @ClassName: DefaultLogicFactory
* @Description: * @Description: 规则工厂
* @Author: zhaoyongfeng * @Author: zhaoyongfeng
* @Date: 2024/11/17 16:05 * @Date: 2024/11/18 22:27
*/ */
@Service @Service
public class DefaultLogicFactory { public class DefaultLogicFactory {
public Map<String, ILogicFilter<?>> logicFilterMap = new ConcurrentHashMap<>(); public Map<String, ILogicFilter<?>> logicFilterMap = new ConcurrentHashMap<>();
public DefaultLogicFactory(List<ILogicFilter<?>> logicFilters) { public DefaultLogicFactory(List<ILogicFilter<?>> logicFilters) {
...@@ -39,13 +40,21 @@ public class DefaultLogicFactory { ...@@ -39,13 +40,21 @@ public class DefaultLogicFactory {
@AllArgsConstructor @AllArgsConstructor
public enum LogicModel { public enum LogicModel {
RULE_WIGHT("rule_weight","【抽奖前规则】根据抽奖权重返回可抽奖范围KEY"), RULE_LOCK("rule_lock", "【抽奖中规则】抽奖n次后,对应奖品可解锁抽奖", "center"),
RULE_BLACKLIST("rule_blacklist","【抽奖前规则】黑名单规则过滤,命中黑名单则直接返回"), RULE_LUCK_AWARD("rule_luck_award", "【抽奖后规则】抽奖n次后,对应奖品可解锁抽奖", "after"),
; ;
private final String code; private final String code;
private final String info; private final String info;
private final String type;
public static boolean isCenter(String code){
return "center".equals(LogicModel.valueOf(code.toUpperCase()).type);
}
public static boolean isAfter(String code){
return "after".equals(LogicModel.valueOf(code.toUpperCase()).type);
}
} }
......
package cn.bugstack.domain.strategy.service.rule.impl; package cn.bugstack.domain.strategy.service.rule.filter.impl;
import cn.bugstack.domain.strategy.model.entity.RuleActionEntity; import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity; import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity;
import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO; import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
import cn.bugstack.domain.strategy.repository.IStrategyRepository; import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.domain.strategy.service.annotation.LogicStrategy; import cn.bugstack.domain.strategy.service.annotation.LogicStrategy;
import cn.bugstack.domain.strategy.service.rule.ILogicFilter; import cn.bugstack.domain.strategy.service.rule.filter.ILogicFilter;
import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory; import cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory;
import cn.bugstack.types.common.Constants;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
/** /**
* @ClassName: RuleBackListLogicFilter * @ClassName: RuleLockLogicFilter
* @Description: 【抽奖前规则】黑名单用户过滤规则 * @Description: 用户抽奖n次后,对应奖品可解锁抽奖
* @Author: zhaoyongfeng * @Author: zhaoyongfeng
* @Date: 2024/11/17 16:07 * @Date: 2024/11/18 22:27
*/ */
@Slf4j @Slf4j
@Component @Component
@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_BLACKLIST) @LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_LOCK)
public class RuleBackListLogicFilter implements ILogicFilter<RuleActionEntity.RaffleBeforeEntity> { public class RuleLockLogicFilter implements ILogicFilter<RuleActionEntity.RaffleCenterEntity> {
@Resource @Resource
private IStrategyRepository repository; private IStrategyRepository repository;
@Override // 用户抽奖次数,后续完成这部分流程开发的时候,从数据库/Redis中读取
public RuleActionEntity<RuleActionEntity.RaffleBeforeEntity> filter(RuleMatterEntity ruleMatterEntity) { private Long userRaffleCount = 0L;
log.info("规则过滤-黑名单 userId:{} strategyId:{} ruleModel:{}", ruleMatterEntity.getUserId(), ruleMatterEntity.getStrategyId(), ruleMatterEntity.getRuleModel());
String userId = ruleMatterEntity.getUserId(); @Override
public RuleActionEntity<RuleActionEntity.RaffleCenterEntity> filter(RuleMatterEntity ruleMatterEntity) {
log.info("规则过滤-次数锁 userId:{} strategyId:{} ruleModel:{}", ruleMatterEntity.getUserId(), ruleMatterEntity.getStrategyId(), ruleMatterEntity.getRuleModel());
// 查询规则值配置 // 查询规则值配置;当前奖品ID,抽奖中规则对应的校验值。如;1、2、6
String ruleValue = repository.queryStrategyRuleValue(ruleMatterEntity.getStrategyId(), ruleMatterEntity.getAwardId(), ruleMatterEntity.getRuleModel()); String ruleValue = repository.queryStrategyRuleValue(ruleMatterEntity.getStrategyId(), ruleMatterEntity.getAwardId(), ruleMatterEntity.getRuleModel());
String[] splitRuleValue = ruleValue.split(Constants.COLON); long raffleCount = Long.parseLong(ruleValue);
Integer awardId = Integer.parseInt(splitRuleValue[0]);
// 用户抽奖次数大于规则限定值,规则放行
// 过滤其他规则 if (userRaffleCount>= raffleCount) {
String[] userBlackIds = splitRuleValue[1].split(Constants.SPLIT); return RuleActionEntity.<RuleActionEntity.RaffleCenterEntity>builder()
for (String userBlackId : userBlackIds) { .code(RuleLogicCheckTypeVO.ALLOW.getCode())
if (userId.equals(userBlackId)) { .info(RuleLogicCheckTypeVO.ALLOW.getInfo())
return RuleActionEntity.<RuleActionEntity.RaffleBeforeEntity>builder() .build();
.ruleModel(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode())
.data(RuleActionEntity.RaffleBeforeEntity.builder()
.strategyId(ruleMatterEntity.getStrategyId())
.awardId(awardId)
.build())
.code(RuleLogicCheckTypeVO.TAKE_OVER.getCode())
.info(RuleLogicCheckTypeVO.TAKE_OVER.getInfo())
.build();
}
} }
return RuleActionEntity.<RuleActionEntity.RaffleBeforeEntity>builder() // 用户抽奖次数小于规则限定值,规则拦截
.code(RuleLogicCheckTypeVO.ALLOW.getCode()) return RuleActionEntity.<RuleActionEntity.RaffleCenterEntity>builder()
.info(RuleLogicCheckTypeVO.ALLOW.getInfo()) .code(RuleLogicCheckTypeVO.TAKE_OVER.getCode())
.info(RuleLogicCheckTypeVO.TAKE_OVER.getInfo())
.build(); .build();
} }
}
}
...@@ -12,4 +12,5 @@ public interface IStrategyAwardDao { ...@@ -12,4 +12,5 @@ public interface IStrategyAwardDao {
List<StrategyAward> queryStrategyAwardListByStrategyId(Long strategyId); List<StrategyAward> queryStrategyAwardListByStrategyId(Long strategyId);
String queryStrategyAwardRuleModels(StrategyAward strategyAward);
} }
package cn.bugstack.infrastructure.persistent.po; package cn.bugstack.infrastructure.persistent.po;
import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date; import java.util.Date;
...@@ -12,6 +14,8 @@ import java.util.Date; ...@@ -12,6 +14,8 @@ import java.util.Date;
* @Date: 2024/11/13 20:26 * @Date: 2024/11/13 20:26
*/ */
@Data @Data
@AllArgsConstructor
@NoArgsConstructor
@Builder @Builder
public class Strategy { public class Strategy {
......
...@@ -4,6 +4,7 @@ package cn.bugstack.infrastructure.persistent.repository; ...@@ -4,6 +4,7 @@ package cn.bugstack.infrastructure.persistent.repository;
import cn.bugstack.domain.strategy.model.entity.StrategyAwardEntity; import cn.bugstack.domain.strategy.model.entity.StrategyAwardEntity;
import cn.bugstack.domain.strategy.model.entity.StrategyEntity; import cn.bugstack.domain.strategy.model.entity.StrategyEntity;
import cn.bugstack.domain.strategy.model.entity.StrategyRuleEntity; import cn.bugstack.domain.strategy.model.entity.StrategyRuleEntity;
import cn.bugstack.domain.strategy.model.valobj.StrategyAwardRuleModelVO;
import cn.bugstack.domain.strategy.repository.IStrategyRepository; import cn.bugstack.domain.strategy.repository.IStrategyRepository;
import cn.bugstack.infrastructure.persistent.dao.IStrategyAwardDao; import cn.bugstack.infrastructure.persistent.dao.IStrategyAwardDao;
import cn.bugstack.infrastructure.persistent.dao.IStrategyDao; import cn.bugstack.infrastructure.persistent.dao.IStrategyDao;
...@@ -63,7 +64,7 @@ public class StrategyRepository implements IStrategyRepository { ...@@ -63,7 +64,7 @@ public class StrategyRepository implements IStrategyRepository {
} }
@Override @Override
public void storeStrategyAwardSearchRateTable(String key, Integer rateRange, Map<Integer, Integer> strategyAwardSearchRateTable) { public void storeStrategyAwardSearchRateTable(String key, int rateRange, Map<Integer, Integer> strategyAwardSearchRateTable) {
// 1. 存储抽奖策略范围值,如10000,用于生成1000以内的随机数 // 1. 存储抽奖策略范围值,如10000,用于生成1000以内的随机数
redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, rateRange); redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, rateRange);
// 2. 存储概率查找表 // 2. 存储概率查找表
...@@ -127,6 +128,22 @@ public class StrategyRepository implements IStrategyRepository { ...@@ -127,6 +128,22 @@ public class StrategyRepository implements IStrategyRepository {
return strategyRuleDao.queryStrategyRuleValue(strategyRule); return strategyRuleDao.queryStrategyRuleValue(strategyRule);
} }
@Override
public String queryStrategyRuleValue(Long strategyId, String ruleModel) {
return queryStrategyRuleValue(strategyId, null, ruleModel);
}
@Override
public StrategyAwardRuleModelVO queryStrategyAwardRuleModelVO(Long strategyId, Integer awardId) {
StrategyAward strategyAward = new StrategyAward();
strategyAward.setStrategyId(strategyId);
strategyAward.setAwardId(awardId);
String ruleModels = strategyAwardDao.queryStrategyAwardRuleModels(strategyAward);
return StrategyAwardRuleModelVO.builder().ruleModels(ruleModels).build();
}
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册