Browse Source

优化和开奖通知

cup 3 years ago
parent
commit
4c88a9b905

+ 49 - 22
mp-quartz/src/main/java/com/qs/mp/quartz/task/MarketingTask.java

@@ -1,21 +1,30 @@
 package com.qs.mp.quartz.task;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.qs.mp.admin.domain.Marketing;
 import com.qs.mp.admin.service.IMarketingAwardsService;
 import com.qs.mp.admin.service.IMarketingService;
 import com.qs.mp.common.core.redis.DistributedLocker;
 import com.qs.mp.common.core.redis.RedisCache;
 import com.qs.mp.common.enums.MarketingStatusEnum;
+import com.qs.mp.common.enums.UserTypeEnum;
 import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.framework.domain.WxSubscribeMessage;
+import com.qs.mp.framework.service.IWxSubscribeMessage;
+import com.qs.mp.user.domain.MarketingUserCode;
 import com.qs.mp.user.service.IMarketingUserCodeService;
 import org.redisson.Redisson;
 import org.redisson.api.RedissonClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.io.IOException;
 import java.util.Date;
+import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 
@@ -28,7 +37,7 @@ import java.util.concurrent.TimeUnit;
 @Component("marketingTask")
 public class MarketingTask {
 
-    public static final String MARKETING_LOTTERY_KEY = "MARKETING_LOTTERY_KEY";
+    public static final String MARKETING_LOTTERY_KEY = "MARKETING_LOTTERY_KEY:%s";
 
 
     @Autowired
@@ -37,35 +46,53 @@ public class MarketingTask {
     @Autowired
     private IMarketingService marketingService;
 
+    @Autowired
+    private IWxSubscribeMessage wxSubscribeMessage;
+
+    @Autowired
+    private IMarketingUserCodeService marketingUserCodeService;
+
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
 
     /**
      * 开奖任务方法
      */
     public void lottery() {
-
-        // 加锁
-        if (!distributedLocker.tryLock(MARKETING_LOTTERY_KEY)) {
+        // 获取结束时间小于等于当前时间且未开奖的活动
+        Date now = DateUtils.getNowDate();
+        List<Marketing> marketingList = marketingService.list(new LambdaQueryWrapper<Marketing>()
+                .eq(Marketing::getTriggerStatus, 0)
+                .eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue())
+                .le(Marketing::getEndTime, now));
+        if (CollectionUtils.isEmpty(marketingList)) {
             return;
         }
-        try {
-            // 获取结束时间小于等于当前时间且未开奖的一个活动
-            Date now = DateUtils.getNowDate();
-            Marketing marketing = marketingService.getOne(new LambdaQueryWrapper<Marketing>()
-                    .eq(Marketing::getTriggerStatus, 0)
-                    .eq(Marketing::getIsOn, MarketingStatusEnum.ON.getValue())
-                    .le(Marketing::getEndTime, now)
-                    .last("limit 1"));
-            if (Objects.isNull(marketing)) {
-                return;
-            }
-
-            // 开奖
-            marketingService.lottery(marketing);
-
 
-        }finally {
-            // 释放锁
-            distributedLocker.unlock(MARKETING_LOTTERY_KEY);
+        for (Marketing marketing : marketingList) {
+            String lockKey = String.format(MARKETING_LOTTERY_KEY, marketing.getId());
+            // 加锁
+            if (!distributedLocker.tryLock(lockKey)) {
+                continue;
+            }
+            try {
+                // 开奖
+                marketingService.lottery(marketing);
+
+                // 获取所有的参与用户
+                List<MarketingUserCode> userCodeList = marketingUserCodeService.list(new LambdaQueryWrapper<MarketingUserCode>()
+                        .eq(MarketingUserCode::getMarketingId, marketing.getId())
+                        .eq(MarketingUserCode::getUserType, UserTypeEnum.ORDINARY.getValue()));
+                for (MarketingUserCode marketingUserCode : userCodeList) {
+                    // 发送开奖订阅通知
+                    wxSubscribeMessage.sendMarketingLottery(marketingUserCode.getUserId(), marketing);
+                }
+            } catch (Exception e) {
+                LogUtil.error(logger, e, "活动开奖异常。marketingId:{0}", marketing.getId());
+            } finally {
+                // 释放锁
+                distributedLocker.unlock(lockKey);
+            }
         }
 
 

+ 21 - 28
mp-service/src/main/java/com/qs/mp/admin/service/impl/CouponServiceImpl.java

@@ -79,19 +79,7 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
 	@Transactional(rollbackFor = Exception.class)
 	public void distributeByMarketing(Long userId, String couponId) {
 		Coupon coupon = getById(couponId);
-		UserCoupon userCoupon = new UserCoupon();
-		userCoupon.setId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
-		userCoupon.setUserId(userId);
-		userCoupon.setVerifyCode(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
-		userCoupon.setCouponId(coupon.getCouponId());
-		if (coupon.getDueDays() > 0) {
-			userCoupon.setValidStart(DateUtils.getToday());
-			userCoupon.setValidEnd(DateUtils.addDays(userCoupon.getValidStart(), coupon.getDueDays() - 1));
-		} else {
-			userCoupon.setValidStart(coupon.getValidStart());
-			userCoupon.setValidEnd(coupon.getValidEnd());
-		}
-		userCoupon.setStatus(UserCouponStatusEnum.UNUSED);
+		UserCoupon userCoupon = getUserCoupon(userId, coupon);
 		userCoupon.setUseAreaDesc(coupon.getUseArea().getDesc());
 		userCouponService.save(userCoupon);
 		boolean rtn = update(new LambdaUpdateWrapper<Coupon>().set(Coupon::getDistributeQty, coupon.getDistributeQty() + 1)
@@ -104,22 +92,10 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
   @Transactional(rollbackFor = Exception.class)
   public void distribute(Ticket ticket, Long userId, String couponId) {
     Coupon coupon = getById(couponId);
-    UserCoupon userCoupon = new UserCoupon();
-    userCoupon.setId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
-    userCoupon.setUserId(userId);
-    userCoupon.setVerifyCode(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
-    userCoupon.setCouponId(coupon.getCouponId());
-    if (coupon.getDueDays() > 0) {
-      userCoupon.setValidStart(DateUtils.getToday());
-      userCoupon.setValidEnd(DateUtils.addDays(userCoupon.getValidStart(), coupon.getDueDays() - 1));
-    } else {
-      userCoupon.setValidStart(coupon.getValidStart());
-      userCoupon.setValidEnd(coupon.getValidEnd());
-    }
-    userCoupon.setStatus(UserCouponStatusEnum.UNUSED);
+	UserCoupon userCoupon = getUserCoupon(userId, coupon);
 
 
-    // 确定限定范围
+		// 确定限定范围
     if (coupon.getUseArea() == CouponUseAreaEnum.POST_SCOPE) {
       UserTicketOrderItem orderItem = userTicketOrderItemService.queryFinishedOrderItem(userId, ticket.getTicketId());
 			UserTicketOrder ticketOrder = userTicketOrderService.getById(orderItem.getOrderId());
@@ -144,7 +120,24 @@ public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> impleme
 		Assert.isTrue(rtn, "领取优惠券奖品,更新优惠券发放量失败。couponId:" + coupon.getCouponId());
   }
 
-  @Override
+	private UserCoupon getUserCoupon(Long userId, Coupon coupon) {
+		UserCoupon userCoupon = new UserCoupon();
+		userCoupon.setId(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
+		userCoupon.setUserId(userId);
+		userCoupon.setVerifyCode(bizIdGenerator.newIdWithUidSharding(String.valueOf(userId)));
+		userCoupon.setCouponId(coupon.getCouponId());
+		if (coupon.getDueDays() > 0) {
+			userCoupon.setValidStart(DateUtils.getToday());
+			userCoupon.setValidEnd(DateUtils.addDays(userCoupon.getValidStart(), coupon.getDueDays() - 1));
+		} else {
+			userCoupon.setValidStart(coupon.getValidStart());
+			userCoupon.setValidEnd(coupon.getValidEnd());
+		}
+		userCoupon.setStatus(UserCouponStatusEnum.UNUSED);
+		return userCoupon;
+	}
+
+	@Override
 	@Transactional
 	public void saveCoupon(Coupon coupon, List<CouponTicket> ticketList) {
 		boolean res = couponService.save(coupon);

+ 40 - 39
mp-service/src/main/java/com/qs/mp/admin/service/impl/MarketingServiceImpl.java

@@ -50,10 +50,10 @@ import java.util.stream.Collectors;
 public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing> implements IMarketingService {
 
     // 内部奖池
-    public static final String MARKETING_LOTTERY_INSIDE_POOL = "MARKETING_LOTTERY_INSIDE_POOL";
+    public static final String MARKETING_LOTTERY_INSIDE_POOL = "MARKETING_LOTTERY_INSIDE_POOL:%s";
 
     // 普通奖池
-    public static final String MARKETING_LOTTERY_ORDINARY_POOL = "MARKETING_LOTTERY_ORDINARY_POOL";
+    public static final String MARKETING_LOTTERY_ORDINARY_POOL = "MARKETING_LOTTERY_ORDINARY_POOL:%s";
 
 
     @Autowired
@@ -97,6 +97,11 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
     @Transactional(rollbackFor = Exception.class)
     public void lottery(Marketing marketing) {
 
+        // 用户抽奖池
+        String userLotteryPool = String.format(MARKETING_LOTTERY_ORDINARY_POOL, marketing.getId());
+        // 内部抽奖池
+        String insideLotteryPool = String.format(MARKETING_LOTTERY_INSIDE_POOL, marketing.getId());
+
         // 获取奖级信息
         List<MarketingAwards> marketingAwardsList = marketingAwardsService.list(new LambdaQueryWrapper<MarketingAwards>()
                 .eq(MarketingAwards::getMarketingId, marketing.getId()));
@@ -126,7 +131,8 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
         // 获取一定数量的内定人员设置抽奖码加入抽奖关系表和抽奖池
         List<SysUser> insideUserList = sysUserService.selectUserListByRand(UserTypeEnum.INSIDE.getValue(), insideNum);
 
-        Set<String> codeList = new HashSet<>();
+        Set<String> insideCodes = new HashSet<>();
+        Set<String> userCodes = new HashSet<>();
         for (SysUser sysUser : insideUserList) {
             // 生成抽奖码
             String code = MarketingUtils.generatePrizeCode();
@@ -141,7 +147,7 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
                 }
                 break;
             }
-            codeList.add(code);
+            insideCodes.add(code);
             MarketingUserCode marketingUserCode = new MarketingUserCode();
             marketingUserCode.setMarketingId(marketing.getId());
             marketingUserCode.setUserId(sysUser.getUserId());
@@ -153,19 +159,18 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
             marketingUserCodeService.save(marketingUserCode);
         }
         // 将抽奖码放入内部抽奖池
-        redisCache.setCacheSet(MARKETING_LOTTERY_INSIDE_POOL, codeList);
+        redisCache.setCacheSet(insideLotteryPool, insideCodes);
 
 
         // 获取普通用户所有的抽奖码
         List<MarketingUserCode> userCodeList = marketingUserCodeService.list(new LambdaQueryWrapper<MarketingUserCode>()
                 .eq(MarketingUserCode::getMarketingId, marketing.getId())
                 .eq(MarketingUserCode::getUserType, UserTypeEnum.ORDINARY.getValue()));
-        codeList.clear();
         if (CollectionUtils.isNotEmpty(userCodeList)) {
-            codeList = userCodeList.stream().map(MarketingUserCode::getCode).collect(Collectors.toSet());
+            userCodes = userCodeList.stream().map(MarketingUserCode::getCode).collect(Collectors.toSet());
         }
         // 将抽奖码放入普通抽奖池
-        redisCache.setCacheSet(MARKETING_LOTTERY_ORDINARY_POOL, codeList);
+        redisCache.setCacheSet(userLotteryPool, userCodes);
 
         // 所有中奖名单
         List<MarketingHitPrize> allHitPrizeList = new ArrayList<>();
@@ -191,26 +196,14 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
 
             if (insideNum != 0) {
                 // 设置内部用户抽奖信息
-                List<String> insideCodeList = redisCache.popCacheSet(MARKETING_LOTTERY_INSIDE_POOL, insideNum);
+                List<String> insideCodeList = redisCache.popCacheSet(insideLotteryPool, insideNum);
                 for (String code : insideCodeList) {
                     MarketingUserCode marketingUserCode = marketingUserCodeService.getOne(new LambdaQueryWrapper<MarketingUserCode>()
                             .eq(MarketingUserCode::getMarketingId, marketing.getId())
                             .eq(MarketingUserCode::getCode, code));
 
                     // 设置中奖信息
-                    MarketingHitPrize marketingHitPrize = new MarketingHitPrize();
-                    marketingHitPrize.setId(bizIdGenerator.newId());
-                    marketingHitPrize.setMarketingId(marketing.getId());
-                    marketingHitPrize.setAwardsId(marketingAwards.getId());
-                    marketingHitPrize.setMarketingUserCodeId(marketingUserCode.getId());
-                    marketingHitPrize.setUserId(marketingUserCode.getUserId());
-                    marketingHitPrize.setUserType(marketingUserCode.getUserType());
-
-                    // 随机抽取奖品,[0, list.size)  左闭右开
-                    int randomIndex = RandomUtil.randomInt(0, marketingAwardsPrizeList.size());
-                    marketingHitPrize.setPrizeId(marketingAwardsPrizeList.get(randomIndex).getId());
-
-                    allHitPrizeList.add(marketingHitPrize);
+                    exchangeMarketingHitPrize(marketing, allHitPrizeList, marketingAwards, marketingAwardsPrizeList, marketingUserCode);
                 }
             }
 
@@ -219,7 +212,7 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
             if (userNum > 0) {
                 // 设置普通用户抽奖信息
                 for (int i = 0; i < userNum; i++) {
-                    List<String> insideCodeList = redisCache.popCacheSet(MARKETING_LOTTERY_INSIDE_POOL, 1);
+                    List<String> insideCodeList = redisCache.popCacheSet(userLotteryPool, 1);
                     MarketingUserCode marketingUserCode = marketingUserCodeService.getOne(new LambdaQueryWrapper<MarketingUserCode>()
                             .eq(MarketingUserCode::getMarketingId, marketing.getId())
                             .eq(MarketingUserCode::getCode, insideCodeList.get(0)));
@@ -229,23 +222,9 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
                             .eq(MarketingUserCode::getMarketingId, marketing.getId())
                             .eq(MarketingUserCode::getUserId, marketingUserCode.getUserId()));
                     List<Object> delUserCodeList = list.stream().map(MarketingUserCode::getCode).collect(Collectors.toList());
-                    redisCache.removeSetValueByKey(MARKETING_LOTTERY_ORDINARY_POOL, delUserCodeList);
-
+                    redisCache.removeSetValueByKey(userLotteryPool, delUserCodeList);
+                    MarketingHitPrize marketingHitPrize = exchangeMarketingHitPrize(marketing, allHitPrizeList, marketingAwards, marketingAwardsPrizeList, marketingUserCode);
 
-                    // 设置中奖信息
-                    MarketingHitPrize marketingHitPrize = new MarketingHitPrize();
-                    marketingHitPrize.setId(bizIdGenerator.newId());
-                    marketingHitPrize.setMarketingId(marketing.getId());
-                    marketingHitPrize.setAwardsId(marketingAwards.getId());
-                    marketingHitPrize.setMarketingUserCodeId(marketingUserCode.getId());
-                    marketingHitPrize.setUserId(marketingUserCode.getUserId());
-                    marketingHitPrize.setUserType(marketingUserCode.getUserType());
-
-                    // 随机抽取奖品,[0, list.size)  左闭右开
-                    int randomIndex = RandomUtil.randomInt(0, marketingAwardsPrizeList.size());
-                    marketingHitPrize.setPrizeId(marketingAwardsPrizeList.get(randomIndex).getId());
-
-                    allHitPrizeList.add(marketingHitPrize);
                     userHitPrizeList.add(marketingHitPrize);
 
                     // 更新用户中奖状态
@@ -287,6 +266,28 @@ public class MarketingServiceImpl extends ServiceImpl<MarketingMapper, Marketing
                 .eq(Marketing::getTriggerStatus, 0));
         Assert.isTrue(rtn, "更新活动开奖状态失败。marketingId:" + marketing.getId());
 
+        // 删除抽奖池
+        redisCache.deleteObject(userLotteryPool);
+        redisCache.deleteObject(insideLotteryPool);
+
+    }
+
+    private MarketingHitPrize exchangeMarketingHitPrize(Marketing marketing, List<MarketingHitPrize> allHitPrizeList, MarketingAwards marketingAwards, List<MarketingAwardsPrize> marketingAwardsPrizeList, MarketingUserCode marketingUserCode) {
+        // 设置中奖信息
+        MarketingHitPrize marketingHitPrize = new MarketingHitPrize();
+        marketingHitPrize.setId(bizIdGenerator.newId());
+        marketingHitPrize.setMarketingId(marketing.getId());
+        marketingHitPrize.setAwardsId(marketingAwards.getId());
+        marketingHitPrize.setMarketingUserCodeId(marketingUserCode.getId());
+        marketingHitPrize.setUserId(marketingUserCode.getUserId());
+        marketingHitPrize.setUserType(marketingUserCode.getUserType());
+
+        // 随机抽取奖品,[0, list.size)  左闭右开
+        int randomIndex = RandomUtil.randomInt(0, marketingAwardsPrizeList.size());
+        marketingHitPrize.setPrizeId(marketingAwardsPrizeList.get(randomIndex).getId());
+
+        allHitPrizeList.add(marketingHitPrize);
+        return marketingHitPrize;
     }
 
     @Override

+ 21 - 0
mp-service/src/main/java/com/qs/mp/framework/domain/WxSubscribeMessage.java

@@ -4,6 +4,7 @@
  */
 package com.qs.mp.framework.domain;
 
+import com.qs.mp.admin.domain.Marketing;
 import com.qs.mp.common.utils.DateUtils;
 import java.util.HashMap;
 
@@ -74,6 +75,26 @@ public class WxSubscribeMessage {
 //        page = page + actId ;
         miniprogram_state = state;
     }
+
+
+    /**
+     * 活动开奖消息
+     */
+    public void buildMarketingLotterySuccessMessage(Marketing marketing){
+        template_id = "3y_My-yRmqmGd3-f-vAwNaK4LQeehzXBSNDi_5wcnFI";
+//        page = "/pages/bills/detail?id=" + merchantBill.getBillId() + "&custId=" + merchantBill.getCustId();
+        /**
+         * 活动名称
+         * {{thing1.DATA}}
+         *
+         * 温馨提示
+         * {{thing5.DATA}}
+         */
+        data.put("thing1", new WeappDataValue(marketing.getTitle()));
+        data.put("thing5", new WeappDataValue("看看你中奖了吗?"));
+    }
+
+
 /*
     public void buildBillPaySuccessMessage(MerchantBill merchantBill){
         template_id = "1F2Hrqfr8fS--3CWeUOkDCjP83U6WTcfnBfqG7CYdKM";

+ 12 - 0
mp-service/src/main/java/com/qs/mp/framework/service/IWxSubscribeMessage.java

@@ -1,9 +1,21 @@
 package com.qs.mp.framework.service;
 
 
+import com.qs.mp.admin.domain.Marketing;
+
 /**
  * @author zhongcp
  * @Date 2021/9/22
  */
 public interface IWxSubscribeMessage {
+
+    /**
+     * 发送开奖消息
+     * @param userId
+     * @param marketing
+     * @return
+     */
+    public boolean sendMarketingLottery(Long userId, Marketing marketing);
+
+
 }

+ 14 - 1
mp-service/src/main/java/com/qs/mp/framework/service/impl/WxSubscribeMessageImpl.java

@@ -1,6 +1,7 @@
 package com.qs.mp.framework.service.impl;
 
 import com.alibaba.fastjson.JSON;
+import com.qs.mp.admin.domain.Marketing;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.http.HttpUtils;
 import com.qs.mp.framework.domain.WxSubscribeMessage;
@@ -40,10 +41,22 @@ public class WxSubscribeMessageImpl implements IWxSubscribeMessage {
   @Value("${miniprogram.state}")
   private String state;
 
+  @Override
+  public boolean sendMarketingLottery(Long userId, Marketing marketing) {
+    String openId = getOpenIdByUserId(userId);
+    WxSubscribeMessage wxSubscribeMessage = new WxSubscribeMessage(userAppId, openId, state);
+    wxSubscribeMessage.buildMarketingLotterySuccessMessage(marketing);
+    return this.sendNotify(userId, marketing.getId().toString(), wxSubscribeMessage);
+  }
+
+  private String getOpenIdByUserId(Long userId) {
+    return sysUserService.selectUserById(userId).getOpenId();
+  }
+
 
   private boolean sendNotify(Long userId, String bizId, WxSubscribeMessage message) {
     // 获取access_token
-    String accessToken = appTokenService.getAccessToken(channelAppId);
+    String accessToken = appTokenService.getAccessToken(userAppId);
     String res = HttpUtils.sendPost(
         "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken,
         JSON.toJSONString(message));