From b647fac1fbac6e6f18b9f2abf727a51727836895 Mon Sep 17 00:00:00 2001
From: yongfeng <2283865573@qq.com>
Date: Sun, 17 Nov 2024 17:53:43 +0800
Subject: [PATCH] =?UTF-8?q?=E7=AD=96=E7=95=A5=E6=9D=83=E9=87=8D=E6=A6=82?=
=?UTF-8?q?=E7=8E=87=E8=A3=85=E9=85=8D=E3=80=81=E6=8A=BD=E5=A5=96=E5=89=8D?=
=?UTF-8?q?=E7=BD=AE=E8=A7=84=E5=88=99=E8=BF=87=E6=BB=A4?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.idea/dataSources.xml | 14 +++
.../mybatis/mapper/strategy_mapper.xml | 8 +-
.../mybatis/mapper/strategy_rule_mapper.xml | 15 ++-
.../test/domain/RaffleStrategyTest.java | 65 ++++++++++
...t.java => StrategyArmoryDispatchTest.java} | 10 +-
.../cn/bugstack/test/domain/StrategyTest.java | 110 +++++++++++++++++
.../model/entity/RaffleAwardEntity.java | 30 +++++
.../model/entity/RaffleFactorEntity.java | 25 ++++
.../model/entity/RuleActionEntity.java | 61 ++++++++++
.../model/entity/RuleMatterEntity.java | 30 +++++
.../strategy/model/entity/StrategyEntity.java | 41 +++++++
.../model/entity/StrategyRuleEntity.java | 69 +++++++++++
.../model/valobj/RuleLogicCheckTypeVO.java | 24 ++++
.../repository/IStrategyRepository.java | 16 ++-
.../strategy/service/IRaffleStrategy.java | 18 +++
.../service/annotation/LogicStrategy.java | 23 ++++
.../service/armory/IStrategyArmory.java | 7 --
.../service/armory/IStrategyDispatch.java | 14 +++
.../service/armory/StrategyArmory.java | 77 ------------
.../armory/StrategyArmoryDispatch.java | 114 ++++++++++++++++++
.../raffle/AbstractRaffleStrategy.java | 78 ++++++++++++
.../service/raffle/DefaultRaffleStrategy.java | 84 +++++++++++++
.../strategy/service/rule/ILogicFilter.java | 17 +++
.../rule/factory/DefaultLogicFactory.java | 52 ++++++++
.../rule/impl/RuleBackListLogicFilter.java | 63 ++++++++++
.../rule/impl/RuleWeightLogicFilter.java | 105 ++++++++++++++++
.../persistent/dao/IStrategyDao.java | 7 +-
.../persistent/dao/IStrategyRuleDao.java | 8 +-
.../infrastructure/persistent/po/Award.java | 2 +
.../persistent/po/Strategy.java | 19 +--
.../persistent/po/StrategyAward.java | 2 +
.../persistent/po/StrategyRule.java | 1 +
.../repository/StrategyRepository.java | 70 +++++++++--
.../cn/bugstack/types/common/Constants.java | 5 +
.../cn/bugstack/types/enums/ResponseCode.java | 2 +
35 files changed, 1175 insertions(+), 111 deletions(-)
create mode 100644 xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/RaffleStrategyTest.java
rename xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/{StrategyArmoryTest.java => StrategyArmoryDispatchTest.java} (93%)
create mode 100644 xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyTest.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleAwardEntity.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleFactorEntity.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleActionEntity.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleMatterEntity.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyEntity.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyRuleEntity.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/valobj/RuleLogicCheckTypeVO.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/IRaffleStrategy.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/annotation/LogicStrategy.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyDispatch.java
delete mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmory.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmoryDispatch.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/AbstractRaffleStrategy.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/DefaultRaffleStrategy.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/ILogicFilter.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/factory/DefaultLogicFactory.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleBackListLogicFilter.java
create mode 100644 xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleWeightLogicFilter.java
diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml
index 939b864..b64454b 100644
--- a/.idea/dataSources.xml
+++ b/.idea/dataSources.xml
@@ -13,5 +13,19 @@
$ProjectFileDir$
+
+ mysql.8
+ true
+ true
+ $PROJECT_DIR$/xfg-frame-archetype-lite-app/src/main/resources/application-dev.yml
+ com.mysql.cj.jdbc.Driver
+ jdbc:mysql://127.0.0.1:13306/big_market?useUnicode=true&characterEncoding=utf8&autoReconnect=true&zeroDateTimeBehavior=convertToNull&serverTimezone=UTC&useSSL=true
+
+
+
+
+
+ $ProjectFileDir$
+
\ No newline at end of file
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 03af8bd..e206839 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 @@
+
@@ -16,5 +17,10 @@
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 fe61a80..326e8de 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
@@ -20,5 +20,18 @@
limit 10
-
+
+
+
+
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
new file mode 100644
index 0000000..0dd43dc
--- /dev/null
+++ b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/RaffleStrategyTest.java
@@ -0,0 +1,65 @@
+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.rule.impl.RuleWeightLogicFilter;
+import com.alibaba.fastjson.JSON;
+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;
+import java.security.PrivateKey;
+
+/**
+ * @ClassName: RaffleStrategyTest
+ * @Description:
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 17:11
+ */
+@SpringBootTest
+@Slf4j
+@RunWith(SpringRunner.class)
+public class RaffleStrategyTest {
+ @Resource
+ private IRaffleStrategy raffleStrategy;
+ @Resource
+ private RuleWeightLogicFilter ruleWeightLogicFilter;
+ @Before
+ public void setUp() {
+ ReflectionTestUtils.setField(ruleWeightLogicFilter, "userScore", 4500L);
+ }
+ @Test
+ public void test_performRaffle() {
+ RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder()
+ .userId("xiaofuge")
+ .strategyId(100001L)
+ .build();
+
+ RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(raffleFactorEntity);
+
+ log.info("请求参数:{}", JSON.toJSONString(raffleFactorEntity));
+ log.info("测试结果:{}", JSON.toJSONString(raffleAwardEntity));
+ }
+
+ @Test
+ public void test_performRaffle_blacklist() {
+ RaffleFactorEntity raffleFactorEntity = RaffleFactorEntity.builder()
+ .userId("user003") // 黑名单用户 user001,user002,user003
+ .strategyId(100001L)
+ .build();
+
+ RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(raffleFactorEntity);
+
+ log.info("请求参数:{}", JSON.toJSONString(raffleFactorEntity));
+ log.info("测试结果:{}", JSON.toJSONString(raffleAwardEntity));
+ }
+
+
+
+}
diff --git a/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyArmoryTest.java b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyArmoryDispatchTest.java
similarity index 93%
rename from xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyArmoryTest.java
rename to xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyArmoryDispatchTest.java
index ae682c4..5a1ee06 100644
--- a/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyArmoryTest.java
+++ b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyArmoryDispatchTest.java
@@ -18,18 +18,18 @@ import javax.annotation.Resource;
@SpringBootTest
@Slf4j
@RunWith(SpringRunner.class)
-public class StrategyArmoryTest {
+public class StrategyArmoryDispatchTest {
@Resource
private IStrategyArmory strategyArmory;
- @Test
+ /*@Test
public void test_strategyArmory(){
strategyArmory.assembleLotteryStrategy(100002L);
}
- /**
+ *//**
* 从装配的策略中随机获取奖品ID值
- */
+ *//*
@Test
public void test_getAssembleRandomVal() {
log.info("测试结果:{} - 奖品ID值", strategyArmory.getRandomAwardId(100002L));
@@ -38,5 +38,5 @@ public class StrategyArmoryTest {
log.info("测试结果:{} - 奖品ID值", strategyArmory.getRandomAwardId(100002L));
log.info("测试结果:{} - 奖品ID值", strategyArmory.getRandomAwardId(100002L));
- }
+ }*/
}
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
new file mode 100644
index 0000000..b4cdd87
--- /dev/null
+++ b/xfg-frame-archetype-lite-app/src/test/java/cn/bugstack/test/domain/StrategyTest.java
@@ -0,0 +1,110 @@
+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;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+/**
+ * @ClassName: StrategyTest
+ * @Description:
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 17:18
+ */
+@Slf4j
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class StrategyTest {
+
+ @Resource
+ private IStrategyArmory strategyArmory;
+
+ @Resource
+ private IStrategyDispatch strategyDispatch;
+
+ /**
+ * 策略ID;100001L、100002L 装配的时候创建策略表写入到 Redis Map 中
+ */
+ @Before
+ public void test_strategyArmory() {
+ boolean success = strategyArmory.assembleLotteryStrategy(100001L);
+ log.info("测试结果:{}", success);
+ }
+
+ /**
+ * 从装配的策略中随机获取奖品ID值
+ */
+ @Test
+ 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
+ private IRedisService redisService;
+
+ @Test
+ public void test_map() {
+ RMap map = redisService.getMap("strategy_id_100001");
+ map.put(1, 101);
+ map.put(2, 101);
+ map.put(3, 101);
+ map.put(4, 102);
+ map.put(5, 102);
+ map.put(6, 102);
+ map.put(7, 103);
+ map.put(8, 103);
+ map.put(9, 104);
+ map.put(10, 105);
+
+ log.info("测试结果:{}", redisService.getMap("strategy_id_100001").get(1));
+ }
+
+ @Test
+ public void test_shuffle(){
+ Map strategyAwardSearchRateTable = new HashMap<>();
+ // 添加内容到Map中
+ strategyAwardSearchRateTable.put(1, 10);
+ strategyAwardSearchRateTable.put(2, 20);
+ strategyAwardSearchRateTable.put(3, 30);
+ strategyAwardSearchRateTable.put(4, 40);
+
+ // 将Map中的值转换为List
+ List valueList = new ArrayList<>(strategyAwardSearchRateTable.values());
+
+ // 使用Collections.shuffle()方法对值的List进行乱序
+ Collections.shuffle(valueList);
+
+ // 将乱序后的值重新放回Map中
+ Map randomizedMap = new LinkedHashMap<>();
+ Iterator valueIterator = valueList.iterator();
+ for (Integer key : strategyAwardSearchRateTable.keySet()) {
+ randomizedMap.put(key, valueIterator.next());
+ }
+
+ // 打印乱序后的Map内容
+ for (Map.Entry entry : randomizedMap.entrySet()) {
+ System.out.println("Key: " + entry.getKey() + ", Value: " + entry.getValue());
+ }
+ }
+
+}
+
diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleAwardEntity.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleAwardEntity.java
new file mode 100644
index 0000000..324474a
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleAwardEntity.java
@@ -0,0 +1,30 @@
+package cn.bugstack.domain.strategy.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @ClassName: RaffleAwardEntity
+ * @Description: 抽奖奖品实体
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:25
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class RaffleAwardEntity {
+ /** 策略ID */
+ private Long strategyId;
+ /** 奖品ID */
+ private Integer awardId;
+ /** 奖品对接标识 - 每一个都是一个对应的发奖策略 */
+ private String awardKey;
+ /** 奖品配置信息 */
+ private String awardConfig;
+ /** 奖品内容描述 */
+ private String awardDesc;
+
+}
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
new file mode 100644
index 0000000..4aac430
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RaffleFactorEntity.java
@@ -0,0 +1,25 @@
+package cn.bugstack.domain.strategy.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.checkerframework.checker.units.qual.A;
+
+/**
+ * @ClassName: RaffleFactorEntity
+ * @Description: 抽奖因子实体
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:26
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class RaffleFactorEntity {
+ /** 用户ID */
+ private String userId;
+ /** 策略ID */
+ private Long strategyId;
+
+}
diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleActionEntity.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleActionEntity.java
new file mode 100644
index 0000000..8e40e95
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleActionEntity.java
@@ -0,0 +1,61 @@
+package cn.bugstack.domain.strategy.model.entity;
+
+import cn.bugstack.domain.strategy.model.valobj.RuleLogicCheckTypeVO;
+import lombok.*;
+
+/**
+ * @ClassName: RuleActionEntity
+ * @Description: 规则动作
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:26
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class RuleActionEntity {
+
+ private String code = RuleLogicCheckTypeVO.ALLOW.getCode();
+ private String info = RuleLogicCheckTypeVO.ALLOW.getInfo();
+ private String ruleModel;
+ private T data;
+
+ static public class RaffleEntity {
+
+ }
+
+ // 抽奖之前
+ @EqualsAndHashCode(callSuper = true)
+ @Data
+ @Builder
+ @AllArgsConstructor
+ @NoArgsConstructor
+ static public class RaffleBeforeEntity extends RaffleEntity {
+ /**
+ * 策略ID
+ */
+ private Long strategyId;
+
+ /**
+ * 权重值Key;用于抽奖时可以选择权重抽奖。
+ */
+ private String ruleWeightValueKey;
+
+ /**
+ * 奖品ID;
+ */
+ private Integer awardId;
+ }
+
+ // 抽奖之中
+ static public class RaffleCenterEntity extends RaffleEntity {
+
+ }
+
+ // 抽奖之后
+ static public class RaffleAfterEntity extends RaffleEntity {
+
+ }
+
+}
+
diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleMatterEntity.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleMatterEntity.java
new file mode 100644
index 0000000..365a153
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/RuleMatterEntity.java
@@ -0,0 +1,30 @@
+package cn.bugstack.domain.strategy.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.checkerframework.checker.units.qual.A;
+
+/**
+ * @ClassName: RuleMatterEntity
+ * @Description: 规则物料实体对象,用于过滤规则的必要参数信息
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:26
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class RuleMatterEntity {
+
+ /** 用户ID */
+ private String userId;
+ /** 策略ID */
+ private Long strategyId;
+ /** 抽奖奖品ID【规则类型为策略,则不需要奖品ID】 */
+ private Integer awardId;
+ /** 抽奖规则类型【rule_random - 随机值计算、rule_lock - 抽奖几次后解锁、rule_luck_award - 幸运奖(兜底奖品)】 */
+ private String ruleModel;
+
+}
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 0000000..6161509
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyEntity.java
@@ -0,0 +1,41 @@
+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;
+
+/**
+ * @ClassName: StrategyEntity
+ * @Description: 策略实体
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/15 23:35
+ */
+@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 0000000..3c4cd8a
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/entity/StrategyRuleEntity.java
@@ -0,0 +1,69 @@
+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;
+
+/**
+ * @ClassName: StrategyRuleEntity
+ * @Description: 策略规则实体
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/15 23:36
+ */
+@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/model/valobj/RuleLogicCheckTypeVO.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/valobj/RuleLogicCheckTypeVO.java
new file mode 100644
index 0000000..7ec49c0
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/model/valobj/RuleLogicCheckTypeVO.java
@@ -0,0 +1,24 @@
+package cn.bugstack.domain.strategy.model.valobj;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @ClassName: RuleLogicCheckTypeVO
+ * @Description: 规则过滤校验类型值对象
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:24
+ */
+@Getter
+@AllArgsConstructor
+public enum RuleLogicCheckTypeVO {
+
+ ALLOW("0000", "放行;执行后续的流程,不受规则引擎影响"),
+ TAKE_OVER("0001","接管;后续的流程,受规则引擎执行结果影响"),
+ ;
+
+ private final String code;
+ private final String info;
+
+}
+
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 1b19192..8517af9 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,17 +1,29 @@
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.util.List;
import java.util.Map;
public interface IStrategyRepository {
+
List queryStrategyAwardList(Long strategyId);
- void storeStrategyAwardSearchRateTable(Long strategyId, Integer rateRange, Map strategyAwardSearchRateTable);
+ void storeStrategyAwardSearchRateTable(String key, Integer rateRange, Map strategyAwardSearchRateTable);
- Integer getStrategyAwardAssemble(Long strategyId, Integer rateKey);
+ Integer getStrategyAwardAssemble(String key, Integer rateKey);
int getRateRange(Long strategyId);
+ int getRateRange(String key);
+
+ StrategyEntity queryStrategyEntityByStrategyId(Long strategyId);
+
+ StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleModel);
+
+ String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel);
+
+
}
diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/IRaffleStrategy.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/IRaffleStrategy.java
new file mode 100644
index 0000000..ff78c44
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/IRaffleStrategy.java
@@ -0,0 +1,18 @@
+package cn.bugstack.domain.strategy.service;
+
+
+import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity;
+import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity;
+
+public interface IRaffleStrategy {
+
+ /**
+ * 执行抽奖;用抽奖因子入参,执行抽奖计算,返回奖品信息
+ *
+ * @param raffleFactorEntity 抽奖因子实体对象,根据入参信息计算抽奖结果
+ * @return 抽奖的奖品
+ */
+ RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity);
+
+}
+
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
new file mode 100644
index 0000000..efb233c
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/annotation/LogicStrategy.java
@@ -0,0 +1,23 @@
+package cn.bugstack.domain.strategy.service.annotation;
+
+import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @ClassName: LogicStrategy
+ * @Description: 策略自定义枚举
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:02
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LogicStrategy {
+
+ DefaultLogicFactory.LogicModel logicMode();
+
+}
+
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 18859a5..ff670a5 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
@@ -10,12 +10,5 @@ public interface IStrategyArmory {
*/
boolean assembleLotteryStrategy(Long strategyId);
- /**
- * 获取抽奖策略装配的随机结果
- *
- * @param strategyId 策略ID
- * @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 0000000..cafea34
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyDispatch.java
@@ -0,0 +1,14 @@
+package cn.bugstack.domain.strategy.service.armory;
+
+public interface IStrategyDispatch {
+ /**
+ * 获取抽奖策略装配的随机结果
+ *
+ * @param strategyId 策略ID
+ * @return 抽奖结果
+ */
+ Integer getRandomAwardId(Long strategyId);
+
+ 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
deleted file mode 100644
index 6d91d70..0000000
--- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmory.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package cn.bugstack.domain.strategy.service.armory;
-
-import cn.bugstack.domain.strategy.model.entity.StrategyAwardEntity;
-import cn.bugstack.domain.strategy.repository.IStrategyRepository;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.security.SecureRandom;
-import java.util.*;
-
-/**
- * @ClassName: StrategyArmory
- * @Description: 策略装配库(兵工厂),负责初始化策略计算
- * @Author: zhaoyongfeng
- * @Date: 2024/11/14 17:39
- */
-@Slf4j
-@Service
-public class StrategyArmory implements IStrategyArmory{
- @Resource
- private IStrategyRepository repository;
-
- @Override
- public boolean assembleLotteryStrategy(Long strategyId) {
- //1. 查询策略配置
- List strategyAwardEntities = repository.queryStrategyAwardList(strategyId);
- // 获取最小概率值
- BigDecimal minAwardRate = strategyAwardEntities.stream()
- .map(StrategyAwardEntity::getAwardRate)
- .min(BigDecimal::compareTo)
- .orElse(BigDecimal.ZERO);
-
- // 3. 获取概率值总和
- BigDecimal totalAwardRate = strategyAwardEntities.stream()
- .map(StrategyAwardEntity::getAwardRate)
- .reduce(BigDecimal.ZERO, BigDecimal::add);
-//TODO 需要修改问题
- // 4. 用 1 % 0.0001 获得概率范围,百分位、千分位、万分位
- BigDecimal rateRange = totalAwardRate.divide(minAwardRate, 0, RoundingMode.CEILING);
- // 5. 生成策略奖品概率查找表「这里指需要在list集合中,存放上对应的奖品占位即可,占位越多等于概率越高」
-
- ArrayList strategyAwardSearchRateTables = new ArrayList<>(rateRange.intValue());
- for(StrategyAwardEntity strategyAward: strategyAwardEntities){
- Integer awardId = strategyAward.getAwardId();
- BigDecimal awardRate = strategyAward.getAwardRate();
- // 计算出每个概率值需要存放到查找表的数量,循环填充
- for (int i = 0; i < rateRange.multiply(awardRate).setScale(0, RoundingMode.CEILING).intValue(); i++) {
- strategyAwardSearchRateTables.add(awardId);
- }
-
- }
- // 6. 对存储的奖品进行乱序操作
- Collections.shuffle(strategyAwardSearchRateTables);
- // 7. 生成出Map集合,key值,对应的就是后续的概率值。通过概率来获得对应的奖品ID
- Map shuffleStrategyAwardSearchRateTable = new LinkedHashMap<>();
- for (int i = 0; i < strategyAwardSearchRateTables.size(); i++) {
- shuffleStrategyAwardSearchRateTable.put(i, strategyAwardSearchRateTables.get(i));
- }
- // 8. 存放到 Redis
- repository.storeStrategyAwardSearchRateTable(strategyId, shuffleStrategyAwardSearchRateTable.size(), shuffleStrategyAwardSearchRateTable);
-
- return true;
-
- }
-
- @Override
- public Integer getRandomAwardId(Long strategyId) {
- // 分布式部署下,不一定为当前应用做的策略装配。也就是值不一定会保存到本应用,而是分布式应用,所以需要从 Redis 中获取。
- int rateRange = repository.getRateRange(strategyId);
- // 通过生成的随机值,获取概率值奖品查找表的结果
- return repository.getStrategyAwardAssemble(strategyId, new SecureRandom().nextInt(rateRange));
- }
-
-}
diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmoryDispatch.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmoryDispatch.java
new file mode 100644
index 0000000..1893b80
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmoryDispatch.java
@@ -0,0 +1,114 @@
+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 lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.security.SecureRandom;
+import java.util.*;
+
+/**
+ * @ClassName: StrategyArmory
+ * @Description: 策略装配库(兵工厂),负责初始化策略计算
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/14 17:39
+ */
+@Slf4j
+@Service
+public class StrategyArmoryDispatch implements IStrategyArmory,IStrategyDispatch{
+ @Resource
+ private IStrategyRepository repository;
+
+ @Override
+ public boolean assembleLotteryStrategy(Long strategyId) {
+ // 1. 查询策略配置
+ List strategyAwardEntities = repository.queryStrategyAwardList(strategyId);
+ assembleLotteryStrategy(String.valueOf(strategyId), strategyAwardEntities);
+
+ // 2. 权重策略配置 - 适用于 rule_weight 权重规则配置
+ StrategyEntity strategyEntity = repository.queryStrategyEntityByStrategyId(strategyId);
+ String ruleWeight = strategyEntity.getRuleWeight();
+ if (null == ruleWeight) return true;
+
+ StrategyRuleEntity strategyRuleEntity = repository.queryStrategyRule(strategyId, 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();
+ for (String key : keys) {
+ List ruleWeightValues = ruleWeightValueMap.get(key);
+ ArrayList strategyAwardEntitiesClone = new ArrayList<>(strategyAwardEntities);
+ strategyAwardEntitiesClone.removeIf(entity -> !ruleWeightValues.contains(entity.getAwardId()));
+ assembleLotteryStrategy(String.valueOf(strategyId).concat("_").concat(key), strategyAwardEntitiesClone);
+ }
+
+ return true;
+ }
+
+ private void assembleLotteryStrategy(String key, List strategyAwardEntities) {
+ // 1. 获取最小概率值
+ BigDecimal minAwardRate = strategyAwardEntities.stream()
+ .map(StrategyAwardEntity::getAwardRate)
+ .min(BigDecimal::compareTo)
+ .orElse(BigDecimal.ZERO);
+
+ // 2. 获取概率值总和
+ BigDecimal totalAwardRate = strategyAwardEntities.stream()
+ .map(StrategyAwardEntity::getAwardRate)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ // 3. 用 1 % 0.0001 获得概率范围,百分位、千分位、万分位
+ BigDecimal rateRange = totalAwardRate.divide(minAwardRate, 0, RoundingMode.CEILING);
+
+ // 4. 生成策略奖品概率查找表「这里指需要在list集合中,存放上对应的奖品占位即可,占位越多等于概率越高」
+ List strategyAwardSearchRateTables = new ArrayList<>(rateRange.intValue());
+ for (StrategyAwardEntity strategyAward : strategyAwardEntities) {
+ Integer awardId = strategyAward.getAwardId();
+ BigDecimal awardRate = strategyAward.getAwardRate();
+ // 计算出每个概率值需要存放到查找表的数量,循环填充
+ for (int i = 0; i < rateRange.multiply(awardRate).setScale(0, RoundingMode.CEILING).intValue(); i++) {
+ strategyAwardSearchRateTables.add(awardId);
+ }
+ }
+
+ // 5. 对存储的奖品进行乱序操作
+ Collections.shuffle(strategyAwardSearchRateTables);
+
+ // 6. 生成出Map集合,key值,对应的就是后续的概率值。通过概率来获得对应的奖品ID
+ Map shuffleStrategyAwardSearchRateTable = new LinkedHashMap<>();
+ for (int i = 0; i < strategyAwardSearchRateTables.size(); i++) {
+ shuffleStrategyAwardSearchRateTable.put(i, strategyAwardSearchRateTables.get(i));
+ }
+
+ // 7. 存放到 Redis
+ repository.storeStrategyAwardSearchRateTable(key, shuffleStrategyAwardSearchRateTable.size(), shuffleStrategyAwardSearchRateTable);
+ }
+
+ @Override
+ public Integer getRandomAwardId(Long strategyId) {
+ // 分布式部署下,不一定为当前应用做的策略装配。也就是值不一定会保存到本应用,而是分布式应用,所以需要从 Redis 中获取。
+ int rateRange = repository.getRateRange(strategyId);
+ // 通过生成的随机值,获取概率值奖品查找表的结果
+ 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-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
new file mode 100644
index 0000000..a2350e6
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/AbstractRaffleStrategy.java
@@ -0,0 +1,78 @@
+package cn.bugstack.domain.strategy.service.raffle;
+
+import cn.bugstack.domain.strategy.model.entity.RaffleAwardEntity;
+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.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.types.enums.ResponseCode;
+import cn.bugstack.types.exception.AppException;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @ClassName: AbstractRaffleStrategy
+ * @Description: 抽奖策略抽象类,定义抽奖的标准流程
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:14
+ */
+@Slf4j
+public abstract class AbstractRaffleStrategy implements IRaffleStrategy {
+
+ // 策略仓储服务 -> domain层像一个大厨,仓储层提供米面粮油
+ protected IStrategyRepository repository;
+ // 策略调度服务 -> 只负责抽奖处理,通过新增接口的方式,隔离职责,不需要使用方关心或者调用抽奖的初始化
+ protected IStrategyDispatch strategyDispatch;
+
+ public AbstractRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) {
+ this.repository = repository;
+ this.strategyDispatch = strategyDispatch;
+ }
+
+ @Override
+ public RaffleAwardEntity performRaffle(RaffleFactorEntity raffleFactorEntity) {
+ // 1. 参数校验
+ String userId = raffleFactorEntity.getUserId();
+ Long strategyId = raffleFactorEntity.getStrategyId();
+ if (null == strategyId || StringUtils.isBlank(userId)) {
+ throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
+ }
+
+ // 2. 策略查询
+ StrategyEntity strategy = repository.queryStrategyEntityByStrategyId(strategyId);
+
+ // 3. 抽奖前 - 规则过滤
+ RuleActionEntity ruleActionEntity = this.doCheckRaffleBeforeLogic(RaffleFactorEntity.builder().userId(userId).strategyId(strategyId).build(), strategy.ruleModels());
+
+ if (RuleLogicCheckTypeVO.TAKE_OVER.getCode().equals(ruleActionEntity.getCode())) {
+ if (DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode().equals(ruleActionEntity.getRuleModel())) {
+ // 黑名单返回固定的奖品ID
+ return RaffleAwardEntity.builder()
+ .awardId(ruleActionEntity.getData().getAwardId())
+ .build();
+ } else if (DefaultLogicFactory.LogicModel.RULE_WIGHT.getCode().equals(ruleActionEntity.getRuleModel())) {
+ // 权重根据返回的信息进行抽奖
+ RuleActionEntity.RaffleBeforeEntity raffleBeforeEntity = ruleActionEntity.getData();
+ String ruleWeightValueKey = raffleBeforeEntity.getRuleWeightValueKey();
+ Integer awardId = strategyDispatch.getRandomAwardId(strategyId, ruleWeightValueKey);
+ return RaffleAwardEntity.builder()
+ .awardId(awardId)
+ .build();
+ }
+ }
+
+ // 4. 默认抽奖流程
+ Integer awardId = strategyDispatch.getRandomAwardId(strategyId);
+
+ return RaffleAwardEntity.builder()
+ .awardId(awardId)
+ .build();
+ }
+
+ protected abstract RuleActionEntity doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, 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
new file mode 100644
index 0000000..05c6c53
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/raffle/DefaultRaffleStrategy.java
@@ -0,0 +1,84 @@
+package cn.bugstack.domain.strategy.service.raffle;
+
+import cn.bugstack.domain.strategy.model.entity.RaffleFactorEntity;
+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.armory.IStrategyDispatch;
+import cn.bugstack.domain.strategy.service.rule.ILogicFilter;
+import cn.bugstack.domain.strategy.service.rule.factory.DefaultLogicFactory;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * @ClassName: DefaultRaffleStrategy
+ * @Description: 默认的抽奖策略实现
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:16
+ */
+@Slf4j
+@Service
+public class DefaultRaffleStrategy extends AbstractRaffleStrategy {
+
+ @Resource
+ private DefaultLogicFactory logicFactory;
+
+ public DefaultRaffleStrategy(IStrategyRepository repository, IStrategyDispatch strategyDispatch) {
+ super(repository, strategyDispatch);
+ }
+
+ @Override
+ protected RuleActionEntity doCheckRaffleBeforeLogic(RaffleFactorEntity raffleFactorEntity, String... logics) {
+ Map> logicFilterGroup = logicFactory.openLogicFilter();
+
+ // 黑名单规则优先过滤
+ String ruleBackList = Arrays.stream(logics)
+ .filter(str -> str.contains(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()))
+ .findFirst()
+ .orElse(null);
+
+ if (StringUtils.isNotBlank(ruleBackList)) {
+ ILogicFilter logicFilter = logicFilterGroup.get(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode());
+ RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
+ ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
+ ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId());
+ ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
+ ruleMatterEntity.setRuleModel(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode());
+ RuleActionEntity ruleActionEntity = logicFilter.filter(ruleMatterEntity);
+ if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) {
+ return ruleActionEntity;
+ }
+ }
+
+ // 顺序过滤剩余规则
+ List ruleList = Arrays.stream(logics)
+ .filter(s -> !s.equals(DefaultLogicFactory.LogicModel.RULE_BLACKLIST.getCode()))
+ .collect(Collectors.toList());
+
+ RuleActionEntity ruleActionEntity = null;
+ for (String ruleModel : ruleList) {
+ ILogicFilter logicFilter = logicFilterGroup.get(ruleModel);
+ RuleMatterEntity ruleMatterEntity = new RuleMatterEntity();
+ ruleMatterEntity.setUserId(raffleFactorEntity.getUserId());
+ ruleMatterEntity.setAwardId(ruleMatterEntity.getAwardId());
+ ruleMatterEntity.setStrategyId(raffleFactorEntity.getStrategyId());
+ ruleMatterEntity.setRuleModel(ruleModel);
+ ruleActionEntity = logicFilter.filter(ruleMatterEntity);
+ // 非放行结果则顺序过滤
+ log.info("抽奖前规则过滤 userId: {} ruleModel: {} code: {} info: {}", raffleFactorEntity.getUserId(), ruleModel, ruleActionEntity.getCode(), ruleActionEntity.getInfo());
+ if (!RuleLogicCheckTypeVO.ALLOW.getCode().equals(ruleActionEntity.getCode())) return ruleActionEntity;
+ }
+
+ return ruleActionEntity;
+ }
+
+}
+
diff --git a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/ILogicFilter.java b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/ILogicFilter.java
new file mode 100644
index 0000000..741e4d5
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/ILogicFilter.java
@@ -0,0 +1,17 @@
+package cn.bugstack.domain.strategy.service.rule;
+
+import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
+import cn.bugstack.domain.strategy.model.entity.RuleMatterEntity;
+
+/*
+ * @return
+ * @author zhaoyongfeng
+ * @description 抽奖规则过滤接口
+ *
+ * @param null
+ */
+public interface ILogicFilter {
+
+ RuleActionEntity filter(RuleMatterEntity ruleMatterEntity);
+
+}
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
new file mode 100644
index 0000000..cc674b8
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/factory/DefaultLogicFactory.java
@@ -0,0 +1,52 @@
+package cn.bugstack.domain.strategy.service.rule.factory;
+
+import cn.bugstack.domain.strategy.model.entity.RuleActionEntity;
+import cn.bugstack.domain.strategy.service.annotation.LogicStrategy;
+import cn.bugstack.domain.strategy.service.rule.ILogicFilter;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @ClassName: DefaultLogicFactory
+ * @Description:
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:05
+ */
+@Service
+public class DefaultLogicFactory {
+ public Map> logicFilterMap = new ConcurrentHashMap<>();
+
+ public DefaultLogicFactory(List> logicFilters) {
+ logicFilters.forEach(logic -> {
+ LogicStrategy strategy = AnnotationUtils.findAnnotation(logic.getClass(), LogicStrategy.class);
+ if (null != strategy) {
+ logicFilterMap.put(strategy.logicMode().getCode(), logic);
+ }
+ });
+ }
+
+ public Map> openLogicFilter() {
+ return (Map>) (Map, ?>) logicFilterMap;
+ }
+
+ @Getter
+ @AllArgsConstructor
+ public enum LogicModel {
+
+ RULE_WIGHT("rule_weight","【抽奖前规则】根据抽奖权重返回可抽奖范围KEY"),
+ RULE_BLACKLIST("rule_blacklist","【抽奖前规则】黑名单规则过滤,命中黑名单则直接返回"),
+
+ ;
+
+ private final String code;
+ private final String info;
+
+ }
+
+}
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/impl/RuleBackListLogicFilter.java
new file mode 100644
index 0000000..803ef23
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleBackListLogicFilter.java
@@ -0,0 +1,63 @@
+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 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
+@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_BLACKLIST)
+public class RuleBackListLogicFilter implements ILogicFilter {
+ @Resource
+ private IStrategyRepository repository;
+
+ @Override
+ public RuleActionEntity filter(RuleMatterEntity ruleMatterEntity) {
+ log.info("规则过滤-黑名单 userId:{} strategyId:{} ruleModel:{}", ruleMatterEntity.getUserId(), ruleMatterEntity.getStrategyId(), ruleMatterEntity.getRuleModel());
+
+ String userId = ruleMatterEntity.getUserId();
+
+ // 查询规则值配置
+ String ruleValue = repository.queryStrategyRuleValue(ruleMatterEntity.getStrategyId(), ruleMatterEntity.getAwardId(), ruleMatterEntity.getRuleModel());
+ 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)) {
+ return RuleActionEntity.builder()
+ .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.builder()
+ .code(RuleLogicCheckTypeVO.ALLOW.getCode())
+ .info(RuleLogicCheckTypeVO.ALLOW.getInfo())
+ .build();
+ }
+
+}
+
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/impl/RuleWeightLogicFilter.java
new file mode 100644
index 0000000..845a113
--- /dev/null
+++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/rule/impl/RuleWeightLogicFilter.java
@@ -0,0 +1,105 @@
+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 cn.bugstack.types.common.Constants;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import javax.annotation.Resource;
+import java.util.*;
+
+/**
+ * @ClassName: RuleWeightLogicFilter
+ * @Description: 【抽奖前规则】根据抽奖权重返回可抽奖范围KEY
+ * @Author: zhaoyongfeng
+ * @Date: 2024/11/17 16:08
+ */
+@Slf4j
+@Component
+@LogicStrategy(logicMode = DefaultLogicFactory.LogicModel.RULE_WIGHT)
+public class RuleWeightLogicFilter implements ILogicFilter {
+
+ @Resource
+ private IStrategyRepository repository;
+
+ public Long userScore = 4500L;
+
+ /**
+ * 权重规则过滤;
+ * 1. 权重规则格式;4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108,109
+ * 2. 解析数据格式;判断哪个范围符合用户的特定抽奖范围
+ *
+ * @param ruleMatterEntity 规则物料实体对象
+ * @return 规则过滤结果
+ */
+ @Override
+ public RuleActionEntity filter(RuleMatterEntity ruleMatterEntity) {
+ log.info("规则过滤-权重范围 userId:{} strategyId:{} ruleModel:{}", ruleMatterEntity.getUserId(), ruleMatterEntity.getStrategyId(), ruleMatterEntity.getRuleModel());
+
+ String userId = ruleMatterEntity.getUserId();
+ Long strategyId = ruleMatterEntity.getStrategyId();
+ String ruleValue = repository.queryStrategyRuleValue(ruleMatterEntity.getStrategyId(), ruleMatterEntity.getAwardId(), ruleMatterEntity.getRuleModel());
+
+ // 1. 根据用户ID查询用户抽奖消耗的积分值,本章节我们先写死为固定的值。后续需要从数据库中查询。
+ Map analyticalValueGroup = getAnalyticalValue(ruleValue);
+ if (null == analyticalValueGroup || analyticalValueGroup.isEmpty()) {
+ return RuleActionEntity.builder()
+ .code(RuleLogicCheckTypeVO.ALLOW.getCode())
+ .info(RuleLogicCheckTypeVO.ALLOW.getInfo())
+ .build();
+ }
+
+ // 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()
+ .filter(key -> userScore >= key)
+ .findFirst()
+ .orElse(null);
+
+ if (null != nextValue) {
+ return RuleActionEntity.builder()
+ .data(RuleActionEntity.RaffleBeforeEntity.builder()
+ .strategyId(strategyId)
+ .ruleWeightValueKey(analyticalValueGroup.get(nextValue))
+ .build())
+ .ruleModel(DefaultLogicFactory.LogicModel.RULE_WIGHT.getCode())
+ .code(RuleLogicCheckTypeVO.TAKE_OVER.getCode())
+ .info(RuleLogicCheckTypeVO.TAKE_OVER.getInfo())
+ .build();
+ }
+
+ return RuleActionEntity.builder()
+ .code(RuleLogicCheckTypeVO.ALLOW.getCode())
+ .info(RuleLogicCheckTypeVO.ALLOW.getInfo())
+ .build();
+ }
+
+ private Map getAnalyticalValue(String ruleValue) {
+ String[] ruleValueGroups = ruleValue.split(Constants.SPACE);
+ Map ruleValueMap = new HashMap<>();
+ for (String ruleValueKey : ruleValueGroups) {
+ // 检查输入是否为空
+ if (ruleValueKey == null || ruleValueKey.isEmpty()) {
+ return ruleValueMap;
+ }
+ // 分割字符串以获取键和值
+ String[] parts = ruleValueKey.split(Constants.COLON);
+ 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-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 8540ee6..f12376a 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
@@ -1,10 +1,15 @@
package cn.bugstack.infrastructure.persistent.dao;
import cn.bugstack.infrastructure.persistent.po.Award;
+import cn.bugstack.infrastructure.persistent.po.Strategy;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface IStrategyDao {
- List queryStrategyList();
+ List queryStrategyList();
+
+ Strategy queryStrategyByStrategyId(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 83d301e..09990d9 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
@@ -1,10 +1,16 @@
package cn.bugstack.infrastructure.persistent.dao;
import cn.bugstack.infrastructure.persistent.po.Award;
+import cn.bugstack.infrastructure.persistent.po.StrategyRule;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface IStrategyRuleDao {
- List queryStrategyRuleList();
+ List queryStrategyRuleList();
+
+ StrategyRule queryStrategyRule(StrategyRule strategyRuleReq);
+
+ String queryStrategyRuleValue(StrategyRule strategyRule);
+
}
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 d238ca2..4b6f413 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
@@ -1,5 +1,6 @@
package cn.bugstack.infrastructure.persistent.po;
+import lombok.Builder;
import lombok.Data;
import java.util.Date;
@@ -28,4 +29,5 @@ public class Award {
/** 更新时间 */
private Date updateTime;
+
}
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 f2163fa..a76b4ef 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
@@ -1,5 +1,6 @@
package cn.bugstack.infrastructure.persistent.po;
+import lombok.Builder;
import lombok.Data;
import java.util.Date;
@@ -11,21 +12,21 @@ import java.util.Date;
* @Date: 2024/11/13 20:26
*/
@Data
+@Builder
public class Strategy {
- /* ID*/
+ /** 自增ID */
private Long id;
-
- /* 抽奖策略描述*/
+ /** 抽奖策略ID */
private Long strategyId;
-
- /* 抽奖策略ID*/
+ /** 抽奖策略描述 */
private String strategyDesc;
-
- /* 创建时间*/
+ /** 抽奖规则模型 */
+ private String ruleModels;
+ /** 创建时间 */
private Date createTime;
-
- /* 更新时间*/
+ /** 更新时间 */
private Date updateTime;
+
}
diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyAward.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyAward.java
index 83a085f..89c2199 100644
--- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyAward.java
+++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyAward.java
@@ -1,5 +1,6 @@
package cn.bugstack.infrastructure.persistent.po;
+import lombok.Builder;
import lombok.Data;
import java.math.BigDecimal;
@@ -38,4 +39,5 @@ public class StrategyAward {
/** 修改时间 */
private Date updateTime;
+
}
diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyRule.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyRule.java
index 1fa5c7e..5d30410 100644
--- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyRule.java
+++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/persistent/po/StrategyRule.java
@@ -1,5 +1,6 @@
package cn.bugstack.infrastructure.persistent.po;
+import lombok.Builder;
import lombok.Data;
import java.util.Date;
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 5c2355f..136f3e4 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
@@ -2,9 +2,15 @@ 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.types.common.Constants;
import org.springframework.stereotype.Repository;
@@ -24,6 +30,10 @@ import java.util.Map;
@Repository
public class StrategyRepository implements IStrategyRepository {
+ @Resource
+ private IStrategyDao strategyDao;
+ @Resource
+ private IStrategyRuleDao strategyRuleDao;
@Resource
private IStrategyAwardDao strategyAwardDao;
@Resource
@@ -53,24 +63,70 @@ public class StrategyRepository implements IStrategyRepository {
}
@Override
- public void storeStrategyAwardSearchRateTable(Long strategyId, Integer rateRange, Map strategyAwardSearchRateTable) {
+ public void storeStrategyAwardSearchRateTable(String key, Integer rateRange, Map strategyAwardSearchRateTable) {
// 1. 存储抽奖策略范围值,如10000,用于生成1000以内的随机数
- redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId, rateRange);
+ redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, rateRange);
// 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(strategyAwardSearchRateTable);
-
}
@Override
- public Integer getStrategyAwardAssemble(Long strategyId, Integer rateKey) {
- return redisService.getFromMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + strategyId, rateKey);
+ public Integer getStrategyAwardAssemble(String key, Integer rateKey) {
+ return redisService.getFromMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key, rateKey);
}
@Override
public int getRateRange(Long strategyId) {
- return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId);
+ return getRateRange(String.valueOf(strategyId));
+ }
+
+ @Override
+ public int getRateRange(String key) {
+ return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key);
+ }
+
+ @Override
+ public StrategyEntity queryStrategyEntityByStrategyId(Long strategyId) {
+ // 优先从缓存获取
+ String cacheKey = Constants.RedisKey.STRATEGY_KEY + strategyId;
+ StrategyEntity strategyEntity = redisService.getValue(cacheKey);
+ if (null != strategyEntity) return strategyEntity;
+ Strategy strategy = strategyDao.queryStrategyByStrategyId(strategyId);
+ strategyEntity = StrategyEntity.builder()
+ .strategyId(strategy.getStrategyId())
+ .strategyDesc(strategy.getStrategyDesc())
+ .ruleModels(strategy.getRuleModels())
+ .build();
+ 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 String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel) {
+ StrategyRule strategyRule = new StrategyRule();
+ strategyRule.setStrategyId(strategyId);
+ strategyRule.setAwardId(awardId);
+ strategyRule.setRuleModel(ruleModel);
+ return strategyRuleDao.queryStrategyRuleValue(strategyRule);
}
}
+
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 008bc32..72232de 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,11 +3,16 @@ package cn.bugstack.types.common;
public class Constants {
public final static String SPLIT = ",";
+ public final static String SPACE = " ";
+ public final static String COLON = ":";
+
public static class RedisKey {
+ public static 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 7460d4b..15eaba2 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,9 +12,11 @@ public enum ResponseCode {
SUCCESS("0000", "成功"),
UN_ERROR("0001", "未知失败"),
ILLEGAL_PARAMETER("0002", "非法参数"),
+ STRATEGY_RULE_WEIGHT_IS_NULL("ERR_BIZ_001", "业务异常,策略规则中 rule_weight 权重规则已适用但未配置"),
;
private String code;
private String info;
+
}
--
GitLab