diff --git a/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_mapper.xml b/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_mapper.xml index 33ec1d55f69557e3e517e52f21cf8ee29e0a3984..c60fd389fc057c25b91d4744a11a38881ec19fb1 100644 --- a/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_mapper.xml +++ b/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_mapper.xml @@ -6,6 +6,7 @@ + @@ -15,5 +16,10 @@ from strategy limit 10 + diff --git a/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_rule_mapper.xml b/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_rule_mapper.xml index 4b3556bffdfddce8db02ae2fcad6295e3f7f3bd2..f160d79406c368130a8559f118816bbb0e182ba4 100644 --- a/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_rule_mapper.xml +++ b/xfg-frame-archetype-lite-app/src/main/resources/mybatis/mapper/strategy_rule_mapper.xml @@ -19,5 +19,10 @@ from strategy_rule limit 10 + diff --git a/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyTest.java b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyTest.java index 665bde5f83a12899b85bef9379605b562dd321c2..0cd9ee11cd4e089b44d951ca79402e1451e75527 100644 --- a/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyTest.java +++ b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyTest.java @@ -1,8 +1,10 @@ package cn.bugstack.test.domain; import cn.bugstack.domain.strategy.service.armory.IStrategyArmory; +import cn.bugstack.domain.strategy.service.armory.IStrategyDispatch; import cn.bugstack.infrastructure.persistent.redis.IRedisService; import lombok.extern.slf4j.Slf4j; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.redisson.api.RMap; @@ -25,21 +27,34 @@ public class StrategyTest { @Resource private IStrategyArmory strategyArmory; + @Resource + private IStrategyDispatch strategyDispatch; + /** * 策略ID;100001L、100002L 装配的时候创建策略表写入到 Redis Map 中 */ @Test public void test_strategyArmory() { - strategyArmory.assembleLotteryStrategy(100002L); - log.info("测试结果:{}"); + boolean success = strategyArmory.assembleLotteryStrategy(100001L); + log.info("测试结果:{}", success); } /** * 从装配的策略中随机获取奖品ID值 */ @Test - public void test_getAssembleRandomVal() { - log.info("测试结果:{} - 奖品ID值", strategyArmory.getRandomAwardId(100002L)); + public void test_getRandomAwardId() { + log.info("测试结果:{} - 奖品ID值", strategyDispatch.getRandomAwardId(100001L)); + } + + /** + * 根据策略ID+权重值,从装配的策略中随机获取奖品ID值 + */ + @Test + public void test_getRandomAwardId_ruleWeightValue() { + log.info("测试结果:{} - 4000 策略配置", strategyDispatch.getRandomAwardId(100001L, "4000:102,103,104,105")); + log.info("测试结果:{} - 5000 策略配置", strategyDispatch.getRandomAwardId(100001L, "5000:102,103,104,105,106,107")); + log.info("测试结果:{} - 6000 策略配置", strategyDispatch.getRandomAwardId(100001L, "6000:102,103,104,105,106,107,108,109")); } @Resource @@ -90,4 +105,5 @@ public class StrategyTest { } } + } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyAwardEntity.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyAwardEntity.java index 85416c3d410e3acf26e6a7ecad37d4a0ab21c637..d05e8caad1aa3b5bed52435f1a6f6e86f15c0581 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyAwardEntity.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyAwardEntity.java @@ -5,6 +5,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.io.Serializable; import java.math.BigDecimal; /** @@ -17,7 +18,7 @@ import java.math.BigDecimal; @Builder @AllArgsConstructor @NoArgsConstructor -public class StrategyAwardEntity { +public class StrategyAwardEntity implements Serializable { /** 抽奖策略ID */ private Long strategyId; /** 抽奖奖品ID - 内部流转使用 */ 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 new file mode 100644 index 0000000000000000000000000000000000000000..dfa2ee2a26daf2a369be566ef5f1c1b067596113 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyEntity.java @@ -0,0 +1,42 @@ +package cn.bugstack.domain.strategy.model.entity; + +import cn.bugstack.types.common.Constants; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; + +/** + * @description: 策略实体 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.model.entity + * @DATE: 2024/4/9 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class StrategyEntity { + + /** 抽奖策略ID */ + private Long strategyId; + /** 抽奖策略描述 */ + private String strategyDesc; + /** 抽奖规则模型 rule_weight,rule_blacklist */ + private String ruleModels; + + public String[] ruleModels() { + if (StringUtils.isBlank(ruleModels)) return null; + return ruleModels.split(Constants.SPLIT); + } + + public String getRuleWeight() { + String[] ruleModels = this.ruleModels(); + for (String ruleModel : ruleModels) { + if ("rule_weight".equals(ruleModel)) return ruleModel; + } + return null; + } + +} diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyRuleEntity.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyRuleEntity.java new file mode 100644 index 0000000000000000000000000000000000000000..748d3645e89d9f93d6ff63c02f1df66f2cd9b1b2 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyRuleEntity.java @@ -0,0 +1,70 @@ +package cn.bugstack.domain.strategy.model.entity; + +import cn.bugstack.types.common.Constants; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @description: + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.model.entity + * @DATE: 2024/4/9 + */ +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class StrategyRuleEntity { + + /** 抽奖策略ID */ + private Long strategyId; + /** 抽奖奖品ID【规则类型为策略,则不需要奖品ID】 */ + private Integer awardId; + /** 抽象规则类型;1-策略规则、2-奖品规则 */ + private Integer ruleType; + /** 抽奖规则类型【rule_random - 随机值计算、rule_lock - 抽奖几次后解锁、rule_luck_award - 幸运奖(兜底奖品)】 */ + private String ruleModel; + /** 抽奖规则比值 */ + private String ruleValue; + /** 抽奖规则描述 */ + private String ruleDesc; + + /** + * 获取权重值 + * 数据案例;4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108,109 + */ + public Map> getRuleWeightValues() { + if (!"rule_weight".equals(ruleModel)) return null; + String[] ruleValueGroups = ruleValue.split(Constants.SPACE); + Map> resultMap = new HashMap<>(); + for (String ruleValueGroup : ruleValueGroups) { + // 检查输入是否为空 + if (ruleValueGroup == null || ruleValueGroup.isEmpty()) { + return resultMap; + } + // 分割字符串以获取键和值 + String[] parts = ruleValueGroup.split(Constants.COLON); + if (parts.length != 2) { + throw new IllegalArgumentException("rule_weight rule_rule invalid input format" + ruleValueGroup); + } + // 解析值 + String[] valueStrings = parts[1].split(Constants.SPLIT); + List values = new ArrayList<>(); + for (String valueString : valueStrings) { + values.add(Integer.parseInt(valueString)); + } + // 将键和值放入Map中 + resultMap.put(ruleValueGroup, values); + } + + return resultMap; + } + +} 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 07d3a95f6fc30c18a0c56ac578252e4f83bb4731..d0908f65aa14649979a548576955427d069c5d0e 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 @@ -1,6 +1,8 @@ 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 java.math.BigDecimal; import java.util.HashMap; @@ -23,11 +25,11 @@ public interface IStrategyRepository { List queryStrategyAwardList(Long strategy); /** - * @param strategyId 策略id + * @param key 策略id * @param rateRange 概率 * @param shuffleStrategyAwardSearchRateTables 所有保存的概率 */ - void storeStrategyAwardSearchRateTables(Long strategyId, Integer rateRange, HashMap shuffleStrategyAwardSearchRateTables); + void storeStrategyAwardSearchRateTables(String key, Integer rateRange, HashMap shuffleStrategyAwardSearchRateTables); /** * @@ -37,10 +39,32 @@ public interface IStrategyRepository { int getRandomAwardId(Long strategyId); /** - * 获取哦奖品id - * @param strategyId + * 获取奖品id + * @param key * @param nextInt * @return */ - Integer getStrategyAwardAssemble(Long strategyId, int nextInt); + Integer getStrategyAwardAssemble(String key, int nextInt); + + /** + * 获取抽奖策略 + * @param strategy 策略id + * @return + */ + StrategyEntity queryStrategyEntityByStrategyId(Long strategy); + + /** + * 查询抽奖策略规则 + * @param strategy 策略id + * @param ruleWeight 策略id + * @return + */ + StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleWeight); + + /** + * 获取概率值 + * @param key + * @return + */ + int getRateRange(String key); } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyArmory.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyArmory.java index de41f534bee6d750d1a472d59b430e22ffc0f868..afce43cd820d55f6af1c75192eac21213b0972b5 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyArmory.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyArmory.java @@ -12,12 +12,7 @@ public interface IStrategyArmory { * 抽奖策略 * @param strategy */ - void assembleLotteryStrategy(Long strategy); + boolean assembleLotteryStrategy(Long strategy); + - /** - * 获取随机奖品id - * @param strategyId - * @return - */ - Integer getRandomAwardId(Long strategyId); } diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyDispatch.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyDispatch.java new file mode 100644 index 0000000000000000000000000000000000000000..da2be9f729328805c59e91f6d32ad8e2e1eb5602 --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyDispatch.java @@ -0,0 +1,24 @@ +package cn.bugstack.domain.strategy.service.armory; + +/** + * @description: 策略抽奖调度 + * @author: hdr + * @PACKAGE_NAME: cn.bugstack.domain.strategy.service.armory + * @DATE: 2024/4/8 + */ +public interface IStrategyDispatch { + /** + * 获取随机奖品id + * @param strategyId + * @return + */ + Integer getRandomAwardId(Long strategyId); + + /** + * 随机获取奖品 + * @param strategyId + * @param ruleWeightValue + * @return + */ + Integer getRandomAwardId(Long strategyId, String ruleWeightValue); +} 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 437338011ea6bf9f3ea1196e5d18d733290fe0af..280c2aec68f9c19c060873863281711e172e303d 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 @@ -1,7 +1,12 @@ package cn.bugstack.domain.strategy.service.armory; 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.repository.IStrategyRepository; +import cn.bugstack.types.enums.ResponseCode; +import cn.bugstack.types.exception.AppException; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -10,7 +15,6 @@ import java.math.BigDecimal; import java.math.RoundingMode; import java.security.SecureRandom; import java.util.*; -import java.util.stream.Collectors; /** * @description: @@ -20,28 +24,60 @@ import java.util.stream.Collectors; */ @Slf4j @Service -public class StrategyArmory implements IStrategyArmory { +public class StrategyArmory implements IStrategyArmory, IStrategyDispatch { @Autowired private IStrategyRepository repository; + public static void main(String[] args) { + StrategyArmory strategyArmory = new StrategyArmory(); + strategyArmory.assembleLotteryStrategy(100001L); + } + @Override - public void assembleLotteryStrategy(Long strategy) { + public boolean assembleLotteryStrategy(Long strategy) { // 1. 查询策略配置 List awardEntityList = repository.queryStrategyAwardList(strategy); + assembleLotteryStrategy(String.valueOf(strategy),awardEntityList); + + // 2. 权重策略陪住 - 使用于 rule_weight 权重规则配置 + StrategyEntity strategyEntity = repository.queryStrategyEntityByStrategyId(strategy); + + System.out.println(JSONObject.toJSONString(strategyEntity)); + if (null == strategyEntity.getRuleWeight()||null == strategyEntity) return true; + String ruleWeight = strategyEntity.getRuleWeight(); + // 2.2 查询策略规则 + StrategyRuleEntity strategyRuleEntity = repository.queryStrategyRule(strategy, ruleWeight); + if (null == strategyRuleEntity) { + throw new AppException(ResponseCode.STRATEGY_RULE_WEIGHT_IS_NULL.getCode(), ResponseCode.STRATEGY_RULE_WEIGHT_IS_NULL.getInfo()); + } + Map> ruleWeightValueMap = strategyRuleEntity.getRuleWeightValues(); + Set keys = ruleWeightValueMap.keySet(); + // 2.3 将获取到的所有 规则写入缓存 + for (String key : keys) { + List ruleWeightValues = ruleWeightValueMap.get(key); + ArrayList strategyAwardEntitiesClone = new ArrayList<>(awardEntityList); + strategyAwardEntitiesClone.removeIf(entity -> !ruleWeightValues.contains(entity.getAwardId())); + assembleLotteryStrategy(String.valueOf(strategy).concat("_").concat(key), strategyAwardEntitiesClone); + } + return true; - // 2. 获取最小概率值 - BigDecimal minAwardRate = awardEntityList.stream().map(StrategyAwardEntity::getAwardRate) + } + + private void assembleLotteryStrategy(String key,List awardEntityList) { + // 1. 获取最小概率值 + BigDecimal minAwardRate = awardEntityList.stream() + .map(StrategyAwardEntity::getAwardRate) .min(BigDecimal::compareTo) .orElse(BigDecimal.ZERO); - // 3. 获取概率值总和 + // 2. 获取概率值总和 BigDecimal totalAwardRate = awardEntityList.stream() .map(StrategyAwardEntity::getAwardRate) .reduce(BigDecimal.ZERO, BigDecimal::add); - // 4. 用 1% 0.001获取概率范围,百分位、千分位、万分位 + // 3. 用 1% 0.001获取概率范围,百分位、千分位、万分位 BigDecimal rateRange = totalAwardRate.divide(minAwardRate, 0, RoundingMode.CEILING); @@ -50,34 +86,37 @@ public class StrategyArmory implements IStrategyArmory { Integer awardId = strategyAwardEntity.getAwardId(); BigDecimal awardRate = strategyAwardEntity.getAwardRate(); - // 5. 计算出每个概率值需要存储到查找表的数量,循环填充 - - log.info("rateRange.multiply(awardRate).setScale(0, RoundingMode.CEILING).intValue()"+rateRange.multiply(awardRate).setScale(0, RoundingMode.CEILING).intValue()); + // 4. 计算出每个概率值需要存储到查找表的数量,循环填充 for (int i = 0; i < rateRange.multiply(awardRate).setScale(0, RoundingMode.CEILING).intValue(); i++) { strategyAwardSearchRateTables.add(awardId); } - // 6. 乱序 + // 5. 乱序 Collections.shuffle(strategyAwardSearchRateTables); - // 7. + // 6. 组装抽奖表 HashMap shuffleStrategyAwardSearchRateTables = new HashMap<>(); for (int i = 0; i < strategyAwardSearchRateTables.size(); i++) { shuffleStrategyAwardSearchRateTables.put(i, (Integer) strategyAwardSearchRateTables.get(i)); } - log.info(shuffleStrategyAwardSearchRateTables.size()+""); - // 8. 存储到 redis中 - repository.storeStrategyAwardSearchRateTables(strategy,shuffleStrategyAwardSearchRateTables.size(), shuffleStrategyAwardSearchRateTables); + // 7. 存储到 redis中 + repository.storeStrategyAwardSearchRateTables(key,shuffleStrategyAwardSearchRateTables.size(), shuffleStrategyAwardSearchRateTables); } - - - } @Override public Integer getRandomAwardId(Long strategyId) { int rateRange = repository.getRandomAwardId(strategyId); - return repository.getStrategyAwardAssemble(strategyId,new SecureRandom().nextInt(rateRange)); + return repository.getStrategyAwardAssemble(String.valueOf(strategyId),new SecureRandom().nextInt(rateRange)); + } + + @Override + public Integer getRandomAwardId(Long strategyId, String ruleWeightValue) { + String key = String.valueOf(strategyId).concat("_").concat(ruleWeightValue); + // 分布式部署下,不一定为当前应用做的策略装配。也就是值不一定会保存到本应用,而是分布式应用,所以需要从 Redis 中获取。 + int rateRange = repository.getRateRange(key); + // 通过生成的随机值,获取概率值奖品查找表的结果 + return repository.getStrategyAwardAssemble(key, new SecureRandom().nextInt(rateRange)); } } diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyDao.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyDao.java index 4d2cc6cf0e01ea2f0bb630bc6b40184e77e7ba13..4159f8c0d573431132d1e6172cd77e564070a2e2 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyDao.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyDao.java @@ -2,6 +2,7 @@ package cn.bugstack.infrastructure.persistent.dao; import cn.bugstack.infrastructure.persistent.po.Strategy; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -15,4 +16,10 @@ public interface IStrategyDao { List queryStrategyList(); + /** + * 通过策略id查询策略 + * @param strategyId 策略id + * @return + */ + Strategy queryStrategyByStrategyId(@Param("strategyId") Long strategyId); } diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyRuleDao.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyRuleDao.java index 53068717f94102b83050c513b7028b39f9ee8d04..d37bbe74127db6dd5c6fe1ad15721b6c98749274 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyRuleDao.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/dao/IStrategyRuleDao.java @@ -15,4 +15,10 @@ public interface IStrategyRuleDao { List queryStrategyRuleList(); + /** + * 策略规则和策略id查询 + * @param strategyRuleReq + * @return + */ + StrategyRule queryStrategyRule(StrategyRule strategyRuleReq); } diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Strategy.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Strategy.java index 017dd7659477fe430484b79dfab47cccd76100dd..3f2e16ecef9d370cf36afb67b3332f1978049e92 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Strategy.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/Strategy.java @@ -19,6 +19,8 @@ public class Strategy { private Long strategyId; /** 抽奖策略描述 */ private String strategyDesc; + /** 抽奖规则模型 rule_weight,rule_blacklist */ + private String ruleModels; /** 创建时间 */ private Date createTime; /** 更新时间 */ 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 fc41464014eba7a16b7c29552391b9f1e146df89..40069d7d98df4b0201a404dc39e7da9f5c4eb34a 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 @@ -1,19 +1,27 @@ 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.repository.IStrategyRepository; import cn.bugstack.infrastructure.persistent.dao.IStrategyAwardDao; +import cn.bugstack.infrastructure.persistent.dao.IStrategyDao; +import cn.bugstack.infrastructure.persistent.dao.IStrategyRuleDao; +import cn.bugstack.infrastructure.persistent.po.Strategy; import cn.bugstack.infrastructure.persistent.po.StrategyAward; +import cn.bugstack.infrastructure.persistent.po.StrategyRule; import cn.bugstack.infrastructure.persistent.redis.IRedisService; -import cn.bugstack.infrastructure.persistent.redis.RedisService; import cn.bugstack.types.common.Constants; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; import lombok.extern.slf4j.Slf4j; -import org.redisson.misc.Hash; +import org.apache.commons.lang3.ObjectUtils; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Repository; -import org.springframework.stereotype.Service; -import java.math.BigDecimal; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -35,11 +43,20 @@ public class StrategyRepository implements IStrategyRepository { @Autowired private IRedisService redisService; + + @Autowired + private IStrategyDao strategyDao; + + @Autowired + private IStrategyRuleDao strategyRuleDao; + + @Override public List queryStrategyAwardList(Long strategy) { // 1. 查询redis中是否有保存策略数据有的话直接返回 String cacheKey = Constants.RedisKey.STRATEGY_AWARD_KEY + strategy; - List strategyAwardEntities = redisService.getValue(cacheKey); + Object json = redisService.getValue(cacheKey); + List strategyAwardEntities = JSON.parseArray(json.toString(), StrategyAwardEntity.class); if (strategyAwardEntities != null && !strategyAwardEntities.isEmpty()) { return strategyAwardEntities; } @@ -57,28 +74,73 @@ public class StrategyRepository implements IStrategyRepository { }).collect(Collectors.toList()); // 2.1 保存到redis中 - redisService.setValue(cacheKey,strategyAwardEntityList); + +// redisService.setValue(cacheKey, strategyAwardEntityList); return strategyAwardEntityList; } @Override - public void storeStrategyAwardSearchRateTables(Long strategyId, Integer rateRange, HashMap shuffleStrategyAwardSearchRateTables) { + public void storeStrategyAwardSearchRateTables(String key, Integer rateRange, HashMap shuffleStrategyAwardSearchRateTables) { // 1. 存储概率值 - redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId, rateRange.intValue()); + redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, rateRange.intValue()); // 2. 存储概率查找表 - Map cacheRateTable = redisService.getMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + strategyId); + Map cacheRateTable = redisService.getMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key); cacheRateTable.putAll(shuffleStrategyAwardSearchRateTables); } @Override public int getRandomAwardId(Long strategyId) { - return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId); + return getRateRange(String.valueOf(strategyId)); + } + + @Override + public Integer getStrategyAwardAssemble(String key, int nextInt) { + return redisService.getFromMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key,nextInt); + } + + @Override + 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; + // 2. 没有数据从数据库获取 + Strategy strategy = strategyDao.queryStrategyByStrategyId(strategyId); + strategyEntity = StrategyEntity.builder() + .strategyId(strategy.getStrategyId()) + .strategyDesc(strategy.getStrategyDesc()) + .ruleModels(strategy.getRuleModels()) + .build(); + // 3. 写入缓存 + redisService.setValue(cacheKey,strategyEntity); + return strategyEntity; + } + + @Override + public StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleModel) { + StrategyRule strategyRuleReq = new StrategyRule(); + strategyRuleReq.setStrategyId(strategyId); + strategyRuleReq.setRuleModel(ruleModel); + StrategyRule strategyRuleRes = strategyRuleDao.queryStrategyRule(strategyRuleReq); + return StrategyRuleEntity.builder() + .strategyId(strategyRuleRes.getStrategyId()) + .awardId(strategyRuleRes.getAwardId()) + .ruleType(strategyRuleRes.getRuleType()) + .ruleModel(strategyRuleRes.getRuleModel()) + .ruleValue(strategyRuleRes.getRuleValue()) + .ruleDesc(strategyRuleRes.getRuleDesc()) + .build(); } @Override - public Integer getStrategyAwardAssemble(Long strategyId, int nextInt) { - return redisService.getFromMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + strategyId,nextInt); + public int getRateRange(String key) { + return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key); } } diff --git a/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/common/Constants.java b/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/common/Constants.java index 008bc32b0ba0ae1a280531c7528f15fd4107ef46..0c21914eefa30758b56af35ab298e2b6b03483e8 100644 --- a/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/common/Constants.java +++ b/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/common/Constants.java @@ -3,8 +3,11 @@ package cn.bugstack.types.common; public class Constants { public final static String SPLIT = ","; + public final static String COLON = ":"; + public final static String SPACE = " "; public static class RedisKey { + public static final String STRATEGY_KEY = "big_market_strategy_key_"; public static String STRATEGY_AWARD_KEY = "big_market_strategy_award_key_"; public static String STRATEGY_RATE_TABLE_KEY = "big_market_strategy_rate_table_key_"; public static String STRATEGY_RATE_RANGE_KEY = "big_market_strategy_rate_range_key_"; diff --git a/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/enums/ResponseCode.java b/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/enums/ResponseCode.java index 7460d4b0cfdc6c3c82e27089338ef10bf0c40ef1..e9015360ba82ebde99bfee1f49a74e252dcb25cb 100644 --- a/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/enums/ResponseCode.java +++ b/xfg-frame-archetype-lite-types/src/main/java/cn/bugstack/types/enums/ResponseCode.java @@ -12,6 +12,7 @@ public enum ResponseCode { SUCCESS("0000", "成功"), UN_ERROR("0001", "未知失败"), ILLEGAL_PARAMETER("0002", "非法参数"), + STRATEGY_RULE_WEIGHT_IS_NULL("ERR_BIZ_001", "业务异常,策略规则中 rule_weight 权重规则已适用但未配置") ; private String code;