Commit 8d3d0413 authored by zhaobiyan's avatar zhaobiyan

积分操作新增唯一键幂等处理

parent c259ec47
......@@ -41,4 +41,6 @@ public class MemberUserScoreBatchOperateReqDTO {
* 扩展参数
*/
private Map<String, Object> extParam;
private String uniqueId;
}
......@@ -12,6 +12,10 @@ import java.util.Map;
@Builder
@ToString
public class MemberUserScoreOperateReqDTO {
/**
* 唯一键 增加积分时必须,做幂等判断使用
*/
private String uniqueId;
/**
* 会员id
*/
......
......@@ -48,4 +48,7 @@ public interface ErrorCodeConstants {
ErrorCode REVERSE_SOURCE_NO_RELEATION_ID = new ErrorCode(1004008004, "reverse.source.no.releation.id");
ErrorCode LEVEL_BOUND_RANGE_ERROR = new ErrorCode(1004008005, "level.bound.range.error");
ErrorCode LEVEL_BOUND_RANGE_CONFLICT = new ErrorCode(1004008006, "level.bound.range.conflict");
ErrorCode SOURCE_TYPE_IS_NULL = new ErrorCode(1004008007, "source.type.is.null");
ErrorCode SCORE_OPERATE_MUST_HAVE_UNIQUE_ID = new ErrorCode(1004008008, "score.operate.must.have.unique.id");
ErrorCode SCORE_OPERATE_IDEMPOTENT_ERROR = new ErrorCode(1004008008, "score.operate.idempotent.error");
}
......@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.member.api.score.dto.*;
import cn.iocoder.yudao.module.member.dal.dataobject.score.MemberUserScoreDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetail.MemberUserScoreDetailDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreDetailReleation.MemberUserScoreDetailReleationDO;
import cn.iocoder.yudao.module.member.dal.dataobject.scoreLog.MemberUserScoreLogDO;
import cn.iocoder.yudao.module.member.dto.ScoreDetailChangeDto;
import cn.iocoder.yudao.module.member.enums.MemberScoreDetailReleationStatueEnum;
import cn.iocoder.yudao.module.member.enums.ScoreOperateTypeEnum;
......@@ -64,6 +65,16 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
if (req.getScoreCount() <= 0) {
throw exception(SCORE_COUNT_ERROR);
}
if (req.getSourceType() == null) {
throw exception(SOURCE_TYPE_IS_NULL);
}
if (StringUtils.isBlank(req.getUniqueId())) {
throw exception(SCORE_OPERATE_MUST_HAVE_UNIQUE_ID);
}
MemberUserScoreLogDO memberUserScoreLogDO = logService.getByUniqueId(req.getUniqueId());
if (memberUserScoreLogDO != null) {
throw exception(SCORE_OPERATE_IDEMPOTENT_ERROR);
}
String lockKey = "member:operate:score:" + req.getMemberId();
RLock lock = redissonClient.getLock(lockKey);
try {
......@@ -127,6 +138,7 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
.operateType(req.getOperateType())
.sourceType(req.getSourceType())
.extParam(req.getExtParam())
.uniqueId(req.getUniqueId() + "_" + memberId)
.build()))
.collect(Collectors.toList());
}
......@@ -187,6 +199,7 @@ public class MemberUserScoreApiImpl implements MemberUserScoreApi{
req.getOperateType().getValue() : req.getSourceType().getOperateType().getValue())
.sourceType(req.getSourceType().getValue())
.extParam(req.getExtParam())
.uniqueId(req.getUniqueId())
.build());
}
}
......@@ -64,6 +64,7 @@ public class MemberUserScoreExpireTask implements JobHandler {
.memberId(memberUserScoreDetailDO.getMemberId())
.scoreCount(memberUserScoreDetailDO.getRemainCount())
.sourceType(ScoreSourceTypeEnum.SYSTEM_EXPIRED)
.uniqueId(ScoreSourceTypeEnum.SYSTEM_EXPIRED +"_"+ memberUserScoreDetailDO.getId() + "_" + System.currentTimeMillis())
.extParam(extParam)
.build());
} catch (Exception e) {
......
......@@ -60,6 +60,7 @@ public class MemberUserScoreController {
.operateType(ScoreOperateTypeEnum.parseByValue(query.getOperateType()))
.sourceType(ScoreSourceTypeEnum.MANUAL_OPERATE)
.extParam(extParam)
.uniqueId(ScoreSourceTypeEnum.MANUAL_OPERATE + "_" + System.currentTimeMillis())
.build());
return success(null);
}
......
......@@ -32,4 +32,6 @@ public class MemberUserScoreLogDO extends BaseDO {
private Long ruleId;
private String extParam = "{}";
private String uniqueId;
}
......@@ -55,6 +55,7 @@ public class MemberUserScoreDetailExpireListener {
.memberId(detail.getMemberId())
.scoreCount(detail.getRemainCount())
.sourceType(ScoreSourceTypeEnum.SYSTEM_EXPIRED)
.uniqueId(ScoreSourceTypeEnum.SYSTEM_EXPIRED +"_"+ detail.getId() + "_" + System.currentTimeMillis())
.extParam(extParam)
.build());
} catch (Exception e) {
......
......@@ -17,4 +17,6 @@ public interface MemberUserScoreLogService extends IService<MemberUserScoreLogDO
PageResult<MemberUserScoreLogBackVO> getPage(MemberUserScoreLogQueryVO query);
Long createScoreLog(MemberUserScoreLogCreateReq createReq);
MemberUserScoreLogDO getByUniqueId(String uniqueId);
}
......@@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogBa
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogCreateReq;
import cn.iocoder.yudao.module.member.vo.memberUserScoreLog.MemberUserScoreLogQueryVO;
import cn.iocoder.yudao.module.system.service.dict.DictTypeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
......@@ -59,10 +61,18 @@ public class MemberUserScoreLogServiceImpl extends AbstractService<MemberUserSco
userScoreLogDO.setOperateType(createReq.getOperateType());
userScoreLogDO.setSourceType(createReq.getSourceType());
userScoreLogDO.setRuleId(createReq.getRuleId());
userScoreLogDO.setUniqueId(createReq.getUniqueId());
if (createReq.getExtParam() != null) {
userScoreLogDO.setExtParam(JSONUtil.toJsonStr(createReq.getExtParam()));
}
this.saveOrUpdate(userScoreLogDO);
return userScoreLogDO.getId();
}
@Override
public MemberUserScoreLogDO getByUniqueId(String uniqueId) {
LambdaQueryWrapper<MemberUserScoreLogDO> wrapper = Wrappers.lambdaQuery();
wrapper.eq(MemberUserScoreLogDO::getUniqueId, uniqueId);
return this.selectOne(wrapper);
}
}
......@@ -17,4 +17,5 @@ public class MemberUserScoreLogCreateReq {
private Integer sourceType;
private Long ruleId;
private Map<String, Object> extParam;
private String uniqueId;
}
......@@ -112,6 +112,7 @@ public class RedeemRewardApiImpl implements RedeemRewardApi {
.sourceType(ScoreSourceTypeEnum.EXCHANGE_REWARD)
.scoreCount(redeemRewardReqVO.getRewardCount() * rewardDO.getPointsRequire())
.releationId(String.valueOf(redeemId))
.uniqueId(ScoreSourceTypeEnum.EXCHANGE_REWARD + "_" + redeemId)
.extParam(extParam)
.build());
}
......
......@@ -274,6 +274,7 @@ public class RewardRedeemServiceImpl extends AbstractService<RewardRedeemMapper,
.scoreCount(rewardRedeemDO.getScoreCount())
.extParam(extParam)
.releationId(String.valueOf(req.getId()))
.uniqueId(ScoreSourceTypeEnum.EXCHANGE_REWARD_CANCEL + "_" + req.getId())
.build());
return true;
}
......
......@@ -1023,4 +1023,5 @@ currency.not.exist = currency not exist
date.format.error = date format error, for example : 2024-01-01 12:11:11
redeem.cancel.status.error = record status must be redeeming
level.bound.range.error = upper count must greater than lower count
level.bound.range.conflict = score range exist conflict
\ No newline at end of file
level.bound.range.conflict = score range exist conflict
score.operate.idempotent.error = idempotent key conflict
\ No newline at end of file
......@@ -1027,4 +1027,5 @@ currency.not.exist = \u5E01\u79CD\u4E0D\u5B58\u5728
date.format.error = \u65E5\u671F\u683C\u5F0F\u4E0D\u6B63\u786E, \u6B63\u786E\u683C\u5F0F\u53C2\u8003: 2024-01-01 12:11:11
redeem.cancel.status.error = \u5151\u6362\u4E2D\u72B6\u6001\u7684\u8BB0\u5F55\u624D\u80FD\u64A4\u9500
level.bound.range.error = \u4E0A\u754C\u6570\u503C\u5FC5\u987B\u5927\u4E8E\u4E0B\u754C\u6570\u503C
level.bound.range.conflict = \u79EF\u5206\u8303\u56F4\u5B58\u5728\u51B2\u7A81
\ No newline at end of file
level.bound.range.conflict = \u79EF\u5206\u8303\u56F4\u5B58\u5728\u51B2\u7A81
score.operate.idempotent.error = \u5E42\u7B49key\u51B2\u7A81
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment