火箭领取接口完善

This commit is contained in:
tianfeng 2025-11-12 23:41:03 +08:00
parent 3bdfc23433
commit 5e0948c86b
7 changed files with 96 additions and 39 deletions

View File

@ -53,6 +53,7 @@ public class RocketRewardClaimCmdExe {
private final WalletGoldClient walletGoldClient; private final WalletGoldClient walletGoldClient;
private final PropsBackpackClient propsBackpackClient; private final PropsBackpackClient propsBackpackClient;
private final BadgeBackpackClient badgeBackpackClient; private final BadgeBackpackClient badgeBackpackClient;
private final RocketHistoryGateway rocketHistoryGateway;
private final Random random = new Random(); private final Random random = new Random();
@ -63,7 +64,7 @@ public class RocketRewardClaimCmdExe {
Long userId = cmd.getReqUserId(); Long userId = cmd.getReqUserId();
String lockKey = RocketKeys.LOCK.getKey(cmd.getRoomId(), "claim", userId); String lockKey = RocketKeys.LOCK.getKey(cmd.getRoomId(), "claim", userId);
return distributedLockUtil.executeWithLock(lockKey, 5L, () -> doClaim(cmd), "奖励领取操作过于频繁,请稍后重试"); return distributedLockUtil.executeWithLock(lockKey, 5L, () -> doClaim(cmd), "Reward collection operations are too frequent. Please try again later");
} }
/** /**
@ -73,59 +74,52 @@ public class RocketRewardClaimCmdExe {
Long userId = cmd.getReqUserId(); Long userId = cmd.getReqUserId();
Long roomId = cmd.getRoomId(); Long roomId = cmd.getRoomId();
String today = LocalDate.now().toString(); String today = LocalDate.now().toString();
// 1. 查询火箭状态 // 1. 查询今天最新的火箭发射记录
RocketStatus rocketStatus = rocketStatusGateway.findByRoomIdAndDate(roomId, today); RocketHistory latestHistory = rocketHistoryGateway.findLatestByRoomIdAndDate(roomId, today);
if (rocketStatus == null) { if (latestHistory == null) {
throw new RuntimeException("火箭状态不存在"); throw new RuntimeException("There are no rockets launched today, and there are no rewards to receive");
} }
Integer rocketLevel = rocketStatus.getLevel().getLevel(); Integer rocketLevel = latestHistory.getLevel();
// 2. 校验是否已发射 // 2. 检查是否已领取每天每个房间每个等级只能领一次
if (rocketStatus.getStatus() != RocketStatusEnum.LAUNCHED) { boolean hasClaimed = rocketRewardLogGateway.existsByRocketAndUser(latestHistory.getId(), userId);
throw new RuntimeException("火箭尚未发射,无法领取奖励");
}
// 3. 检查是否已领取每天每个房间每个等级只能领一次
boolean hasClaimed = rocketRewardLogGateway.existsByRoomAndUserAndDateAndLevel(roomId, userId, today, rocketLevel);
if (hasClaimed) { if (hasClaimed) {
throw new RuntimeException("今日该等级火箭已领取,请等待下一级或明天再来"); throw new RuntimeException("This class of rocket has been collected today. Please wait for the next stage or come back tomorrow.");
} }
// 4. 查询火箭配置 // 3. 查询火箭配置
RocketConfig config = rocketConfigGateway.findByLevel(rocketLevel); RocketConfig config = rocketConfigGateway.findByLevel(rocketLevel);
if (config == null) { if (config == null) {
throw new RuntimeException("火箭配置不存在"); throw new RuntimeException("火箭配置不存在");
} }
// 5. 检查奖励数量是否已达上限 // 4. MongoDB原子递增检查
Integer rewardQuantity = config.getRewardQuantity() != null ? config.getRewardQuantity() : 20; int rewardQuantity = config.getRewardQuantity() != null ? config.getRewardQuantity() : 20;
if (rocketStatus.getClaimCount() >= rewardQuantity) { boolean success = rocketHistoryGateway.tryIncrementClaimCount(latestHistory.getId(), rewardQuantity);
throw new RuntimeException("奖励已被领完,请下次早点来"); if (!success) {
throw new RuntimeException("The rewards have been collected, please come earlier next time");
} }
// 6. 解析奖励配置 // 5. 解析奖励配置
List<PropsActivityRewardConfigInfoDTO> rewardList = parseRewardConfig(config.getRewardConfig().toJSONString()); List<PropsActivityRewardConfigInfoDTO> rewardList = parseRewardConfig(config.getRewardConfig().toJSONString());
if (rewardList == null || rewardList.isEmpty()) { if (rewardList == null || rewardList.isEmpty()) {
throw new RuntimeException("奖励配置为空"); throw new RuntimeException("奖励配置为空");
} }
// 7. 随机选择一个奖励 // 6. 随机选择一个奖励
PropsActivityRewardConfigInfoDTO selectedReward = rewardList.get(random.nextInt(rewardList.size())); PropsActivityRewardConfigInfoDTO selectedReward = rewardList.get(random.nextInt(rewardList.size()));
// 8. 发放奖励 // 7. 发放奖励
String walletBizNo = RocketRewardLog.buildBizNo(roomId.toString(), userId); String walletBizNo = RocketRewardLog.buildBizNo(roomId.toString(), userId);
grantReward(userId, selectedReward, walletBizNo); grantReward(userId, selectedReward, walletBizNo);
// 9. 保存领取记录 // 8. 保存领取记录
saveRewardLog(roomId, userId, today, rocketLevel, selectedReward, walletBizNo); saveRewardLog(roomId, userId, latestHistory, selectedReward, walletBizNo);
// 10. 更新领取人数
rocketStatus.incrementClaimCount();
rocketStatusGateway.save(rocketStatus);
// 11. 推送领取成功消息 // 9. 推送领取成功消息
try { try {
String userName = "用户" + userId; String userName = "用户" + userId;
Long rewardAmount = getRewardAmount(selectedReward); Long rewardAmount = getRewardAmount(selectedReward);
@ -134,7 +128,7 @@ public class RocketRewardClaimCmdExe {
log.error("推送奖励领取消息失败: roomId={}, userId={}", roomId, userId, e); log.error("推送奖励领取消息失败: roomId={}, userId={}", roomId, userId, e);
} }
// 12. 构建返回结果 // 10. 构建返回结果
RocketRewardCO rewardCO = new RocketRewardCO(); RocketRewardCO rewardCO = new RocketRewardCO();
rewardCO.setRewardType(selectedReward.getType()); rewardCO.setRewardType(selectedReward.getType());
rewardCO.setRewardItemId(selectedReward.getId()); rewardCO.setRewardItemId(selectedReward.getId());
@ -218,7 +212,6 @@ public class RocketRewardClaimCmdExe {
.build() .build()
); );
log.info("金币发放成功: userId={}, amount={}", userId, goldAmount);
} catch (Exception e) { } catch (Exception e) {
log.error("金币发放失败: userId={}, amount={}", userId, goldAmount, e); log.error("金币发放失败: userId={}, amount={}", userId, goldAmount, e);
throw new RuntimeException("金币发放失败"); throw new RuntimeException("金币发放失败");
@ -243,8 +236,8 @@ public class RocketRewardClaimCmdExe {
.setOpUser(userId); .setOpUser(userId);
propsBackpackClient.giveProps(cmd); propsBackpackClient.giveProps(cmd);
log.info("道具发放成功(TODO): userId={}, propId={}, quantity={}, type={}", // 发送通知
userId, propId, quantity, detailType); propsBackpackClient.givePropsNotify(userId, detailType, quantity, propId);
} catch (Exception e) { } catch (Exception e) {
log.error("道具发放失败: userId={}, propId={}", userId, propId, e); log.error("道具发放失败: userId={}, propId={}", userId, propId, e);
throw new RuntimeException("道具发放失败"); throw new RuntimeException("道具发放失败");
@ -270,7 +263,8 @@ public class RocketRewardClaimCmdExe {
.setBadgeType(SysBadgeConfigTypeEnum.ACTIVITY) .setBadgeType(SysBadgeConfigTypeEnum.ACTIVITY)
); );
log.info("徽章发放成功(TODO): userId={}, badgeId={}", userId, badgeId); // 发送通知
propsBackpackClient.givePropsNotify(userId, SysBadgeConfigTypeEnum.ACTIVITY.name(), quantity, badgeId);
} catch (Exception e) { } catch (Exception e) {
log.error("徽章发放失败: userId={}, badgeId={}", userId, badgeId, e); log.error("徽章发放失败: userId={}, badgeId={}", userId, badgeId, e);
throw new RuntimeException("徽章发放失败"); throw new RuntimeException("徽章发放失败");
@ -280,12 +274,13 @@ public class RocketRewardClaimCmdExe {
/** /**
* 保存领取记录 * 保存领取记录
*/ */
private void saveRewardLog(Long roomId, Long userId, String date, Integer level, private void saveRewardLog(Long roomId, Long userId, RocketHistory rocketHistory,
PropsActivityRewardConfigInfoDTO reward, String walletBizNo) { PropsActivityRewardConfigInfoDTO reward, String walletBizNo) {
RocketRewardLog log = new RocketRewardLog(); RocketRewardLog log = new RocketRewardLog();
log.setRocketHistoryId(rocketHistory.getId());
log.setRoomId(roomId); log.setRoomId(roomId);
log.setUserId(userId); log.setUserId(userId);
log.setRocketLevel(level); log.setRocketLevel(rocketHistory.getLevel());
log.setIsContributor(0); log.setIsContributor(0);
log.setContributionEnergy(0L); log.setContributionEnergy(0L);
log.setContributionRate(null); log.setContributionRate(null);

View File

@ -18,6 +18,22 @@ public interface RocketHistoryGateway {
*/ */
String save(RocketHistory history); String save(RocketHistory history);
/**
* 查询今天最新的火箭发射记录按发射时间倒序
*/
RocketHistory findLatestByRoomIdAndDate(Long roomId, String date);
/**
* 尝试原子递增领取人数带上限检查
* @return 是否成功递增
*/
boolean tryIncrementClaimCount(String historyId, int maxCount);
/**
* 增加领取人数
*/
void incrementClaimCount(String historyId);
/** /**
* 根据ID查询 * 根据ID查询
*/ */

View File

@ -26,6 +26,10 @@ public class RocketHistory {
private Integer totalContributors; private Integer totalContributors;
private RewardPool rewardPool; private RewardPool rewardPool;
private ClaimStats claimStats; private ClaimStats claimStats;
/**
* 已领取人数
*/
private Integer claimedCount;
private LocalDateTime launchTime; private LocalDateTime launchTime;
private LocalDateTime claimStartTime; private LocalDateTime claimStartTime;
private LocalDateTime claimEndTime; private LocalDateTime claimEndTime;

View File

@ -54,7 +54,7 @@ public class RocketConfigConvertor {
} else { } else {
config.setNormalRewardConfig(new JSONArray()); config.setNormalRewardConfig(new JSONArray());
} }
config.setRewardQuantity(entity.getRewardQuantity());
config.setStatus(entity.getStatus()); config.setStatus(entity.getStatus());
// config.setCreatedAt(entity.getCreatedAt()); // config.setCreatedAt(entity.getCreatedAt());
// config.setUpdatedAt(entity.getUpdatedAt()); // config.setUpdatedAt(entity.getUpdatedAt());
@ -91,7 +91,8 @@ public class RocketConfigConvertor {
} else { } else {
entity.setNormalRewardConfig(null); entity.setNormalRewardConfig(null);
} }
entity.setRewardQuantity(config.getRewardQuantity());
entity.setStatus(config.getStatus()); entity.setStatus(config.getStatus());
// createdAt updatedAt 由数据库自动管理 // createdAt updatedAt 由数据库自动管理

View File

@ -2,6 +2,7 @@ package com.red.circle.other.infra.database.mongo.repository;
import com.red.circle.other.infra.database.mongo.document.RocketHistoryDocument; import com.red.circle.other.infra.database.mongo.document.RocketHistoryDocument;
import org.springframework.data.mongodb.repository.MongoRepository; import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -21,6 +22,11 @@ public interface RocketHistoryRepository extends MongoRepository<RocketHistoryDo
*/ */
List<RocketHistoryDocument> findByRoomIdOrderByLaunchTimeDesc(Long roomId); List<RocketHistoryDocument> findByRoomIdOrderByLaunchTimeDesc(Long roomId);
/**
* 查询今天最新的火箭发射记录按发射时间倒序
*/
RocketHistoryDocument findFirstByRoomIdAndDateOrderByLaunchTimeDesc(Long roomId, String date);
/** /**
* 根据房间ID和日期查询 * 根据房间ID和日期查询
*/ */

View File

@ -1,5 +1,6 @@
package com.red.circle.other.infra.gateway; package com.red.circle.other.infra.gateway;
import com.mongodb.client.result.UpdateResult;
import com.red.circle.other.domain.gateway.RocketHistoryGateway; import com.red.circle.other.domain.gateway.RocketHistoryGateway;
import com.red.circle.other.domain.rocket.RocketHistory; import com.red.circle.other.domain.rocket.RocketHistory;
import com.red.circle.other.infra.convertor.RocketHistoryConvertor; import com.red.circle.other.infra.convertor.RocketHistoryConvertor;
@ -41,6 +42,40 @@ public class RocketHistoryGatewayImpl implements RocketHistoryGateway {
return saved.getId(); return saved.getId();
} }
@Override
public RocketHistory findLatestByRoomIdAndDate(Long roomId, String date) {
RocketHistoryDocument document = rocketHistoryRepository.findFirstByRoomIdAndDateOrderByLaunchTimeDesc(roomId, date);
if (document == null) {
return null;
}
return rocketHistoryConvertor.toDomain(document);
}
@Override
public boolean tryIncrementClaimCount(String historyId, int maxCount) {
Query query = new Query();
query.addCriteria(Criteria.where("_id").is(historyId));
query.addCriteria(Criteria.where("claimedCount").lt(maxCount)); // 小于上限才更新
Update update = new Update();
update.inc("claimedCount", 1);
update.set("updatedAt", LocalDateTime.now());
UpdateResult result = mongoTemplate.updateFirst(query, update, RocketHistoryDocument.class);
return result.getModifiedCount() > 0; // 更新成功返回true
}
@Override
public void incrementClaimCount(String historyId) {
Query query = new Query(Criteria.where("_id").is(historyId));
Update update = new Update();
update.inc("claimedCount", 1);
update.set("updatedAt", LocalDateTime.now());
mongoTemplate.updateFirst(query, update, RocketHistoryDocument.class);
}
@Override @Override
public RocketHistory findById(String id) { public RocketHistory findById(String id) {
return rocketHistoryRepository.findById(id) return rocketHistoryRepository.findById(id)

View File

@ -15,7 +15,7 @@
</resultMap> </resultMap>
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, level, max_energy, reward_config, contributor_reward_rate, id, level, max_energy, reward_config,reward_quantity, contributor_reward_rate,
normal_reward_config, status, created_at, updated_at normal_reward_config, status, created_at, updated_at
</sql> </sql>