记得上下班打卡 | git大法好,push需谨慎

Commit 7ca36097 authored by wangyifan's avatar wangyifan

草莓护照-添加缓存

parent d1c3fb46
......@@ -22,6 +22,10 @@ public class AdamRedisConst {
public static final String INFO_ADDRESSES = PREFIX.concat("info:addresses:");
public static final String INFO_CAOMEI_BADGE_PUBLISHED = PREFIX.concat("info:caomei:badge:published");
public static final String INFO_CAOMEI_BADGE_USER = PREFIX.concat("info:caomei:badge:user:");
/**
* 身份证号已支付演出ID列表(短缓存,缓解 kylin_order_ticket_entities 无身份证索引时的热点查询压力)
*/
public static final String INFO_CAOMEI_PAID_PERFORMANCE_IDS_BY_IDCARD = PREFIX.concat("info:caomei:paid_performance_ids:idcard:");
/**
* {adam:info:biz:{uid},List<com.liquidnet.service.adam.dto.vo.AdamUserBizAcctVo>}
*/
......
......@@ -697,6 +697,38 @@ public class AdamRdmService {
return badges;
}
/**
* 用户认领徽章时追加一条(与收货地址 addAddressesVoByUid 相同:写回整列表到 Redis)
*/
public boolean addUserCaomeiBadgeDtoByUid(String uid,
List<AdamCaomeiPassportUserBadgeDto> vos,
AdamCaomeiPassportUserBadgeDto dto) {
if (vos == null) {
vos = new ArrayList<>();
}
vos.add(dto);
return setUserCaomeiBadgesByUid(uid, vos);
}
/**
* 根据身份证获取已支付演出ID列表(60秒短缓存,缓解无索引热点查询)
*/
public List<String> getPaidPerformanceIdsByIdCard(String idCard) {
if (StringUtils.isEmpty(idCard)) {
return Collections.emptyList();
}
String rk = AdamRedisConst.INFO_CAOMEI_PAID_PERFORMANCE_IDS_BY_IDCARD.concat(idCard);
List<String> performanceIds = (List<String>) redisUtil.get(rk);
if (CollectionUtils.isEmpty(performanceIds)) {
performanceIds = adamCaomeiBadgeMapper.selectPaidPerformanceIdsByIdCard(idCard);
if (performanceIds == null) {
performanceIds = Collections.emptyList();
}
redisUtil.set(rk, performanceIds, 60);
}
return performanceIds;
}
/**
* 删除用户徽章redis
* @param uid
......
......@@ -2,6 +2,7 @@ package com.liquidnet.service.adam.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.liquidnet.commons.lang.util.IDGenerator;
import com.liquidnet.service.adam.dto.AdamCaomeiPassportUserBadgeDto;
import com.liquidnet.service.adam.dto.param.AdamCaomeiBadgeApplyParam;
import com.liquidnet.service.adam.dto.AdamCaomeiBadgeApplyRecordUserDto;
import com.liquidnet.service.adam.dto.vo.AdamCaomeiBadgeApplyRecordUserVo;
......@@ -14,14 +15,18 @@ import com.liquidnet.service.adam.mapper.AdamCaomeiBadgeMapper;
import com.liquidnet.service.adam.mapper.AdamCaomeiPassportMapper;
import com.liquidnet.service.adam.service.AdamRdmService;
import com.liquidnet.service.adam.service.IAdamCaomeiBadgeUserService;
import com.liquidnet.service.adam.util.QueueUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.base.SqlMapping;
import com.liquidnet.service.base.constant.MQConst;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
......@@ -39,6 +44,8 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
private AdamCaomeiBadgeApplyRecordMapper badgeApplyRecordMapper;
@Autowired
private AdamRdmService adamRdmService;
@Autowired
private QueueUtils queueUtils;
@Override
@Transactional(rollbackFor = Exception.class)
......@@ -58,7 +65,17 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
return ResponseDto.failure(ErrorMapping.get("10607"));
}
// 2. 检查用户是否已经领取过该徽章
// 2. 与收货地址 add 一致:先取 Redis(或回源)用户徽章列表,再判重;DB 再兜一层防缓存未命中或其它写入路径
List<AdamCaomeiPassportUserBadgeDto> badgeVos = adamRdmService.getUserCaomeiBadgesByUid(uid);
if (badgeVos == null) {
badgeVos = new ArrayList<>();
} else {
badgeVos = new ArrayList<>(badgeVos);
}
if (badgeVos.stream().anyMatch(b -> badgeId.equals(b.getBadgeId()))) {
log.info("[claimBadge] 用户已领取过该徽章(Redis列表), uid: {}, badgeId: {}", uid, badgeId);
return ResponseDto.failure(ErrorMapping.get("10608"));
}
int count = adamCaomeiBadgeMapper.checkUserBadgeExists(uid, badgeId);
if (count > 0) {
log.info("[claimBadge] 用户已领取过该徽章, uid: {}, badgeId: {}", uid, badgeId);
......@@ -67,9 +84,7 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
int type = badge.getType() == null ? 0 : badge.getType();
// 3. 根据徽章类型执行不同的认领逻辑
if (type == 1) {
// 护照纪念徽章:需要绑定了护照才能领取
AdamCaomeiPassport bound = adamCaomeiPassportMapper.selectOne(
Wrappers.lambdaQuery(AdamCaomeiPassport.class)
.eq(AdamCaomeiPassport::getUserId, uid)
......@@ -80,15 +95,13 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
log.error("[claimBadge] 认领护照纪念徽章需先绑定护照, uid: {}, badgeId: {}", uid, badgeId);
return ResponseDto.failure(ErrorMapping.get("10609"));
}
// 发放徽章 (source: 1-绑定护照自动发放/护照徽章认领)
adamCaomeiBadgeMapper.insertUserBadge(uid, badgeId, 1);
adamRdmService.delUserCaomeiBadgesByUid(uid);
// 发放徽章 (source: 1-绑定护照自动发放/护照徽章认领):先写 Redis,再 MQ 落库
grantUserBadgeRedisThenMq(uid, badge, 1, badgeVos);
log.info("[claimBadge] 护照纪念徽章认领成功, uid: {}, badgeId: {}", uid, badgeId);
return ResponseDto.success(badgeId);
} else if (type == 2) {
// 演出纪念徽章:需要实名认证 +(购票记录 或 补签审核已通过)
AdamRealInfoVo real = adamRdmService.getRealInfoVoByUidPlain(uid);
if (real == null || real.getState() == null || real.getState() != 1 || StringUtils.isBlank(real.getIdCard())) {
log.error("[claimBadge] 认领演出徽章需先实名, uid: {}, badgeId: {}", uid, badgeId);
......@@ -96,8 +109,7 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
}
String idCard = real.getIdCard();
List<String> paidPerformanceIds = adamCaomeiBadgeMapper.selectPaidPerformanceIdsByIdCard(idCard);
// 有支付记录
List<String> paidPerformanceIds = adamRdmService.getPaidPerformanceIdsByIdCard(idCard);
boolean hasPaidRecord = paidPerformanceIds != null && paidPerformanceIds.contains(badge.getPerformanceId());
Integer passedApplyCount = badgeApplyRecordMapper.selectCount(
Wrappers.lambdaQuery(AdamCaomeiBadgeApplyRecord.class)
......@@ -112,26 +124,13 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
return ResponseDto.failure(ErrorMapping.get("10611"));
}
// 自动发放该演出所有关联徽章
// List<AdamCaomeiBadge> performanceBadges = adamCaomeiBadgeMapper.selectList(
// Wrappers.lambdaQuery(AdamCaomeiBadge.class)
// .eq(AdamCaomeiBadge::getPerformanceId, badge.getPerformanceId())
// .eq(AdamCaomeiBadge::getDisplayStatus, 1)
// .eq(AdamCaomeiBadge::getType, 2)
// );
// for (AdamCaomeiBadge perfBadge : performanceBadges) {
// 发放徽章:2-购票自动发放/演出徽章认领,3-补签审核通过后认领
int source = hasPaidRecord ? 2 : 3;
adamCaomeiBadgeMapper.insertUserBadge(uid, badgeId, source);
adamRdmService.delUserCaomeiBadgesByUid(uid);
// }
grantUserBadgeRedisThenMq(uid, badge, source, badgeVos);
log.info("[claimBadge] 演出纪念徽章认领成功, uid: {}, badgeId: {}, 发放数量: {}", uid, badgeId, 1);
return ResponseDto.success(badgeId);
} else if (type == 3) {
// 特殊徽章不可自助领取
log.error("[claimBadge] 特殊徽章不可自助领取, uid: {}, badgeId: {}", uid, badgeId);
return ResponseDto.failure(ErrorMapping.get("10612"));
}
......@@ -140,6 +139,31 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
return ResponseDto.failure(ErrorMapping.get("10613"));
}
/**
* Redis 追加用户徽章展示 DTO,再发 MQ 异步执行 sqlmap 中的 INSERT。
*/
private void grantUserBadgeRedisThenMq(String uid, AdamCaomeiBadge badge, int source,
List<AdamCaomeiPassportUserBadgeDto> badgeVos) {
Date now = new Date();
AdamCaomeiPassportUserBadgeDto dto = new AdamCaomeiPassportUserBadgeDto();
dto.setBadgeId(badge.getBadgeId());
dto.setBadgeName(StringUtils.defaultString(badge.getName()));
dto.setIcon(StringUtils.defaultString(badge.getIcon()));
dto.setShareText(StringUtils.defaultString(badge.getShareText()));
dto.setType(badge.getType());
dto.setClaimedAt(now);
dto.setSource(source);
adamRdmService.addUserCaomeiBadgeDtoByUid(uid, badgeVos, dto);
long t = System.currentTimeMillis();
queueUtils.sendMsgByRedis(
MQConst.AdamQueue.SQL_UCENTER.getKey(),
SqlMapping.get("adam_caomei_user_badge.add", uid, badge.getBadgeId(), source)
);
log.debug("[claimBadge] MQ耗时:{}ms, uid: {}, badgeId: {}", System.currentTimeMillis() - t, uid, badge.getBadgeId());
}
@Override
public ResponseDto<List<AdamCaomeiBadgeApplyRecordUserVo>> getApplyRecords(String uid) {
if (StringUtils.isBlank(uid)) {
......@@ -164,7 +188,6 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
}
@Override
@Transactional(rollbackFor = Exception.class)
public ResponseDto<String> applyBadge(AdamCaomeiBadgeApplyParam param, String uid) {
if (StringUtils.isBlank(uid)) {
return ResponseDto.failure(ErrorMapping.get("10001"));
......@@ -202,21 +225,19 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
return ResponseDto.failure("您已有待审核的补签申请,请勿重复提交");
}
Date now = new Date();
AdamCaomeiBadgeApplyRecord record = new AdamCaomeiBadgeApplyRecord();
record.setApplyRecordId(IDGenerator.nextSnowId());
record.setUserId(uid);
record.setBadgeId(badgeId);
record.setPerformanceId(StringUtils.defaultString(badge.getPerformanceId()));
record.setProofImageUrl(proofImageUrl);
record.setAuditStatus(0);
record.setRejectReason("");
record.setCreatedAt(now);
record.setUpdatedAt(now);
int inserted = badgeApplyRecordMapper.insert(record);
if (inserted <= 0) {
return ResponseDto.failure();
}
return ResponseDto.success(record.getApplyRecordId());
final String applyRecordId = IDGenerator.nextSnowId();
long t = System.currentTimeMillis();
queueUtils.sendMsgByRedis(
MQConst.AdamQueue.SQL_UCENTER.getKey(),
SqlMapping.get("adam_caomei_badge_apply_record.add",
applyRecordId,
uid,
badgeId,
badge.getPerformanceId(),
proofImageUrl)
);
log.info("[claimBadge] MQ耗时:{}ms, uid: {}, badgeId: {}", System.currentTimeMillis() - t, uid, badge.getBadgeId());
return ResponseDto.success(applyRecordId);
}
}
......@@ -153,7 +153,7 @@ public class AdamCaomeiPassportUserServiceImpl implements IAdamCaomeiPassportUse
// 5. TODO 优化点
final List<String> paidPerformanceIds = StringUtils.isNotBlank(idCard)
? adamCaomeiBadgeMapper.selectPaidPerformanceIdsByIdCard(idCard)
? adamRdmService.getPaidPerformanceIdsByIdCard(idCard)
: new ArrayList<>();
log.info("[getPassportHome] 用户已支付的演出订单数量, uid: {}, 数量: {}", uid, paidPerformanceIds.size());
......
......@@ -80,10 +80,13 @@ adam_user_mobile_locate.update_province=UPDATE adam_user_mobile_locate SET provi
adam_user_mobile_locate.close=UPDATE adam_user_mobile_locate SET `state`=2, updated_at=? WHERE uid=? AND `state`=1
# ----------------------------------------------------
# 草莓护照-用户徽章获得记录 (adam_caomei_user_badge)
# 用户端 claimBadge:与 AdamCaomeiBadgeUserServiceImpl 中「先写 Redis 用户徽章列表、再 MQ 异步落库」配套;参数顺序 user_id, badge_id, source;created_at 由库端 now() 写入
adam_caomei_user_badge.add=INSERT INTO adam_caomei_user_badge (user_id, badge_id, source, created_at) VALUES (?,?,?,now())
# ----------------------------------------------------
# 草莓护照-徽章补签申请 (adam_caomei_badge_apply_record)
# 用户端 applyBadge:与「先写 Redis 补签列表、再 MQ 异步落库」配套;参数顺序 apply_record_id, user_id, badge_id, performance_id, proof_image_url;audit_status=0、reject_reason 空串、时间由 now() 写入
adam_caomei_badge_apply_record.add=INSERT INTO adam_caomei_badge_apply_record (apply_record_id, user_id, badge_id, performance_id, proof_image_url, audit_status, reject_reason, created_at, updated_at) VALUES (?,?,?,?,?,0,'',now(),now())
# ----------------------------------------------------
candy_user_coupon.close=UPDATE candy_user_coupon SET state=2,updated_at=sysdate(),operator='close' WHERE uid=? AND state=1
......
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