From 8ff266ff417c3c6213af929946210f41dc8cfcd4 Mon Sep 17 00:00:00 2001 From: zhangsan <646228430@qq.com> Date: Sat, 28 Jun 2025 11:33:26 +0800 Subject: [PATCH] =?UTF-8?q?6.28=20=E4=BA=BA=E7=BE=A4=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E8=BF=87=E6=BB=A4=EF=BC=8C=E6=B4=BB=E5=8A=A8?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=AF=B9xx=E7=94=A8=E6=88=B7=E5=8F=AF?= =?UTF-8?q?=E8=A7=81=E3=80=81=E5=8F=AF=E5=8F=82=E4=B8=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mysql/sql/0626group_buying_sys.sql | 2 +- .../IIndexGroupBuyMarketServiceTest.java | 16 ++++++ .../whut/test/domain/tag/ITagServiceTest.java | 6 +++ .../repository/IActivityRepository.java | 2 + .../valobj/GroupBuyActivityDiscountVO.java | 31 ++++++++++- .../activity/model/valobj/TagScopeEnumVO.java | 23 ++++++++ .../discount/impl/MJCalculateService.java | 2 +- .../discount/impl/NCalculateService.java | 2 +- .../discount/impl/ZJCalculateService.java | 4 +- .../discount/impl/ZKCalculateService.java | 2 +- .../DefaultActivityStrategyFactory.java | 4 ++ .../activity/service/trial/node/EndNode.java | 11 ++-- .../service/trial/node/MarketNode.java | 12 +++-- .../activity/service/trial/node/TagNode.java | 52 +++++++++++++++++++ .../repository/ActivityRepository.java | 17 ++++++ .../adapter/repository/TagRepository.java | 6 ++- .../infrastructure/redis/IRedisService.java | 5 ++ 17 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/TagScopeEnumVO.java create mode 100644 group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/node/TagNode.java diff --git a/docs/dev-ops/mysql/sql/0626group_buying_sys.sql b/docs/dev-ops/mysql/sql/0626group_buying_sys.sql index 90689f0..4305e19 100644 --- a/docs/dev-ops/mysql/sql/0626group_buying_sys.sql +++ b/docs/dev-ops/mysql/sql/0626group_buying_sys.sql @@ -95,7 +95,7 @@ CREATE TABLE `group_buy_activity` ( -- ---------------------------- -- Records of group_buy_activity -- ---------------------------- -INSERT INTO `group_buy_activity` VALUES (1, 100123, '测试活动', '25120207', 0, 1, 1, 15, 1, '2025-06-19 10:19:40', '2025-06-19 10:19:40', '1', '1', '2025-06-19 10:19:40', '2025-06-26 15:27:48'); +INSERT INTO `group_buy_activity` VALUES (1, 100123, '测试活动', '25120207', 0, 1, 1, 15, 1, '2025-06-19 10:19:40', '2025-06-19 10:19:40', 'RQ_KJHKL98UU78H66554GFDV', '1', '2025-06-19 10:19:40', '2025-06-26 15:27:48'); -- ---------------------------- -- Table structure for group_buy_discount diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/domain/activity/IIndexGroupBuyMarketServiceTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/domain/activity/IIndexGroupBuyMarketServiceTest.java index 2a6a23a..734b0cb 100644 --- a/group-buying-sys-app/src/test/java/edu/whut/test/domain/activity/IIndexGroupBuyMarketServiceTest.java +++ b/group-buying-sys-app/src/test/java/edu/whut/test/domain/activity/IIndexGroupBuyMarketServiceTest.java @@ -23,6 +23,9 @@ public class IIndexGroupBuyMarketServiceTest { @Resource private IIndexGroupBuyMarketService indexGroupBuyMarketService; + /** + * 测试人群标签功能的时候,可以进入 ITagServiceTest#test_tag_job 执行人群写入 + */ @Test public void test_indexMarketTrial() throws Exception { MarketProductEntity marketProductEntity = new MarketProductEntity(); @@ -36,6 +39,19 @@ public class IIndexGroupBuyMarketServiceTest { log.info("返回结果:{}", JSON.toJSONString(trialBalanceEntity)); } + @Test + public void test_indexMarketTrial_no_tag() throws Exception { + MarketProductEntity marketProductEntity = new MarketProductEntity(); + marketProductEntity.setUserId("user01"); + marketProductEntity.setSource("s01"); + marketProductEntity.setChannel("c01"); + marketProductEntity.setGoodsId("9890001"); + + TrialBalanceEntity trialBalanceEntity = indexGroupBuyMarketService.indexMarketTrial(marketProductEntity); + log.info("请求参数:{}", JSON.toJSONString(marketProductEntity)); + log.info("返回结果:{}", JSON.toJSONString(trialBalanceEntity)); + } + @Test public void test_indexMarketTrial_error() throws Exception { MarketProductEntity marketProductEntity = new MarketProductEntity(); diff --git a/group-buying-sys-app/src/test/java/edu/whut/test/domain/tag/ITagServiceTest.java b/group-buying-sys-app/src/test/java/edu/whut/test/domain/tag/ITagServiceTest.java index 7f08116..0afaaa7 100644 --- a/group-buying-sys-app/src/test/java/edu/whut/test/domain/tag/ITagServiceTest.java +++ b/group-buying-sys-app/src/test/java/edu/whut/test/domain/tag/ITagServiceTest.java @@ -36,4 +36,10 @@ public class ITagServiceTest { log.info("gudebai 不存在,预期结果为 false,测试结果:{}", bitSet.get(redisService.getIndexFromUserId("gudebai"))); } + @Test + public void test_null_tag_bitmap() { + RBitSet bitSet = redisService.getBitSet("null"); + log.info("测试结果:{}", bitSet.isExists()); + } + } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java index d19e310..6f10491 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/adapter/repository/IActivityRepository.java @@ -14,4 +14,6 @@ public interface IActivityRepository { SCSkuActivityVO querySCSkuActivityBySCGoodsId(String source, String channel, String goodsId); + boolean isTagCrowdRange(String tagId, String userId); + } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/GroupBuyActivityDiscountVO.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/GroupBuyActivityDiscountVO.java index 42da3a6..25e0919 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/GroupBuyActivityDiscountVO.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/GroupBuyActivityDiscountVO.java @@ -1,11 +1,14 @@ package edu.whut.domain.activity.model.valobj; +import edu.whut.types.common.Constants; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.apache.commons.lang3.StringUtils; import java.util.Date; +import java.util.Objects; /** * 拼团活动营销配置值对象 @@ -73,10 +76,36 @@ public class GroupBuyActivityDiscountVO { */ private String tagId; /** - * 人群标签规则范围 + * 人群标签规则范围,如果有值,说明有限制 */ private String tagScope; + /** + * 可见限制,可以看见不等于能参加拼团 + * 只要存在这样一个值,那么首次获得的默认值就是 false,false代表有限制 + */ + public boolean isVisible() { + if(StringUtils.isBlank(this.tagScope)) return TagScopeEnumVO.VISIBLE.getAllow(); //等价于return true,放行 + String[] split = this.tagScope.split(Constants.SPLIT); + if (split.length > 0 && Objects.equals(split[0], "1") && StringUtils.isNotBlank(split[0])) { + return TagScopeEnumVO.VISIBLE.getRefuse(); //等价于return false,待后续校验 + } + return TagScopeEnumVO.VISIBLE.getAllow(); + } + + /** + * 参与限制 + * 只要存在这样一个值,那么首次获得的默认值就是 false + */ + public boolean isEnable() { + if(StringUtils.isBlank(this.tagScope)) return TagScopeEnumVO.VISIBLE.getAllow(); + String[] split = this.tagScope.split(Constants.SPLIT); + if (split.length == 2 && Objects.equals(split[1], "2") && StringUtils.isNotBlank(split[1])) { + return TagScopeEnumVO.ENABLE.getRefuse(); + } + return TagScopeEnumVO.ENABLE.getAllow(); + } + @Getter @Builder @AllArgsConstructor diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/TagScopeEnumVO.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/TagScopeEnumVO.java new file mode 100644 index 0000000..44b6789 --- /dev/null +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/model/valobj/TagScopeEnumVO.java @@ -0,0 +1,23 @@ +package edu.whut.domain.activity.model.valobj; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 活动人群标签作用域范围枚举 + */ +@Getter +@AllArgsConstructor +@NoArgsConstructor +public enum TagScopeEnumVO { + + VISIBLE(true,false,"是否可看见拼团"), + ENABLE(true, false,"是否可参与拼团"), + ; + + private Boolean allow; + private Boolean refuse; + private String desc; + +} diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/MJCalculateService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/MJCalculateService.java index 0f0a9c7..80dd6d3 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/MJCalculateService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/MJCalculateService.java @@ -17,7 +17,7 @@ public class MJCalculateService extends AbstractDiscountCalculateService { @Override public BigDecimal doCalculate(BigDecimal originalPrice, GroupBuyActivityDiscountVO.GroupBuyDiscount groupBuyDiscount) { - log.info("优惠策略折扣计算:{}", groupBuyDiscount.getDiscountType().getCode()); + log.info("满减优惠策略折扣计算规则,0代表人人可参与,1代表指定标签人群参与:{}", groupBuyDiscount.getDiscountType().getCode()); // 获取折扣表达式 - 100,10 满100减10元 String marketExpr = groupBuyDiscount.getMarketExpr(); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/NCalculateService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/NCalculateService.java index c5a3924..afbb47a 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/NCalculateService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/NCalculateService.java @@ -15,7 +15,7 @@ public class NCalculateService extends AbstractDiscountCalculateService { @Override public BigDecimal doCalculate(BigDecimal originalPrice, GroupBuyActivityDiscountVO.GroupBuyDiscount groupBuyDiscount) { - log.info("优惠策略折扣计算:{}", groupBuyDiscount.getDiscountType().getCode()); + log.info("N元购优惠策略折扣计算规则,0代表人人可参与,1代表指定标签人群参与:{}", groupBuyDiscount.getDiscountType().getCode()); // 折扣表达式 - 直接为优惠后的金额 String marketExpr = groupBuyDiscount.getMarketExpr(); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZJCalculateService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZJCalculateService.java index 5c990ec..ebae346 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZJCalculateService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZJCalculateService.java @@ -15,12 +15,12 @@ public class ZJCalculateService extends AbstractDiscountCalculateService { @Override public BigDecimal doCalculate(BigDecimal originalPrice, GroupBuyActivityDiscountVO.GroupBuyDiscount groupBuyDiscount) { - log.info("优惠策略折扣计算:{}", groupBuyDiscount.getDiscountType().getCode()); + log.info("直减优惠策略折扣计算规则,0代表人人可参与,1代表指定标签人群参与:{}", groupBuyDiscount.getDiscountType().getCode()); // 折扣表达式 - 直减为扣减金额 String marketExpr = groupBuyDiscount.getMarketExpr(); - // 折扣价格 + // 折扣后的实际支付金额 BigDecimal deductionPrice = originalPrice.subtract(new BigDecimal(marketExpr)); // 判断折扣后金额,最低支付1分钱 diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZKCalculateService.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZKCalculateService.java index c4ad7b6..c5f0e9b 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZKCalculateService.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/discount/impl/ZKCalculateService.java @@ -15,7 +15,7 @@ public class ZKCalculateService extends AbstractDiscountCalculateService { @Override public BigDecimal doCalculate(BigDecimal originalPrice, GroupBuyActivityDiscountVO.GroupBuyDiscount groupBuyDiscount) { - log.info("优惠策略折扣计算:{}", groupBuyDiscount.getDiscountType().getCode()); + log.info("折扣优惠策略折扣计算规则,0代表人人可参与,1代表指定标签人群参与:{}", groupBuyDiscount.getDiscountType().getCode()); // 折扣表达式 - 折扣百分比 String marketExpr = groupBuyDiscount.getMarketExpr(); diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/factory/DefaultActivityStrategyFactory.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/factory/DefaultActivityStrategyFactory.java index 96431a6..49ab825 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/factory/DefaultActivityStrategyFactory.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/factory/DefaultActivityStrategyFactory.java @@ -34,6 +34,10 @@ public class DefaultActivityStrategyFactory { private SkuVO skuVO; // 折扣价格 private BigDecimal deductionPrice; + // 活动可见性限制 + private boolean visible; + // 活动 + private boolean enable; } } diff --git a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/node/EndNode.java b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/node/EndNode.java index 2625e44..0f2a159 100644 --- a/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/node/EndNode.java +++ b/group-buying-sys-domain/src/main/java/edu/whut/domain/activity/service/trial/node/EndNode.java @@ -7,8 +7,6 @@ import edu.whut.domain.activity.model.valobj.SkuVO; import edu.whut.domain.activity.service.trial.AbstractGroupBuyMarketSupport; import edu.whut.domain.activity.service.trial.factory.DefaultActivityStrategyFactory; import edu.whut.types.design.framework.tree.StrategyHandler; -import lombok.AllArgsConstructor; -import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -24,8 +22,9 @@ public class EndNode extends AbstractGroupBuyMarketSupport discountCalculateServiceMap; + private final TagNode tagNode; + /** * 异步加载数据 * @param requestParameter @@ -57,8 +59,10 @@ public class MarketNode extends AbstractGroupBuyMarketSupport skuVOFutureTask = new FutureTask<>(querySkuVOFromDBThreadTask); threadPoolExecutor.execute(skuVOFutureTask); - // 写入上下文 - 对于一些复杂场景,获取数据的操作,有时候会在下N个节点获取,这样前置查询数据,可以提高接口响应效率 + // 写入上下文- 对于一些复杂场景,获取数据的操作,有时候会在下N个节点获取,这样前置查询数据,可以提高接口响应效率 + // 写入活动配置信息 dynamicContext.setGroupBuyActivityDiscountVO(groupBuyActivityDiscountVOFutureTask.get(timeout, TimeUnit.MINUTES)); + // 写入商品信息 dynamicContext.setSkuVO(skuVOFutureTask.get(timeout, TimeUnit.MINUTES)); log.info("拼团商品查询试算服务-MarketNode userId:{} 异步线程加载数据「GroupBuyActivityDiscountVO、SkuVO」完成", requestParameter.getUserId()); @@ -75,13 +79,14 @@ public class MarketNode extends AbstractGroupBuyMarketSupport { + + @Resource + private EndNode endNode; + + @Override + protected TrialBalanceEntity doApply(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception { + // 获取拼团活动配置 + GroupBuyActivityDiscountVO groupBuyActivityDiscountVO = dynamicContext.getGroupBuyActivityDiscountVO(); + + String tagId = groupBuyActivityDiscountVO.getTagId(); + boolean visible = groupBuyActivityDiscountVO.isVisible(); + boolean enable = groupBuyActivityDiscountVO.isEnable(); + + // 人群标签配置为空,说明该活动不限定人群参与 + if (StringUtils.isBlank(tagId)) { + dynamicContext.setVisible(true); + dynamicContext.setEnable(true); + return router(requestParameter, dynamicContext); + } + + // 是否在人群范围内;visible、enable 如果值为 ture 则表示没有配置拼团限制,那么就直接保证为 true 即可 + boolean isWithin = repository.isTagCrowdRange(tagId, requestParameter.getUserId()); + dynamicContext.setVisible(visible || isWithin); + dynamicContext.setEnable(enable || isWithin); + return router(requestParameter, dynamicContext); + } + + @Override + public StrategyHandler get(MarketProductEntity requestParameter, DefaultActivityStrategyFactory.DynamicContext dynamicContext) throws Exception { + return endNode; + } + +} diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java index 9195542..387ff7c 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/ActivityRepository.java @@ -13,7 +13,10 @@ import edu.whut.infrastructure.dao.po.GroupBuyActivity; import edu.whut.infrastructure.dao.po.GroupBuyDiscount; import edu.whut.infrastructure.dao.po.SCSkuActivity; import edu.whut.infrastructure.dao.po.Sku; +import edu.whut.infrastructure.redis.IRedisService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RBitSet; import org.springframework.stereotype.Repository; import javax.annotation.Resource; @@ -23,6 +26,7 @@ import javax.annotation.Resource; */ @Repository @RequiredArgsConstructor +@Slf4j public class ActivityRepository implements IActivityRepository { private final IGroupBuyActivityDao groupBuyActivityDao; @@ -33,6 +37,8 @@ public class ActivityRepository implements IActivityRepository { private final ISCSkuActivityDao skuActivityDao; + private final IRedisService redisService; + @Override public GroupBuyActivityDiscountVO queryGroupBuyActivityDiscountVO(Long activityId) { GroupBuyActivity groupBuyActivityRes = groupBuyActivityDao.queryValidGroupBuyActivityId(activityId); @@ -97,4 +103,15 @@ public class ActivityRepository implements IActivityRepository { .build(); } + @Override + public boolean isTagCrowdRange(String tagId, String userId) { + //根据标签id获取对应位图 + RBitSet bitSet = redisService.getBitSet(tagId); + if (!bitSet.isExists()) { + return true; + } + // 判断用户是否存在人群中 + return bitSet.get(redisService.getIndexFromUserId(userId)); + } + } diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TagRepository.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TagRepository.java index 3dadef0..fe2d9c6 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TagRepository.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/adapter/repository/TagRepository.java @@ -10,6 +10,7 @@ import edu.whut.infrastructure.dao.po.CrowdTagsDetail; import edu.whut.infrastructure.dao.po.CrowdTagsJob; import edu.whut.infrastructure.redis.IRedisService; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.redisson.api.RBitSet; import org.springframework.dao.DuplicateKeyException; import org.springframework.stereotype.Repository; @@ -21,6 +22,7 @@ import javax.annotation.Resource; */ @Repository @RequiredArgsConstructor +@Slf4j public class TagRepository implements ITagRepository { private final ICrowdTagsDao crowdTagsDao; @@ -73,11 +75,11 @@ public class TagRepository implements ITagRepository { try { crowdTagsDetailDao.addCrowdTagsUserId(crowdTagsDetailReq); - // 获取BitSet RBitSet bitSet = redisService.getBitSet(tagId); - bitSet.set(redisService.getIndexFromUserId(userId), true); + bitSet.set(redisService.getIndexFromUserId(userId)); } catch (DuplicateKeyException ignore) { + log.info("用户id{}已在人群标签{}中",userId,tagId); // 忽略唯一索引冲突 } } diff --git a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/redis/IRedisService.java b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/redis/IRedisService.java index 8792ad7..856f3ea 100644 --- a/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/redis/IRedisService.java +++ b/group-buying-sys-infrastructure/src/main/java/edu/whut/infrastructure/redis/IRedisService.java @@ -283,6 +283,11 @@ public interface IRedisService { //位图 RBitSet getBitSet(String key); + /** + * 将userId 映射到一个哈希值,指定需存入位图的位置 + * @param userId + * @return + */ default int getIndexFromUserId(String userId) { try { MessageDigest md = MessageDigest.getInstance("MD5");