diff --git a/src/main/java/com/sqx/common/aspect/DebounceAspect.java b/src/main/java/com/sqx/common/aspect/DebounceAspect.java index 289e1c69..992f3471 100644 --- a/src/main/java/com/sqx/common/aspect/DebounceAspect.java +++ b/src/main/java/com/sqx/common/aspect/DebounceAspect.java @@ -32,7 +32,7 @@ public class DebounceAspect { // 用于存储基于方法和入参情况的上次执行时间,结构为:方法签名 -> (入参值 -> 上次执行时间) private static final ConcurrentHashMap> executionTimeMap = new ConcurrentHashMap<>(); - private static final ReentrantLock lock = new ReentrantLock(); + private static final ReentrantLock LOCK = new ReentrantLock(); @Around("logPointCut()") public Object aroundDebounce(ProceedingJoinPoint joinPoint) throws Throwable { @@ -95,7 +95,7 @@ public class DebounceAspect { public void cleanExpiredRecords() { long expirationTime = System.currentTimeMillis() - TimeUnit.SECONDS.toMillis(10); - lock.lock(); + LOCK.lock(); try { for (Entry> outerEntry : executionTimeMap.entrySet()) { String methodSignature = outerEntry.getKey(); @@ -112,7 +112,7 @@ public class DebounceAspect { } } } finally { - lock.unlock(); + LOCK.unlock(); } } } diff --git a/src/main/java/com/sqx/common/utils/SpelUtil.java b/src/main/java/com/sqx/common/utils/SpelUtil.java index f1ccc0e6..f35b1089 100644 --- a/src/main/java/com/sqx/common/utils/SpelUtil.java +++ b/src/main/java/com/sqx/common/utils/SpelUtil.java @@ -10,6 +10,9 @@ import org.springframework.expression.spel.support.StandardEvaluationContext; import java.lang.reflect.Method; +/** + * @author ww + */ public class SpelUtil { /** * 用于SpEL表达式解析. diff --git a/src/main/java/com/sqx/modules/app/entity/InviteAchievement.java b/src/main/java/com/sqx/modules/app/entity/InviteAchievement.java index 59f0ee6c..13592338 100644 --- a/src/main/java/com/sqx/modules/app/entity/InviteAchievement.java +++ b/src/main/java/com/sqx/modules/app/entity/InviteAchievement.java @@ -45,6 +45,11 @@ public class InviteAchievement implements Serializable { * 达标次数 */ private Integer count; + /** + * 已领取奖励次数 + */ + private Integer giveAwardCount; + /** * 是否首次达标 diff --git a/src/main/java/com/sqx/modules/job/task/TempOrdersTask.java b/src/main/java/com/sqx/modules/job/task/TempOrdersTask.java index 5572a683..f80b37b6 100644 --- a/src/main/java/com/sqx/modules/job/task/TempOrdersTask.java +++ b/src/main/java/com/sqx/modules/job/task/TempOrdersTask.java @@ -46,6 +46,9 @@ import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -85,6 +88,9 @@ public class TempOrdersTask { private final SysUserMoneyDetailsService sysUserMoneyDetailsService; private final UserInfoService userInfoService; + private static final ConcurrentHashMap idLocks = new ConcurrentHashMap<>(); + + private Logger logger = LoggerFactory.getLogger(getClass()); public TempOrdersTask(InviteAchievementService inviteAchievementService, CourseService courseService, SysUserMoneyDetailsService sysUserMoneyDetailsService, UserInfoService userInfoService) { @@ -168,6 +174,7 @@ public class TempOrdersTask { UserEntity user = userService.selectUserById(order.getUserId()); UserEntity byUser = userService.queryByInvitationCodeOrUserId(user.getInviterUserId(), user.getInviterCode()); + // UserEntity byUser = userService.queryByInvitationCode(user.getInviterCode()); if (byUser != null) { ApiAccessLimitUtil.runFunAndCheckKey(() -> { @@ -315,7 +322,7 @@ public class TempOrdersTask { moneyDetailsQuery.eq(UserMoneyDetails::getClassify, 6); moneyDetailsQuery.eq(UserMoneyDetails::getUserId, sourceUser.getUserId()); moneyDetailsQuery.eq(UserMoneyDetails::getByUserId, user.getUserId()); - moneyDetailsQuery.ge(UserMoneyDetails::getCreateTime, beginOfDay); + moneyDetailsQuery.eq(UserMoneyDetails::getCreateTime, beginOfDay); int count = userMoneyDetailsService.count(moneyDetailsQuery); if (count > 0) { logger.info("用户: {} 今日已领取奖励", user.getUserId()); @@ -348,68 +355,57 @@ public class TempOrdersTask { * 计算分享达标奖励 */ private void calcInviteStandardAward(UserEntity sourceUser) { - Set byUserIdList = inviteAchievementService.list(new LambdaQueryWrapper().eq(InviteAchievement::getUserId, sourceUser.getUserId()) - .eq(InviteAchievement::getState, 1).select(InviteAchievement::getTargetUserId)).stream().map(InviteAchievement::getTargetUserId).collect(Collectors.toSet()); - int inviteCount; - if (byUserIdList.isEmpty()) { + // 获取该 id 对应的锁,如果不存在则创建一个新的锁 + Lock lock = idLocks.computeIfAbsent(sourceUser.getUserId().toString(), k -> new ReentrantLock()); + + // 尝试获取锁,如果获取失败则表示该 id 正在执行,直接返回 + if (!lock.tryLock()) { + logger.error("分享达标奖励正在执行,跳过: {}", sourceUser.getUserId()); return; } - List list = userInfoService.list(new LambdaQueryWrapper().in(UserInfo::getUserId, byUserIdList).isNotNull(UserInfo::getAccountNo).select(UserInfo::getCertNo)); - logger.info("邀请用户实名信息: {}", list.stream().map(UserInfo::getCertNo).collect(Collectors.toSet())); - UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper().eq(UserInfo::getUserId, sourceUser.getUserId()).select(UserInfo::getCertNo)); - Set collect = userInfoService.list(new LambdaQueryWrapper().in(UserInfo::getUserId, byUserIdList).isNotNull(UserInfo::getAccountNo).select(UserInfo::getCertNo)) - .stream().map(UserInfo::getCertNo).collect(Collectors.toSet()); - // 去除与本人身份信息相同的用户 - if (!collect.isEmpty() && userInfo != null && StrUtil.isNotBlank(userInfo.getCertNo())) { - collect.remove(userInfo.getCertNo()); - } - inviteCount = collect.size(); - logger.info("邀请达标人员: {}", inviteCount); - - // 查询所有已开启的奖励 - List completAwardList = completAwardService.list(new QueryWrapper().eq("status", 1)); - if (completAwardList.isEmpty()) { - logger.info("未开启分享达标奖励"); - return; - } - - // 遍历奖励,寻找最低达标人数 - int minInviteCount = completAwardList.get(0).getInviteCount(); - for (CompletAward completAward : completAwardList) { - if (completAward.getInviteCount() < minInviteCount) { - minInviteCount = completAward.getInviteCount(); + try { + Set byUserIdList = inviteAchievementService.list(new LambdaQueryWrapper().eq(InviteAchievement::getUserId, sourceUser.getUserId()) + .eq(InviteAchievement::getState, 1).select(InviteAchievement::getTargetUserId)).stream().map(InviteAchievement::getTargetUserId).collect(Collectors.toSet()); + if (byUserIdList.isEmpty()) { + return; } - } - - // 如果邀请人数小于最低达标人数,则不发放奖励 - if (inviteCount < minInviteCount) { - logger.info("邀请人数: {} 小于最低达标人数: {}", inviteCount, minInviteCount); - return; - } - - // 查询是否开启分享循环奖励 - int isLoop = Integer.parseInt(commonRepository.findOne(932).getValue()); - - // 遍历奖励,发放奖励 - for (CompletAward completAward : completAwardList) { - QueryWrapper moneyDetailsQuery = new QueryWrapper<>(); - moneyDetailsQuery.eq("classify", 6); - moneyDetailsQuery.eq("user_id", sourceUser.getUserId()); - moneyDetailsQuery.eq("source_id", completAward.getId()); - // 奖励次数 - int awardCount = userMoneyDetailsService.count(moneyDetailsQuery); + UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper().eq(UserInfo::getUserId, sourceUser.getUserId()).select(UserInfo::getCertNo)); + Set collect = userInfoService.list(new LambdaQueryWrapper().in(UserInfo::getUserId, byUserIdList).isNotNull(UserInfo::getAccountNo).select(UserInfo::getCertNo)) + .stream().map(UserInfo::getCertNo).collect(Collectors.toSet()); + // 去除与本人身份信息相同的用户 + if (!collect.isEmpty() && userInfo != null && StrUtil.isNotBlank(userInfo.getCertNo())) { + collect.remove(userInfo.getCertNo()); + } + int inviteCount = collect.size(); + // 查询所有已开启的奖励 + CompletAward completAward = completAwardService.getById(1); + if (completAward == null) { + logger.error("分享达标奖励未配置"); + return; + } + // 如果邀请人数小于最低达标人数,则不发放奖励 + if (inviteCount < completAward.getInviteCount()) { + return; + } + // 查询是否开启分享循环奖励 + int isLoop = Integer.parseInt(commonRepository.findOne(932).getValue()); + InviteAchievement inviteAchievement = inviteAchievementService.getByUserId(sourceUser.getUserId()); + // 发放奖励 + int awardCount = inviteAchievement.getGiveAwardCount(); // 如果未开启循环奖励,并且已经发放过奖励,则跳过 if (isLoop != 1 && awardCount > 0) { - logger.info("奖励已发放: {}, 用户: {}, 奖励类型: {}", completAward.getId(), sourceUser.getUserId(), completAward.getId()); - continue; + return; } - // 计算获取奖励次数 + // 计算获取奖励次数 邀请达标人员 / 邀请人数 int awardNum = inviteCount / completAward.getInviteCount(); if (isLoop != 1) { awardNum = 1; } + if (awardNum - awardCount <= 0) { + return; + } for (int i = 0; i < awardNum - awardCount; i++) { switch (completAward.getType()) { case 1: @@ -430,6 +426,15 @@ public class TempOrdersTask { break; } } + // 更新邀请达标奖励次数 + inviteAchievementService.update(null, new LambdaUpdateWrapper() + .eq(InviteAchievement::getId, inviteAchievement.getId()) + .set(InviteAchievement::getGiveAwardCount, inviteAchievement.getGiveAwardCount() + (awardNum - awardCount))); + } catch (Exception e) { + logger.error("分享达标额外奖励发放失败,用户: {}", sourceUser.getUserId(), e); + } finally { + lock.unlock(); + idLocks.remove(sourceUser.getUserId().toString()); } } }