From caf38ce3777f8ac8ffcec2f276730eebcb257d2c Mon Sep 17 00:00:00 2001 From: hudingrong <1649576115@qq.com> Date: Tue, 16 Apr 2024 21:03:41 +0800 Subject: [PATCH] rule_model_center --- .../cn/bugstack/config/RedisClientConfig.java | 6 +- .../mybatis/mapper/strategy_award_mapper.xml | 4 ++ .../test/domain/RaffleStrategyTest.java | 40 ++++++++++++- .../model/entity/RaffleFactorEntity.java | 2 + .../strategy/model/entity/StrategyEntity.java | 7 ++- .../valobj/StrategyAwardRuleModelVO.java | 50 ++++++++++++++++ .../repository/IStrategyRepository.java | 9 +++ .../service/armory/StrategyArmory.java | 4 +- .../raffle/AbstractRaffleStrategy.java | 23 +++++++- .../service/raffle/DefaultRaffleStrategy.java | 30 ++++++++++ .../rule/factory/DefaultLogicFactory.java | 16 +++++- .../rule/impl/RuleLockLogicFilter.java | 54 ++++++++++++++++++ .../persistent/dao/IStrategyAwardDao.java | 7 +++ .../infrastructure/persistent/po/Award.java | 1 + .../persistent/redis/RedisService.java | 1 + .../repository/StrategyRepository.java | 57 +++++++++++++------ 16 files changed, 283 insertions(+), 28 deletions(-) create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/valobj/StrategyAwardRuleModelVO.java create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleLockLogicFilter.java diff --git a/xfg-frame-archetype-lite-app/src/main/java/cn/bugstack/config/RedisClientConfig.java b/xfg-frame-archetype-lite-app/src/main/java/cn/bugstack/config/RedisClientConfig.java index 703a0ec..53d2906 100644 --- a/xfg-frame-archetype-lite-app/src/main/java/cn/bugstack/config/RedisClientConfig.java +++ b/xfg-frame-archetype-lite-app/src/main/java/cn/bugstack/config/RedisClientConfig.java @@ -11,6 +11,7 @@ import org.redisson.api.RedissonClient; import org.redisson.client.codec.BaseCodec; import org.redisson.client.protocol.Decoder; import org.redisson.client.protocol.Encoder; +import org.redisson.codec.JsonJacksonCodec; import org.redisson.config.Config; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ConfigurableApplicationContext; @@ -32,8 +33,9 @@ public class RedisClientConfig { public RedissonClient redissonClient(ConfigurableApplicationContext applicationContext, RedisClientConfigProperties properties) { Config config = new Config(); // 根据需要可以设定编解码器;https://github.com/redisson/redisson/wiki/4.-%E6%95%B0%E6%8D%AE%E5%BA%8F%E5%88%97%E5%8C%96 - config.setCodec(new RedisCodec()); - + // 需要手动从json转pojo + //config.setCodec(new RedisCodec()); + config.setCodec(new JsonJacksonCodec()); config.useSingleServer() .setAddress("redis://" + properties.getHost() + ":" + properties.getPort()) .setPassword(properties.getPassword()) diff --git a/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_award_mapper.xml b/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_award_mapper.xml index 67ee57e..003960e 100644 --- a/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_award_mapper.xml +++ b/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_award_mapper.xml @@ -28,5 +28,9 @@ from strategy_award where strategy_id = #{strategyId} + diff --git a/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/RaffleStrategyTest.java b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/RaffleStrategyTest.java index 1595037..002af8d 100644 --- a/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/RaffleStrategyTest.java +++ b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/RaffleStrategyTest.java @@ -3,6 +3,9 @@ package cn.bugstack.test.domain; import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity; import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity; import cn.bugstack.domain.strategy.service.IRaffleStrategy; +import cn.bugstack.domain.strategy.service.armory.IStrategyArmory; +import cn.bugstack.domain.strategy.service.armory.StrategyArmory; +import cn.bugstack.domain.strategy.service.rule.impl.RuleLockLogicFilter; import cn.bugstack.domain.strategy.service.rule.impl.RuleWeightLogicFilter; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; @@ -25,17 +28,35 @@ import javax.annotation.Resource; @SpringBootTest public class RaffleStrategyTest { + @Resource + private IStrategyArmory strategyArmory; @Resource private IRaffleStrategy raffleStrategy; - @Resource private RuleWeightLogicFilter ruleWeightLogicFilter; + @Resource + private RuleLockLogicFilter ruleLockLogicFilter; @Before public void setUp() { + // 策略装配 100001、100002、100003 + log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100001L)); + log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100002L)); + log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100003L)); + + // 通过反射 mock 规则中的值 ReflectionTestUtils.setField(ruleWeightLogicFilter, "userScore", 40500L); + ReflectionTestUtils.setField(ruleLockLogicFilter, "userRaffleCount", 10L); + } + + @Test + public void test() { + log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100001L)); + log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100002L)); + log.info("测试结果:{}", strategyArmory.assembleLotteryStrategy(100003L)); } + @Test public void test_performRaffle() { RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder() @@ -62,4 +83,21 @@ public class RaffleStrategyTest { 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)); + } + } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleFactorEntity.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleFactorEntity.java index 04c2a20..bdc10b4 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleFactorEntity.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleFactorEntity.java @@ -22,4 +22,6 @@ public class RaffleFactorEntity { private String userId; /** 策略ID */ private Long strategyId; + /** 奖品ID */ + private Integer awardId; } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyEntity.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyEntity.java index dfa2ee2..4bcc8c8 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyEntity.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyEntity.java @@ -7,6 +7,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.apache.commons.lang3.StringUtils; +import java.io.Serializable; + /** * @description: 策略实体 * @author: hdr @@ -17,7 +19,7 @@ import org.apache.commons.lang3.StringUtils; @Builder @AllArgsConstructor @NoArgsConstructor -public class StrategyEntity { +public class StrategyEntity implements Serializable { /** 抽奖策略ID */ private Long strategyId; @@ -33,6 +35,9 @@ public class StrategyEntity { public String getRuleWeight() { String[] ruleModels = this.ruleModels(); + if (ruleModels == null) { + return null; + } for (String ruleModel : ruleModels) { if ("rule_weight".equals(ruleModel)) return ruleModel; } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/valobj/StrategyAwardRuleModelVO.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/valobj/StrategyAwardRuleModelVO.java new file mode 100644 index 0000000..a1e56e5 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/valobj/StrategyAwardRuleModelVO.java @@ -0,0 +1,50 @@ +package cn.bugstack.domain.strategy.model.valobj; + +import cn.bugstack.domain.strategy.service.rule.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.Arrays; +import java.util.List; + +/** + * @description: 抽奖策略规则规则值对象;值对象,没有唯一ID,仅限于从数据库查询对象 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.model.valobj + * @DATE: 2024/4/16 + */ +@Getter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class StrategyAwardRuleModelVO { + + private String ruleModels; + + /** + * 获取抽奖中规则;或者使用 lambda 表达式 + *

+ * List ruleModelList = Arrays.stream(ruleModels.split(Constants.SPLIT)) + * .filter(DefaultLogicFactory.LogicModel::isCenter) + * .collect(Collectors.toList()); + * return ruleModelList; + *

+ * List collect = Arrays.stream(ruleModelValues).filter(DefaultLogicFactory.LogicModel::isCenter).collect(Collectors.toList()); + */ + + public String[] raffleCenterRuleModelList() { + List ruleModelList = new ArrayList<>(); + String[] ruleModeValues = ruleModels.split(Constants.SPLIT); + Arrays.stream(ruleModeValues).forEach(item-> { + if (DefaultLogicFactory.LogicModel.isCenter(item)) { + ruleModelList.add(item); + } + }); + + return ruleModelList.toArray(new String[0]); + } +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/repository/IStrategyRepository.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/repository/IStrategyRepository.java index 4e5d633..fd918a8 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/repository/IStrategyRepository.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/repository/IStrategyRepository.java @@ -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.StrategyEntity; import cn.bugstack.domain.strategy.model.entity.StrategyRuleEntity; +import cn.bugstack.domain.strategy.model.valobj.StrategyAwardRuleModelVO; import java.math.BigDecimal; import java.util.HashMap; @@ -76,4 +77,12 @@ public interface IStrategyRepository { * @return */ String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel); + + /** + * 查询 ruleModel + * @param strategyId + * @param awardId + * @return + */ + StrategyAwardRuleModelVO queryStrategyAwardRuleModelVO(Long strategyId, Integer awardId); } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmory.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmory.java index 280c2ae..9470d83 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmory.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmory.java @@ -8,6 +8,7 @@ import cn.bugstack.types.enums.ResponseCode; import cn.bugstack.types.exception.AppException; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -44,8 +45,7 @@ public class StrategyArmory implements IStrategyArmory, IStrategyDispatch { // 2. 权重策略陪住 - 使用于 rule_weight 权重规则配置 StrategyEntity strategyEntity = repository.queryStrategyEntityByStrategyId(strategy); - System.out.println(JSONObject.toJSONString(strategyEntity)); - if (null == strategyEntity.getRuleWeight()||null == strategyEntity) return true; + if (StringUtils.isEmpty(strategyEntity.getRuleWeight())) return true; String ruleWeight = strategyEntity.getRuleWeight(); // 2.2 查询策略规则 StrategyRuleEntity strategyRuleEntity = repository.queryStrategyRule(strategy, ruleWeight); diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/AbstractRaffleStrategy.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/AbstractRaffleStrategy.java index bdba2ba..795c79d 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/AbstractRaffleStrategy.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/AbstractRaffleStrategy.java @@ -5,6 +5,7 @@ import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity; import cn.bugstack.domain.strategy.model.entity.RuleActionEntity; import cn.bugstack.domain.strategy.model.entity.StrategyEntity; 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.service.IRaffleStrategy; import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch; @@ -53,7 +54,6 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy { .userId(userId) .strategyId(strategyId) .build(), strategy.ruleModels()); - log.info("ruleActionEntity:{}", JSON.toJSONString(ruleActionEntity)); if (RuleLogicCheckTypeVO.TAKE_OVER.getCode().equals(ruleActionEntity.getCode())) { if (DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode().equals(ruleActionEntity.getRuleModel())) { @@ -63,7 +63,6 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy { .build(); } else if (DefaultLogicFactory.LogicModel.RULE_WIGHT.getCode().equals(ruleActionEntity.getRuleModel())) { // 权重根据返回的信息进行抽奖 - System.out.println("权重抽奖"); RuleActionEntity.RaffleBeforeEntity raffleBeforeEntity = ruleActionEntity.getData(); String ruleWeightValueKey = raffleBeforeEntity.getRuleWeightValueKey(); Integer awardId = strategyDispatch.getRandomAwardId(strategyId,ruleWeightValueKey); @@ -74,13 +73,31 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy { } // 4. 默认抽奖流程 - System.out.println("默认抽奖"); Integer awardId = strategyDispatch.getRandomAwardId(strategyId); + // 5. 查询奖品规则「抽奖中(拿到奖品ID时,过滤规则)、抽奖后(扣减完奖品库存后过滤,抽奖中拦截和无库存则走兜底)」 + StrategyAwardRuleModelVO strategyAwardRuleModelVO = repository.queryStrategyAwardRuleModelVO(strategyId, awardId); + + // 6. 抽奖中 - 规则过滤 + RuleActionEntity 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() .awardId(awardId) .build(); } + protected abstract RuleActionEntity doCheckRaffleCenterLogic(RaffleFactorEntity raffleFactorEntity, String... logics); + protected abstract RuleActionEntity doCheckRaffleBeforeLogic(RaffleFactorEntity factorEntity, String... logics); } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/DefaultRaffleStrategy.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/DefaultRaffleStrategy.java index 9ae0dcb..db13df1 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/DefaultRaffleStrategy.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/DefaultRaffleStrategy.java @@ -36,9 +36,39 @@ public class DefaultRaffleStrategy extends AbstractRaffleStrategy{ public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) { super(repository, strategyDispatch); } + + @Override + protected RuleActionEntity doCheckRaffleCenterLogic(RaffleFactorEntity raffleFactorEntity, String... logics) { + if (logics == null || 0 == logics.length) return RuleActionEntity.builder() + .code(RuleLogicCheckTypeVO.ALLOW.getCode()) + .info(RuleLogicCheckTypeVO.ALLOW.getInfo()) + .build(); + + Map> logicFilterGroup = logicFactory.openLogicFilter(); + + RuleActionEntity ruleActionEntity = null; + for (String ruleModel : logics) { + ILogicFilter logicFilter = logicFilterGroup.get(ruleModel); + RuleMatterEntity ruleMatterEntity = new RuleMatterEntity(); + ruleMatterEntity.setUserId(raffleFactorEntity.getUserId()); + ruleMatterEntity.setAwardId(raffleFactorEntity.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; + } + @Override protected RuleActionEntity doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, String... logics) { + if (logics == null || 0 == logics.length) return RuleActionEntity.builder() + .code(RuleLogicCheckTypeVO.ALLOW.getCode()) + .info(RuleLogicCheckTypeVO.ALLOW.getInfo()) + .build(); log.info("raffleFactorEntity:{},logics:{}", JSON.toJSONString(raffleFactorEntity),logics); Map> logicFilterGroup = logicFactory.openLogicFilter(); diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/factory/DefaultLogicFactory.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/factory/DefaultLogicFactory.java index 4cabdff..19f9bf4 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/factory/DefaultLogicFactory.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/factory/DefaultLogicFactory.java @@ -40,13 +40,23 @@ public class DefaultLogicFactory { @AllArgsConstructor public enum LogicModel { - RULE_WIGHT("rule_weight","【抽奖前规则】根据抽奖权重返回可抽奖范围KEY"), - RULE_BLACKLIST("rule_blacklist","【抽奖前规则】黑名单规则过滤,命中黑名单则直接返回"), - + RULE_WIGHT("rule_weight", "【抽奖前规则】根据抽奖权重返回可抽奖范围KEY", "before"), + RULE_BLACKLIST("rule_blacklist", "【抽奖前规则】黑名单规则过滤,命中黑名单则直接返回", "before"), + RULE_LOCK("rule_lock", "【抽奖中规则】抽奖n次后,对应奖品可解锁抽奖", "center"), + RULE_LUCK_AWARD("rule_luck_award", "【抽奖后规则】抽奖n次后,对应奖品可解锁抽奖", "after"), ; private final String code; 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); + } } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleLockLogicFilter.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleLockLogicFilter.java new file mode 100644 index 0000000..b7e619b --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleLockLogicFilter.java @@ -0,0 +1,54 @@ +package cn.bugstack.domain.strategy.service.rule.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.service.annotation.LogicStrategy; +import cn.bugstack.domain.strategy.service.rule.ILogicFilter; +import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * @description: 用户抽奖n次后,对应奖品可解锁抽奖 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.raffle + * @DATE: 2024/4/16 + */ +@Slf4j +@Component +@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_LOCK) +public class RuleLockLogicFilter implements ILogicFilter { + + @Resource + private IStrategyRepository repository; + + // 测试数据 + private Long userRaffleCount = 0L; + + @Override + public RuleActionEntity 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()); + long raffleCount = Long.parseLong(ruleValue); + + // 用户抽奖次数大于规则限定值,规则放行 + if (userRaffleCount>= raffleCount) { + return RuleActionEntity.builder() + .code(RuleLogicCheckTypeVO.ALLOW.getCode()) + .info(RuleLogicCheckTypeVO.ALLOW.getInfo()) + .build(); + } + + // 用户抽奖次数小于规则限定值,规则拦截 + return RuleActionEntity.builder() + .code(RuleLogicCheckTypeVO.TAKE_OVER.getCode()) + .info(RuleLogicCheckTypeVO.TAKE_OVER.getInfo()) + .build(); + } +} diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyAwardDao.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyAwardDao.java index 67b6bb4..bab0f42 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyAwardDao.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyAwardDao.java @@ -22,4 +22,11 @@ public interface IStrategyAwardDao { * @return */ List queryStrategyAwardListByStrategyId(@Param("strategyId") Long strategyId); + + /** + * 查询ruleModels + * @param strategyAward + * @return + */ + String queryStrategyAwardRuleModels(StrategyAward strategyAward); } diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Award.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Award.java index 70a34e7..df8a66f 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Award.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Award.java @@ -12,6 +12,7 @@ import java.util.Date; */ @Data public class Award { + /** 自增ID */ private Long id; /** 抽奖奖品ID - 内部流转使用 */ diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/redis/RedisService.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/redis/RedisService.java index 74352dc..878819e 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/redis/RedisService.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/redis/RedisService.java @@ -102,6 +102,7 @@ public class RedisService implements IRedisService { return redissonClient.getMap(key); } + @Override public void addToMap(String key, String field, String value) { RMap map = redissonClient.getMap(key); map.put(field, value); diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/StrategyRepository.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/StrategyRepository.java index 6df15a9..061e84a 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/StrategyRepository.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/repository/StrategyRepository.java @@ -3,6 +3,7 @@ package cn.bugstack.infrastructure.persistent.repository; import cn.bugstack.domain.strategy.model.entity.StrategyAwardEntity; import cn.bugstack.domain.strategy.model.entity.StrategyEntity; 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.infrastructure.persistent.dao.IStrategyAwardDao; import cn.bugstack.infrastructure.persistent.dao.IStrategyDao; @@ -16,6 +17,7 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; @@ -55,9 +57,10 @@ public class StrategyRepository implements IStrategyRepository { public List queryStrategyAwardList(Long strategy) { // 1. 查询redis中是否有保存策略数据有的话直接返回 String cacheKey = Constants.RedisKey.STRATEGY_AWARD_KEY + strategy; - Object json = redisService.getValue(cacheKey); - List strategyAwardEntities = JSON.parseArray(json.toString(), StrategyAwardEntity.class); - if (strategyAwardEntities != null && !strategyAwardEntities.isEmpty()) { + List strategyAwardEntities = redisService.getValue(cacheKey); + + if (strategyAwardEntities != null && strategyAwardEntities.size() != 0) { +// List strategyAwardEntities = JSON.parseArray(json.toString(), StrategyAwardEntity.class); return strategyAwardEntities; } @@ -75,7 +78,7 @@ public class StrategyRepository implements IStrategyRepository { // 2.1 保存到redis中 -// redisService.setValue(cacheKey, strategyAwardEntityList); + redisService.setValue(cacheKey, strategyAwardEntityList); return strategyAwardEntityList; } @@ -103,21 +106,33 @@ public class StrategyRepository implements IStrategyRepository { public StrategyEntity queryStrategyEntityByStrategyId(Long strategyId) { // 1. 优先从缓存获取 String cacheKey = Constants.RedisKey.STRATEGY_KEY + strategyId; - Map maps = redisService.getValue(cacheKey); - StrategyEntity strategyEntity = StrategyEntity.builder() - .strategyId(Long.parseLong(maps.get("strategyId").toString())) - .strategyDesc((String) maps.get("strategyDesc")) - .ruleModels((String) maps.get("ruleModels")) - .build(); - if (null != strategyEntity) return strategyEntity; + + StrategyEntity strategyEntity = new StrategyEntity(); + StrategyEntity maps = redisService.getValue(cacheKey); + if (null != maps){ +// strategyEntity = StrategyEntity.builder() +// .strategyId(Long.parseLong(maps.get("strategyId").toString())) +// .strategyDesc((String) maps.get("strategyDesc")) +// .ruleModels((String) maps.get("ruleModels")) +// .build(); + return maps; + } // 2. 没有数据从数据库获取 Strategy strategy = strategyDao.queryStrategyByStrategyId(strategyId); - strategyEntity = StrategyEntity.builder() - .strategyId(strategy.getStrategyId()) - .strategyDesc(strategy.getStrategyDesc()) - .ruleModels(strategy.getRuleModels()) - .build(); + strategyEntity.setStrategyId(strategy.getStrategyId()); + if (StringUtils.isNotBlank(strategy.getRuleModels())) { + strategyEntity.setRuleModels(strategy.getRuleModels()); + } + strategyEntity.setStrategyDesc(strategy.getStrategyDesc()); +// = StrategyEntity.builder() +// .strategyId(strategy.getStrategyId()) +// .strategyDesc(strategy.getStrategyDesc()) +// .ruleModels(strategy.getRuleModels()) +// .build(); + + // 3. 写入缓存 + log.info("strategyEntity:{}",strategyEntity); redisService.setValue(cacheKey,strategyEntity); return strategyEntity; } @@ -152,4 +167,14 @@ public class StrategyRepository implements IStrategyRepository { return strategyRuleDao.queryStrategyRuleValue(strategyRule); } + @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(); + } + } -- GitLab