diff --git a/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/LogicChainTest.java b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/LogicChainTest.java new file mode 100644 index 0000000000000000000000000000000000000000..3c007ee9803ff62136c41caa28595cd6d1a6244f --- /dev/null +++ b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/LogicChainTest.java @@ -0,0 +1,67 @@ +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; + +/** + * @author Fuzhengwei bugstack.cn @小傅哥 + * @description 抽奖责任链测试,验证不同的规则走不同的责任链 + * @create 2024-01-20 11:20 + */ +@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(100003L); + Integer awardId = logicChain.logic("user001", 100003L); + 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); + } + +} 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 002af8d5b005ca6050fc638d7c7ff4fd98850078..65d0b14cd799e0f30d35dff66ec0edcd5073fb45 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 @@ -4,9 +4,8 @@ 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 cn.bugstack.domain.strategy.service.rule.filter.impl.RuleLockLogicFilter; +import cn.bugstack.domain.strategy.service.rule.filter.impl.RuleWeightLogicFilter; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.junit.Before; @@ -74,7 +73,7 @@ public class RaffleStrategyTest { public void test_performRaffle_blacklist() { RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder() .userId("user003") // 黑名单用户 user001,user002,user003 - .strategyId(100001L) + .strategyId(100003L) .build(); RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(raffleFactorEntity); 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 index a1e56e5e2145b292eabb43c069b8bab8e470abc6..0b480b3d410a64944cdffeb2fd42dd257ebfb0d1 100644 --- 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 @@ -1,6 +1,6 @@ package cn.bugstack.domain.strategy.model.valobj; -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.AllArgsConstructor; import lombok.Builder; 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 fd918a8a3e021581879acc768f608b93a218d606..0119b67e722851a97258921a15a6262e6e05c349 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 @@ -69,6 +69,14 @@ public interface IStrategyRepository { */ int getRateRange(String key); + /** + * 查询策略规则值 + * @param strategyId 策略jd + * @param ruleModel 奖品id + * @return 策略规则 + */ + String queryStrategyRuleValue(Long strategyId, String ruleModel); + /** * 查询策略规则值 * @param strategyId 策略id diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/annotation/LogicStrategy.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/annotation/LogicStrategy.java index 7a5d9ea7ff771da5f99b815e44d013ae8500d207..5bd418b1b969eb5095eed5060f5a46f829864893 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/annotation/LogicStrategy.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/annotation/LogicStrategy.java @@ -1,6 +1,6 @@ package cn.bugstack.domain.strategy.service.annotation; -import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory; +import cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; 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 795c79dbe32b0b4102c6ee4518d6957a62eac2e8..30d23185e03e92118c19f7a04432456a28afa594 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 @@ -9,11 +9,11 @@ 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; -import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory; -import cn.bugstack.domain.strategy.service.rule.impl.RuleBackListLogicFilter; +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.filter.factory.DefaultLogicFactory; import cn.bugstack.types.enums.ResponseCode; import cn.bugstack.types.exception.AppException; -import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -30,10 +30,13 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy { protected IStrategyRepository repository; // 策略调度服务 -> 只负责抽奖处理,通过新增接口的方式,隔离职责,不需要使用方关心或者调用抽奖的初始化 protected IStrategyDispatch strategyDispatch; + // 抽奖的职责链 -> 抽奖的规则中,解耦出前置规则为职责链处理 + protected final DefaultChainFactory defaultChainFactory; - public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) { + public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory) { this.repository = repository; this.strategyDispatch = strategyDispatch; + this.defaultChainFactory = defaultChainFactory; } @Override @@ -46,6 +49,13 @@ public abstract class AbstractRaffleStrategy implements IRaffleStrategy { throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo()); } +// // 2. 获取抽奖职责链 -> 前置规则的责任链处理 +// ILogicChain logicChain = defaultChainFactory.openLogicChain(strategyId); +// +// // 3. 通过职责链获取,获奖id +// Integer awardId = logicChain.logic(userId, strategyId); + + // 2. 策略查询 StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId) ; 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 db13df1f5ce25ae27b9016dbfd55f6d239d22aea..ce9b4d4980bb315beed940306da502d6c7c7a347 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 @@ -7,9 +7,9 @@ import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO; import cn.bugstack.domain.strategy.repository.IStrategyRepository; import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch; import cn.bugstack.domain.strategy.service.rule.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 com.alibaba.fastjson.JSON; -import com.sun.deploy.security.ruleset.RuleAction; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -33,8 +33,8 @@ public class DefaultRaffleStrategy extends AbstractRaffleStrategy{ @Resource private DefaultLogicFactory logicFactory; - public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) { - super(repository, strategyDispatch); + public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch, DefaultChainFactory defaultChainFactory) { + super(repository, strategyDispatch, defaultChainFactory); } @Override diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/AbstractLogicChain.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/AbstractLogicChain.java new file mode 100644 index 0000000000000000000000000000000000000000..f9c63be6a59d65f9cd63f7d4f130475472152424 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/AbstractLogicChain.java @@ -0,0 +1,29 @@ +package cn.bugstack.domain.strategy.service.rule.chain; + +import lombok.extern.slf4j.Slf4j; + +/** + * @description: 抽奖策略责任链,判断走那种抽奖策略。如;默认抽象、权重抽奖、黑名单抽奖 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.chain + * @DATE: 2024/4/19 + */ +@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(); +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/ILogicChain.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/ILogicChain.java new file mode 100644 index 0000000000000000000000000000000000000000..a9761bb6543c781814b654cd334cd2d112bc6df8 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/ILogicChain.java @@ -0,0 +1,19 @@ +package cn.bugstack.domain.strategy.service.rule.chain; + +/** + * @description: 抽奖策略规则责任链接口 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.chain + * @DATE: 2024/4/19 + */ +public interface ILogicChain extends ILogicChainArmory { + + /** + * 责任链接口 + * + * @param userId 用户id + * @param strategyId 策略id + * @return 奖品id + */ + Integer logic(String userId, Long strategyId); +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/ILogicChainArmory.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/ILogicChainArmory.java new file mode 100644 index 0000000000000000000000000000000000000000..a25c970a4c7480aa524c8a3b7351d468baa80b3e --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/ILogicChainArmory.java @@ -0,0 +1,14 @@ +package cn.bugstack.domain.strategy.service.rule.chain; + +/** + * @description: 责任链装配 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.chain + * @DATE: 2024/4/19 + */ +public interface ILogicChainArmory { + + ILogicChain next(); + + ILogicChain appendNext(ILogicChain next); +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/factory/DefaultChainFactory.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/factory/DefaultChainFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..9e638e0284dc06a26e2c2dd73198fced8382b62a --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/factory/DefaultChainFactory.java @@ -0,0 +1,50 @@ +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; + +/** + * @description: 装配工厂 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.chain.factory + * @DATE: 2024/4/19 + */ +@Service +public class DefaultChainFactory { + + private final Map logicChainGroup; + + protected IStrategyRepository repository; + + + public DefaultChainFactory(Map logicChainGroup, IStrategyRepository repository) { + this.logicChainGroup = logicChainGroup; + this.repository = repository; + } + + 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.appendNext(logicChainGroup.get("default")); + + return logicChain; + } + +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/BackListLogicChain.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/BackListLogicChain.java new file mode 100644 index 0000000000000000000000000000000000000000..65be467878d6e83e423249bdb8100c0fe7006465 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/BackListLogicChain.java @@ -0,0 +1,54 @@ +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; + +/** + * @description: + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.chain.impl + * @DATE: 2024/4/19 + */ +@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"; + } + +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/DefaultLogicChain.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/DefaultLogicChain.java new file mode 100644 index 0000000000000000000000000000000000000000..595e30cf8b96b52fbd41d118a56e3fdb9863d981 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/DefaultLogicChain.java @@ -0,0 +1,34 @@ +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; + +/** + * @description: 默认的责任链「最为最后一个链」 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.chain.impl + * @DATE: 2024/4/19 + */ +@Slf4j +@Component("default") +public class DefaultLogicChain extends AbstractLogicChain { + + @Resource + protected IStrategyDispatch strategyDispatch; + + @Override + protected String ruleModel() { + return "default"; + } + + @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; + } +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/RuleWeightLogicChain.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/RuleWeightLogicChain.java new file mode 100644 index 0000000000000000000000000000000000000000..ee0b8bce1a8dc93d26f1c05f8bf012fe93744109 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/chain/impl/RuleWeightLogicChain.java @@ -0,0 +1,97 @@ +package cn.bugstack.domain.strategy.service.rule.chain.impl; + +import cn.bugstack.domain.strategy.repository.IStrategyRepository; +import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch; +import cn.bugstack.domain.strategy.service.rule.chain.AbstractLogicChain; +import cn.bugstack.types.common.Constants; +import com.alibaba.fastjson.JSON; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; +import java.util.*; + +/** + * @description: + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.chain.impl + * @DATE: 2024/4/19 + */ +@Slf4j +@Component("rule_weight") +public class RuleWeightLogicChain extends AbstractLogicChain { + + @Resource + private IStrategyRepository repository; + + @Resource + private IStrategyDispatch strategyDispatch; + + public Long userScore = 0L; + + @Override + protected String ruleModel() { + return "rule_weight"; + } + + /** + * 权重责任链过滤; + * 1. 权重规则格式;4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108,109 + * 2. 解析数据格式;判断哪个范围符合用户的特定抽奖范围 + */ + @Override + public Integer logic(String userId, Long strategyId) { + log.info("抽奖责任链-权重开始 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel()); + + String ruleValue = repository.queryStrategyRuleValue(strategyId, ruleModel()); + + // 1. 根据用户ID查询用户抽奖小号的积分值 + Map analyticalValueGroup = getAnalyticalValue(ruleValue); + if (null == analyticalValueGroup || analyticalValueGroup.isEmpty()) { + return null; + } + + // 2. 装换keys值,并默认排序 + List analyticalSortedKeys = new ArrayList<>(analyticalValueGroup.keySet()); + Collections.sort(analyticalSortedKeys); + + // 3. 找出最小符合的值,也就是【4500 积分,能找到 4000:102,103,104,105】、【5000 积分,能找到 5000:102,103,104,105,106,107】 + Long nextValue = analyticalSortedKeys.stream() + .sorted(Comparator.reverseOrder()) + .filter(analyticalSortedKeyValue-> userScore >= analyticalSortedKeyValue) + .findFirst() + .orElse(null); + + // 4. 权重抽奖 + if (null != nextValue) { + Integer awardId = strategyDispatch.getRandomAwardId(strategyId, analyticalValueGroup.get(nextValue)); + log.info("抽奖责任链-权重接管 userId: {} strategyId: {} ruleModel: {} awardId: {}", userId, strategyId, ruleModel(), awardId); + return awardId; + } + + // 5. 过滤其他责任链 + log.info("抽奖责任链-权重放行 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel()); + return next().logic(userId, strategyId); + } + + private Map getAnalyticalValue(String ruleValue) { + String[] ruleGroups = ruleValue.split(Constants.SPACE); + log.info("ruleGroups:{}",ruleGroups); + Map ruleValueMap = new HashMap<>(); + for (String ruleValueKey : ruleGroups) { + // 判断是否有值 + if (ruleValueKey == null || ruleValueKey.isEmpty()) { + return ruleValueMap; + } + // 分割字符串以获取键和值 + String[] parts = ruleValueKey.split(Constants.COLON); + log.info("parts:{},ruleValue:{}", JSON.toJSONString(parts),ruleValue); + if (parts.length < 2) { + throw new IllegalArgumentException("rule_weight rule_rule invalid input format" + ruleValueKey); + } + ruleValueMap.put(Long.parseLong(parts[0]), ruleValueKey); + } + return ruleValueMap; + + } +} 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/filter/factory/DefaultLogicFactory.java similarity index 93% rename from xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/factory/DefaultLogicFactory.java rename to xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/factory/DefaultLogicFactory.java index 19f9bf46c1f27a7c8d339301ca0bd3aef02dbcb5..4cc891d57294248cf25cca8d888c718d5e13077b 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/filter/factory/DefaultLogicFactory.java @@ -1,4 +1,4 @@ -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.service.annotation.LogicStrategy; @@ -15,7 +15,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * @description: 规则工厂 * @author: hdr - * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.factory + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.filter.factory * @DATE: 2024/4/12 */ @Service @@ -57,7 +57,6 @@ public class DefaultLogicFactory { 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/RuleBackListLogicFilter.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/impl/RuleBackListLogicFilter.java similarity index 92% rename from xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleBackListLogicFilter.java rename to xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/impl/RuleBackListLogicFilter.java index 934bd7c3b62ba2c7ac6df8c6112d286af1728780..4d1c7283505854633f72ac6f227d802c6936b331 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleBackListLogicFilter.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/impl/RuleBackListLogicFilter.java @@ -1,4 +1,4 @@ -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.RuleMatterEntity; @@ -6,7 +6,7 @@ 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 cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory; import cn.bugstack.types.common.Constants; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -16,7 +16,7 @@ import javax.annotation.Resource; /** * @description: [抽奖前规则]黑名单用户过滤规则 * @author: hdr - * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.impl + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.filter.impl * @DATE: 2024/4/12 */ @Slf4j 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/filter/impl/RuleLockLogicFilter.java similarity index 93% rename from xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleLockLogicFilter.java rename to xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/impl/RuleLockLogicFilter.java index b7e619ba7c5b82cc4aa40424a19289336de0c785..2aa5a0a33e7dbcdcf77fac02e404995940bb71d2 100644 --- 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/filter/impl/RuleLockLogicFilter.java @@ -1,4 +1,4 @@ -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.RuleMatterEntity; @@ -6,7 +6,7 @@ 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 cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleWeightLogicFilter.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/impl/RuleWeightLogicFilter.java similarity index 95% rename from xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleWeightLogicFilter.java rename to xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/impl/RuleWeightLogicFilter.java index a8a51a7d214a9af9bf20ebbbf984cb823eaf4522..471e807123f3d9ec3329f0e66e5a9e71374119fa 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleWeightLogicFilter.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/filter/impl/RuleWeightLogicFilter.java @@ -1,4 +1,4 @@ -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.RuleMatterEntity; @@ -6,7 +6,7 @@ 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 cn.bugstack.domain.strategy.service.rule.filter.factory.DefaultLogicFactory; import cn.bugstack.types.common.Constants; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -17,7 +17,7 @@ import java.util.*; /** * @description: [抽奖前规则] 根据抽奖鉴权重返可抽奖范围key * @author: hdr - * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.impl + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.rule.filter.impl * @DATE: 2024/4/12 */ @Slf4j 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 061e84a4bdd6f1fa696bef99c14d2a206714d781..843c514b895ff05d5596e99129bd974c85a56efc 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 @@ -158,6 +158,11 @@ public class StrategyRepository implements IStrategyRepository { return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key); } + @Override + public String queryStrategyRuleValue(Long strategyId, String ruleModel) { + return queryStrategyRuleValue(strategyId, null, ruleModel); + } + @Override public String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel) { StrategyRule strategyRule = new StrategyRule();