diff --git a/docs/dev-ops/mysql/sql/xfg-frame-archetype.sql b/docs/dev-ops/mysql/sql/xfg-frame-archetype.sql index b23e1b487307b5addeb4bc229f628cec3c36eb05..5533ecf2c0f5ae2482e2ad1c89326ca11c34a029 100644 --- a/docs/dev-ops/mysql/sql/xfg-frame-archetype.sql +++ b/docs/dev-ops/mysql/sql/xfg-frame-archetype.sql @@ -109,10 +109,14 @@ COMMIT; CREATE database if NOT EXISTS `big_market` default character set utf8mb4 collate utf8mb4_0900_ai_ci; use `big_market`; + +DROP TABLE IF EXISTS `strategy`; + CREATE TABLE `strategy` ( `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID', `strategy_id` bigint(8) NOT NULL COMMENT '抽奖策略ID', `strategy_desc` varchar(128) NOT NULL COMMENT '抽奖策略描述', + `rule_models` varchar(256) DEFAULT NULL COMMENT '规则模型,rule配置的模型同步到此表,便于使用', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), @@ -122,12 +126,14 @@ CREATE TABLE `strategy` ( LOCK TABLES `strategy` WRITE; /*!40000 ALTER TABLE `strategy` DISABLE KEYS */; -INSERT INTO `strategy` - (`id`, `strategy_id`, `strategy_desc`, `create_time`, `update_time`) +INSERT INTO `strategy` (`id`, `strategy_id`, `strategy_desc`, `rule_models`, `create_time`, `update_time`) VALUES - (1,100001,'抽奖策略','2023-12-09 09:37:19','2023-12-09 09:37:19'); + (1,100001,'抽奖策略','rule_weight,rule_blacklist','2023-12-09 09:37:19','2023-12-09 18:06:34'); + +/*!40000 ALTER TABLE `strategy` ENABLE KEYS */; UNLOCK TABLES; + CREATE TABLE `strategy_award` ( `id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增ID', `strategy_id` bigint(8) NOT NULL COMMENT '抽奖策略ID', @@ -167,7 +173,7 @@ CREATE TABLE `strategy_rule` ( `award_id` int(8) DEFAULT NULL COMMENT '抽奖奖品ID【规则类型为策略,则不需要奖品ID】', `rule_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '抽象规则类型;1-策略规则、2-奖品规则', `rule_model` varchar(16) NOT NULL COMMENT '抽奖规则类型【rule_random - 随机值计算、rule_lock - 抽奖几次后解锁、rule_luck_award - 幸运奖(兜底奖品)】', - `rule_value` varchar(64) NOT NULL COMMENT '抽奖规则比值', + `rule_value` varchar(256) NOT NULL COMMENT '抽奖规则比值', `rule_desc` varchar(128) NOT NULL COMMENT '抽奖规则描述', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', diff --git a/xfg-frame-archetype-lite-app/data/log/log_info.log b/xfg-frame-archetype-lite-app/data/log/log_info.log index 94c556faaf20f9debdd07122ddb647224c307d6e..72664e5f71c0280a05c4605e6f1473f108c2cd67 100644 --- a/xfg-frame-archetype-lite-app/data/log/log_info.log +++ b/xfg-frame-archetype-lite-app/data/log/log_info.log @@ -1,92 +1,17 @@ -25-03-03.21:06:31.068 [main ] INFO ApiTest - Starting ApiTest using Java 17.0.10 on xruicc with PID 27140 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.21:06:31.069 [main ] INFO ApiTest - The following 1 profile is active: "dev" -25-03-03.21:06:32.143 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.21:06:32.148 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.21:06:32.189 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 14 ms. Found 0 Redis repository interfaces. -25-03-03.21:06:33.173 [main ] INFO Version - Redisson 3.23.4 -25-03-03.21:06:33.646 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.21:06:33.662 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.21:06:35.292 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.21:06:35.347 [main ] INFO ApiTest - Started ApiTest in 4.759 seconds (JVM running for 5.923) -25-03-03.21:06:35.870 [main ] INFO ApiTest - 测试结果:100 -25-03-03.22:38:56.367 [main ] INFO StrategyArmoryTest - Starting StrategyArmoryTest using Java 17.0.10 on xruicc with PID 19328 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.22:38:56.368 [main ] INFO StrategyArmoryTest - The following 1 profile is active: "dev" -25-03-03.22:38:57.244 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.22:38:57.246 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.22:38:57.278 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 16 ms. Found 0 Redis repository interfaces. -25-03-03.22:38:58.526 [main ] INFO Version - Redisson 3.23.4 -25-03-03.22:38:59.017 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:38:59.039 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:39:00.415 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.22:39:00.472 [main ] INFO StrategyArmoryTest - Started StrategyArmoryTest in 4.546 seconds (JVM running for 5.706) -25-03-03.22:39:01.015 [main ] INFO HikariDataSource - HikariPool-1 - Starting... -25-03-03.22:39:01.417 [main ] INFO HikariDataSource - HikariPool-1 - Start completed. -25-03-03.22:39:15.717 [SpringApplicationShutdownHook] INFO HikariDataSource - HikariPool-1 - Shutdown initiated... -25-03-03.22:39:15.734 [SpringApplicationShutdownHook] INFO HikariDataSource - HikariPool-1 - Shutdown completed. -25-03-03.22:49:25.462 [main ] INFO StrategyArmoryTest - Starting StrategyArmoryTest using Java 17.0.10 on xruicc with PID 22388 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.22:49:25.462 [main ] INFO StrategyArmoryTest - The following 1 profile is active: "dev" -25-03-03.22:49:26.394 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.22:49:26.396 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.22:49:26.428 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 17 ms. Found 0 Redis repository interfaces. -25-03-03.22:49:27.663 [main ] INFO Version - Redisson 3.23.4 -25-03-03.22:49:28.164 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:49:28.182 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:49:29.535 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.22:49:29.582 [main ] INFO StrategyArmoryTest - Started StrategyArmoryTest in 4.547 seconds (JVM running for 5.653) -25-03-03.22:50:59.298 [main ] INFO StrategyArmoryTest - Starting StrategyArmoryTest using Java 17.0.10 on xruicc with PID 27376 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.22:50:59.299 [main ] INFO StrategyArmoryTest - The following 1 profile is active: "dev" -25-03-03.22:51:00.158 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.22:51:00.160 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.22:51:00.191 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 17 ms. Found 0 Redis repository interfaces. -25-03-03.22:51:01.355 [main ] INFO Version - Redisson 3.23.4 -25-03-03.22:51:01.816 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:51:01.837 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:51:03.156 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.22:51:03.209 [main ] INFO StrategyArmoryTest - Started StrategyArmoryTest in 4.371 seconds (JVM running for 5.499) -25-03-03.22:51:03.710 [main ] INFO HikariDataSource - HikariPool-1 - Starting... -25-03-03.22:51:04.076 [main ] INFO HikariDataSource - HikariPool-1 - Start completed. -25-03-03.22:51:04.349 [SpringApplicationShutdownHook] INFO HikariDataSource - HikariPool-1 - Shutdown initiated... -25-03-03.22:51:04.363 [SpringApplicationShutdownHook] INFO HikariDataSource - HikariPool-1 - Shutdown completed. -25-03-03.22:55:30.466 [main ] INFO StrategyArmoryTest - Starting StrategyArmoryTest using Java 17.0.10 on xruicc with PID 11100 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.22:55:30.467 [main ] INFO StrategyArmoryTest - The following 1 profile is active: "dev" -25-03-03.22:55:31.327 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.22:55:31.332 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.22:55:31.361 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 15 ms. Found 0 Redis repository interfaces. -25-03-03.22:55:32.533 [main ] INFO Version - Redisson 3.23.4 -25-03-03.22:55:32.979 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:55:32.996 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.22:55:34.444 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.22:55:34.503 [main ] INFO StrategyArmoryTest - Started StrategyArmoryTest in 4.551 seconds (JVM running for 5.69) -25-03-03.23:05:02.637 [main ] INFO StrategyArmoryTest - Starting StrategyArmoryTest using Java 17.0.10 on xruicc with PID 27872 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.23:05:02.638 [main ] INFO StrategyArmoryTest - The following 1 profile is active: "dev" -25-03-03.23:05:03.612 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.23:05:03.615 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.23:05:03.646 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 17 ms. Found 0 Redis repository interfaces. -25-03-03.23:05:05.145 [main ] INFO Version - Redisson 3.23.4 -25-03-03.23:05:05.733 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.23:05:05.755 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.23:05:07.553 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.23:05:07.621 [main ] INFO StrategyArmoryTest - Started StrategyArmoryTest in 5.522 seconds (JVM running for 7.136) -25-03-03.23:14:35.673 [main ] INFO StrategyArmoryTest - Starting StrategyArmoryTest using Java 17.0.10 on xruicc with PID 23408 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.23:14:35.674 [main ] INFO StrategyArmoryTest - The following 1 profile is active: "dev" -25-03-03.23:14:36.513 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.23:14:36.517 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.23:14:36.545 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 16 ms. Found 0 Redis repository interfaces. -25-03-03.23:14:37.757 [main ] INFO Version - Redisson 3.23.4 -25-03-03.23:14:38.190 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.23:14:38.206 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.23:14:39.491 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.23:14:39.534 [main ] INFO StrategyArmoryTest - Started StrategyArmoryTest in 4.288 seconds (JVM running for 5.373) -25-03-03.23:16:07.203 [main ] INFO StrategyArmoryTest - Starting StrategyArmoryTest using Java 17.0.10 on xruicc with PID 26864 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) -25-03-03.23:16:07.204 [main ] INFO StrategyArmoryTest - The following 1 profile is active: "dev" -25-03-03.23:16:08.184 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode -25-03-03.23:16:08.186 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. -25-03-03.23:16:08.214 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 16 ms. Found 0 Redis repository interfaces. -25-03-03.23:16:09.432 [main ] INFO Version - Redisson 3.23.4 -25-03-03.23:16:09.894 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.23:16:09.914 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 -25-03-03.23:16:11.278 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' -25-03-03.23:16:11.330 [main ] INFO StrategyArmoryTest - Started StrategyArmoryTest in 4.566 seconds (JVM running for 5.677) -25-03-03.23:16:11.810 [main ] INFO StrategyArmoryTest - 测试:101 -25-03-03.23:16:11.813 [main ] INFO StrategyArmoryTest - 测试:101 -25-03-03.23:16:11.817 [main ] INFO StrategyArmoryTest - 测试:101 +25-03-04.22:24:53.944 [main ] INFO StrategyArmoryDispatchTest - Starting StrategyArmoryDispatchTest using Java 17.0.10 on xruicc with PID 4052 (started by 15505 in D:\MarketingIntegrationSystem\xfg-frame-archetype-lite-app) +25-03-04.22:24:53.945 [main ] INFO StrategyArmoryDispatchTest - The following 1 profile is active: "dev" +25-03-04.22:24:55.095 [main ] INFO RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode +25-03-04.22:24:55.098 [main ] INFO RepositoryConfigurationDelegate - Bootstrapping Spring Data Redis repositories in DEFAULT mode. +25-03-04.22:24:55.133 [main ] INFO RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 17 ms. Found 0 Redis repository interfaces. +25-03-04.22:24:56.571 [main ] INFO Version - Redisson 3.23.4 +25-03-04.22:24:57.068 [redisson-netty-2-4] INFO MasterPubSubConnectionPool - 1 connections initialized for 192.168.1.10/192.168.1.10:6379 +25-03-04.22:24:57.087 [redisson-netty-2-13] INFO MasterConnectionPool - 5 connections initialized for 192.168.1.10/192.168.1.10:6379 +25-03-04.22:24:58.434 [main ] INFO EndpointLinksResolver - Exposing 1 endpoint(s) beneath base path '/actuator' +25-03-04.22:24:58.489 [main ] INFO StrategyArmoryDispatchTest - Started StrategyArmoryDispatchTest in 5.029 seconds (JVM running for 6.288) +25-03-04.22:24:59.246 [main ] INFO HikariDataSource - HikariPool-1 - Starting... +25-03-04.22:24:59.656 [main ] INFO HikariDataSource - HikariPool-1 - Start completed. +25-03-04.22:24:59.767 [main ] INFO StrategyArmoryDispatchTest - 测试结果:101 - 4000 策略配置 +25-03-04.22:24:59.770 [main ] INFO StrategyArmoryDispatchTest - 测试结果:101 - 5000 策略配置 +25-03-04.22:24:59.773 [main ] INFO StrategyArmoryDispatchTest - 测试结果:103 - 6000 策略配置 +25-03-04.22:24:59.805 [SpringApplicationShutdownHook] INFO HikariDataSource - HikariPool-1 - Shutdown initiated... +25-03-04.22:24:59.816 [SpringApplicationShutdownHook] INFO HikariDataSource - HikariPool-1 - Shutdown completed. 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 51% 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 754fca62ab35a0fadb45ea987a3154879f8ef6a6..a68ce6fbe9b136157097e65af6723daff5e51d91 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 @@ -1,13 +1,16 @@ 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.dao.IStrategyAwardDao; import cn.bugstack.infrastructure.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.context.annotation.Bean; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; @@ -15,24 +18,27 @@ import javax.annotation.Resource; @Slf4j @RunWith(SpringRunner.class) @SpringBootTest -public class StrategyArmoryTest { +public class StrategyArmoryDispatchTest { @Resource private IStrategyArmory strategyArmory; - @Test + @Resource + private IStrategyDispatch strategyDispatch; + + @Before public void test(){ boolean success=strategyArmory.assembleLotteryStrategy(100001l); + log.info(String.valueOf(success)); } @Test public void test_getRandomAward(){ - log.info("测试:{}", strategyArmory.getRandomAwardId(100001l)); - log.info("测试:{}", strategyArmory.getRandomAwardId(100001l)); - log.info("测试:{}", strategyArmory.getRandomAwardId(100001l)); - - + 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")); } + } \ No newline at end of file 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..06a81f86a3034e46cffcae29a84e6b5611b59b33 --- /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; +import org.checkerframework.checker.lock.qual.NewObject; +import org.checkerframework.common.value.qual.ArrayLen; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class StrategyEntity { + /** 抽奖策略ID */ + private Long strategyId; + /** 抽奖策略描述 */ + private String strategyDesc; + /** 抽奖规则模型 rule_weight,rule_blacklist */ + private String ruleModels; + + //解析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..9a59933c64df6ed8c776e45e816a6235cc1123b1 --- /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; + +/** + * @author Fuzhengwei bugstack.cn @小傅哥 + * @description 策略规则实体 + * @create 2023-12-31 15:32 + */ +@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 f338a0c40ce89fa4b25bf65fd8f97999333ed5c4..336bc18ecf931795b32b983cce2fa8776c3d5a36 100644 --- a/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/repository/IStrategyRepository.java +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/repository/IStrategyRepository.java @@ -3,6 +3,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.util.Date; import java.util.List; @@ -12,14 +14,21 @@ import java.util.Map; * @description 策略服务仓储接口 */ public interface IStrategyRepository { + + List queryStrategyAwardList(Long strategyId); - void storeStrategyAwardSearchRateTable(Long strategyId, int size, Map shuffleStrategyAwardSearchRateTable); + void storeStrategyAwardSearchRateTable(String key, int size, Map shuffleStrategyAwardSearchRateTable); int getRateRange(Long strategyId); + int getRateRange(String key); Integer getStrategyAwardAssemble(Long strategyId, Integer rateKey); + StrategyEntity queryStrategyEntityByStrategyId(Long strategyId); + + StrategyRuleEntity queryStrategyRule(Long strategyId, String ruleWeight); + // List queryStrategyAwardList(Long strategyId); // // void storeStrategyAwardSearchRateTable(String key, Integer rateRange, Map strategyAwardSearchRateTable); 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 a13ae12218c733ff9edff9cba112c6860ec97f05..e6536e692e3affa2839ed5591e3da5076f5ef05f 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 @@ -14,13 +14,6 @@ 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 0000000000000000000000000000000000000000..0393a2cd74270fd3a0099fbf25230c21f8ca4caa --- /dev/null +++ b/xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/IStrategyDispatch.java @@ -0,0 +1,23 @@ +package cn.bugstack.domain.strategy.service.armory; + + +/** + * 策略抽奖调度 + */ +public interface IStrategyDispatch { + /** + * 获取抽奖策略装配的随机结果 + * + * @param strategyId 策略ID + * @return 抽奖结果 + */ + Integer getRandomAwardId(Long strategyId); + + /** + * 权重抽奖 + * + * @param strategyId 策略ID + * @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/StrategyArmoryDispatch.java similarity index 54% rename from xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmory.java rename to xfg-frame-archetype-lite-domain/src/main/java/cn/bugstack/domain/strategy/service/armory/StrategyArmoryDispatch.java index f62aff04dd46cae04e3be97175db6cd301e43525..5416ed62d9752f4f290b90a86b57bb6d65d51a6b 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/StrategyArmoryDispatch.java @@ -1,7 +1,11 @@ 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; @@ -17,7 +21,7 @@ import java.util.*; */ @Slf4j @Service -public class StrategyArmory implements IStrategyArmory { +public class StrategyArmoryDispatch implements IStrategyArmory,IStrategyDispatch { @Resource private IStrategyRepository repository; @@ -26,7 +30,36 @@ public class StrategyArmory implements IStrategyArmory { public boolean assembleLotteryStrategy(Long strategyId) { //取得了配置实体类 List strategyAwardEntities=repository.queryStrategyAwardList(strategyId); + assembleLotteryStrategy(String.valueOf(strategyId), strategyAwardEntities); + + //权重策略配置 -适用于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> ruleWeightMap = strategyRuleEntity.getRuleWeightValues(); + Set keys=ruleWeightMap.keySet(); + + //取原来的奖品集合 然后过滤掉里面不符合权重规则的奖品 + for (String key : keys) { + List ruleWeightValues = ruleWeightMap.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) { //最小的概率 BigDecimal minAwardRate=strategyAwardEntities.stream() .map(StrategyAwardEntity :: getAwardRate) @@ -61,11 +94,11 @@ public class StrategyArmory implements IStrategyArmory { } // 8. 存放到 Redis - repository.storeStrategyAwardSearchRateTable(strategyId, shuffleStrategyAwardSearchRateTable.size(), shuffleStrategyAwardSearchRateTable); + repository.storeStrategyAwardSearchRateTable(key, shuffleStrategyAwardSearchRateTable.size(), shuffleStrategyAwardSearchRateTable); - return true; } + @Override public Integer getRandomAwardId(Long strategyId) { // 分布式部署下,不一定为当前应用做的策略装配。也就是值不一定会保存到本应用,而是分布式应用,所以需要从 Redis 中获取。 @@ -75,5 +108,14 @@ public class StrategyArmory implements IStrategyArmory { } + @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(strategyId, new SecureRandom().nextInt(rateRange)); + } + } diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/adapter/repository/StrategyRepository.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/adapter/repository/StrategyRepository.java index 517cfc6cf551216bc0abe2b22f2376e1f2ed019b..7aec56593ac81e2d765260b19c065c3bfdcbb344 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/adapter/repository/StrategyRepository.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/adapter/repository/StrategyRepository.java @@ -1,6 +1,8 @@ package cn.bugstack.infrastructure.adapter.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.dao.IStrategyAwardDao; import cn.bugstack.infrastructure.dao.IStrategyDao; @@ -34,10 +36,10 @@ public class StrategyRepository implements IStrategyRepository { // @Resource // private IRaffleActivityDao raffleActivityDao; -// @Resource -// private IStrategyDao strategyDao; -// @Resource -// private IStrategyRuleDao strategyRuleDao; + @Resource + private IStrategyDao strategyDao; + @Resource + private IStrategyRuleDao strategyRuleDao; // @Resource // private IRaffleActivityAccountDao raffleActivityAccountDao; @@ -91,11 +93,11 @@ public class StrategyRepository implements IStrategyRepository { * 简单来说,getMap 方法返回的 RMap 对象是懒加载的,只有在你实际进行操作时,Redis 数据库中的数据结构才会被创建或修改。 */ @Override - public void storeStrategyAwardSearchRateTable(Long strategyId, int size, Map shuffleStrategyAwardSearchRateTable) { + public void storeStrategyAwardSearchRateTable(String key, int size, Map shuffleStrategyAwardSearchRateTable) { // 1. 存储抽奖策略范围值,如10000,用于生成1000以内的随机数 - redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId, size); + redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, size); // 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(shuffleStrategyAwardSearchRateTable); } @@ -105,11 +107,54 @@ public class StrategyRepository implements IStrategyRepository { return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + strategyId); } + @Override + public int getRateRange(String key) { + return redisService.getValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key); + } + @Override public Integer getStrategyAwardAssemble(Long strategyId, Integer rateKey) { return redisService.getFromMap(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + strategyId,rateKey); } + @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 strategyReq=new StrategyRule(); + strategyReq.setStrategyId(strategyId); + strategyReq.setRuleModel(ruleModel); + + StrategyRule strategyRule=strategyRuleDao.queryStrategyRule(strategyReq); + return StrategyRuleEntity.builder() + .strategyId(strategyRule.getStrategyId()) + .awardId(strategyRule.getAwardId()) + .ruleType(strategyRule.getRuleType()) + .ruleModel(strategyRule.getRuleModel()) + .ruleValue(strategyRule.getRuleValue()) + .ruleDesc(strategyRule.getRuleDesc()) + .build(); + } + // // @Override diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/Strategy.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/Strategy.java index 9065cd3da72c24db84220ff051112ec2c70e2957..f2b98a5fb673b1c038a73069d5d5035c51a607aa 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/Strategy.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/Strategy.java @@ -19,5 +19,6 @@ public class Strategy { private Date createTime; private Date updateTime; + private String ruleModels; } diff --git a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/StrategyRule.java b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/StrategyRule.java index 1c41e613b1bc565a6e6254bda59459f7c491aabd..80709ccf122c1285afca749cd86186e94aed3888 100644 --- a/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/StrategyRule.java +++ b/xfg-frame-archetype-lite-infrastructure/src/main/java/cn/bugstack/infrastructure/dao/po/StrategyRule.java @@ -6,9 +6,9 @@ import java.util.Date; @Data public class StrategyRule { private Long id; - private Integer strategyId; + private Long strategyId; private Integer awardId; - private Byte ruleType; + private Integer ruleType; private String ruleModel; private String ruleValue; private String ruleDesc; 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..6580aa149fef4980b6752c895c4cfa3112262a14 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;