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

Commit c43bc066 authored by wangyifan's avatar wangyifan

草莓护照- 支持批量领取徽章

parent 5779f1da
...@@ -5,12 +5,14 @@ import io.swagger.annotations.ApiModelProperty; ...@@ -5,12 +5,14 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data; import lombok.Data;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import java.util.List;
@Data @Data
@ApiModel("草莓徽章-认领参数") @ApiModel("草莓徽章-认领参数")
public class AdamCaomeiBadgeClaimParam { public class AdamCaomeiBadgeClaimParam {
@NotBlank(message = "徽章ID不能为空") @NotEmpty(message = "徽章ID列表不能为空")
@ApiModelProperty(value = "徽章ID", required = true) @ApiModelProperty(value = "徽章ID列表", required = true)
private String badgeId; private List<@NotBlank(message = "徽章ID不能为空") String> badgeIds;
} }
...@@ -14,7 +14,7 @@ public interface IAdamCaomeiBadgeUserService { ...@@ -14,7 +14,7 @@ public interface IAdamCaomeiBadgeUserService {
/** /**
* 认领徽章 * 认领徽章
*/ */
ResponseDto<String> claimBadge(String badgeId, String uid); ResponseDto<List<String>> claimBadges(List<String> badgeIds, String uid);
/** /**
* 补签申请记录列表(用户端) * 补签申请记录列表(用户端)
......
...@@ -87,6 +87,18 @@ public interface AdamCaomeiBadgeMapper extends BaseMapper<AdamCaomeiBadge> { ...@@ -87,6 +87,18 @@ public interface AdamCaomeiBadgeMapper extends BaseMapper<AdamCaomeiBadge> {
@Select("select count(1) from adam_caomei_user_badge where user_id = #{userId} and badge_id = #{badgeId}") @Select("select count(1) from adam_caomei_user_badge where user_id = #{userId} and badge_id = #{badgeId}")
int checkUserBadgeExists(@Param("userId") String userId, @Param("badgeId") String badgeId); int checkUserBadgeExists(@Param("userId") String userId, @Param("badgeId") String badgeId);
@Select({
"<script>",
"select badge_id from adam_caomei_user_badge",
"where user_id = #{userId} and badge_id in",
"<foreach collection='badgeIds' item='badgeId' open='(' separator=',' close=')'>",
"#{badgeId}",
"</foreach>",
"</script>"
})
List<String> selectClaimedBadgeIdsByUserAndBadgeIds(@Param("userId") String userId,
@Param("badgeIds") List<String> badgeIds);
@Insert({ @Insert({
"insert into adam_caomei_user_badge (user_id, badge_id, source, created_at) ", "insert into adam_caomei_user_badge (user_id, badge_id, source, created_at) ",
"values (#{userId}, #{badgeId}, #{source}, now())" "values (#{userId}, #{badgeId}, #{source}, now())"
......
...@@ -36,9 +36,9 @@ public class AdamCaomeiBadgeUserController { ...@@ -36,9 +36,9 @@ public class AdamCaomeiBadgeUserController {
@ApiOperationSupport(order = 1) @ApiOperationSupport(order = 1)
@ApiOperation("认领徽章") @ApiOperation("认领徽章")
@PostMapping("claim") @PostMapping("claim")
public ResponseDto<String> claim(@Valid @RequestBody AdamCaomeiBadgeClaimParam param) { public ResponseDto<List<String>> claim(@Valid @RequestBody AdamCaomeiBadgeClaimParam param) {
String uid = CurrentUtil.getCurrentUid(); String uid = CurrentUtil.getCurrentUid();
return adamCaomeiBadgeUserService.claimBadge(param.getBadgeId(), uid); return adamCaomeiBadgeUserService.claimBadges(param.getBadgeIds(), uid);
} }
@ApiOperationSupport(order = 2) @ApiOperationSupport(order = 2)
......
...@@ -30,8 +30,11 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -30,8 +30,11 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.HashSet;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Slf4j @Slf4j
...@@ -51,21 +54,36 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi ...@@ -51,21 +54,36 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public ResponseDto<String> claimBadge(String badgeId, String uid) { public ResponseDto<List<String>> claimBadges(List<String> badgeIds, String uid) {
if (StringUtils.isBlank(uid)) { if (StringUtils.isBlank(uid)) {
return ResponseDto.failure(ErrorMapping.get("10001")); return ResponseDto.failure(ErrorMapping.get("10001"));
} }
if (badgeIds == null || badgeIds.isEmpty()) {
return ResponseDto.failure("徽章ID列表不能为空");
}
List<String> requestBadgeIds = badgeIds.stream()
.filter(StringUtils::isNotBlank)
.map(StringUtils::trim)
.collect(Collectors.collectingAndThen(Collectors.toCollection(LinkedHashSet::new), ArrayList::new));
if (requestBadgeIds.isEmpty()) {
return ResponseDto.failure("徽章ID列表不能为空");
}
// 1. 查询徽章配置 // 1) 批量查询徽章配置(一次查询)
AdamCaomeiBadge badge = adamCaomeiBadgeMapper.selectOne( List<AdamCaomeiBadge> badges = adamCaomeiBadgeMapper.selectList(
Wrappers.lambdaQuery(AdamCaomeiBadge.class) Wrappers.lambdaQuery(AdamCaomeiBadge.class)
.eq(AdamCaomeiBadge::getBadgeId, badgeId) .in(AdamCaomeiBadge::getBadgeId, requestBadgeIds)
.eq(AdamCaomeiBadge::getDisplayStatus, 1) .eq(AdamCaomeiBadge::getDisplayStatus, 1)
); );
if (badge == null) { if (badges == null || badges.size() != requestBadgeIds.size()) {
log.error("[claimBadge] 徽章不存在或未上架, uid: {}, badgeId: {}", uid, badgeId); log.error("[claimBadges] 存在徽章不存在或未上架, uid: {}, badgeIds: {}", uid, requestBadgeIds);
return ResponseDto.failure(ErrorMapping.get("10607")); return ResponseDto.failure(ErrorMapping.get("10607"));
} }
Map<String, AdamCaomeiBadge> badgeMap = badges.stream()
.collect(Collectors.toMap(AdamCaomeiBadge::getBadgeId, b -> b));
List<AdamCaomeiBadge> orderedBadges = requestBadgeIds.stream()
.map(badgeMap::get)
.collect(Collectors.toList());
// 2. 与收货地址 add 一致:先取 Redis(或回源)用户徽章列表,再判重;DB 再兜一层防缓存未命中或其它写入路径 // 2. 与收货地址 add 一致:先取 Redis(或回源)用户徽章列表,再判重;DB 再兜一层防缓存未命中或其它写入路径
List<AdamCaomeiPassportUserBadgeDto> badgeVos = adamRdmService.getUserCaomeiBadgesByUid(uid); List<AdamCaomeiPassportUserBadgeDto> badgeVos = adamRdmService.getUserCaomeiBadgesByUid(uid);
...@@ -74,19 +92,35 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi ...@@ -74,19 +92,35 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
} else { } else {
badgeVos = new ArrayList<>(badgeVos); badgeVos = new ArrayList<>(badgeVos);
} }
if (badgeVos.stream().anyMatch(b -> badgeId.equals(b.getBadgeId()))) { Set<String> claimedInCache = badgeVos.stream()
log.info("[claimBadge] 用户已领取过该徽章(Redis列表), uid: {}, badgeId: {}", uid, badgeId); .map(AdamCaomeiPassportUserBadgeDto::getBadgeId)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
if (requestBadgeIds.stream().anyMatch(claimedInCache::contains)) {
log.info("[claimBadges] 用户已领取过徽章(Redis列表), uid: {}, badgeIds: {}", uid, requestBadgeIds);
return ResponseDto.failure(ErrorMapping.get("10608")); return ResponseDto.failure(ErrorMapping.get("10608"));
} }
int count = adamCaomeiBadgeMapper.checkUserBadgeExists(uid, badgeId); List<String> claimedInDb = adamCaomeiBadgeMapper.selectClaimedBadgeIdsByUserAndBadgeIds(uid, requestBadgeIds);
if (count > 0) { if (claimedInDb != null && !claimedInDb.isEmpty()) {
log.info("[claimBadge] 用户已领取过该徽章, uid: {}, badgeId: {}", uid, badgeId); log.info("[claimBadges] 用户已领取过徽章(DB), uid: {}, badgeIds: {}", uid, claimedInDb);
return ResponseDto.failure(ErrorMapping.get("10608")); return ResponseDto.failure(ErrorMapping.get("10608"));
} }
int type = badge.getType() == null ? 0 : badge.getType(); boolean hasType1 = orderedBadges.stream().anyMatch(b -> b.getType() != null && b.getType() == 1);
boolean hasType2 = orderedBadges.stream().anyMatch(b -> b.getType() != null && b.getType() == 2);
boolean hasType3 = orderedBadges.stream().anyMatch(b -> b.getType() != null && b.getType() == 3);
boolean hasUnknownType = orderedBadges.stream().anyMatch(b -> b.getType() == null || (b.getType() != 1 && b.getType() != 2 && b.getType() != 3));
if (hasType3) {
log.error("[claimBadges] 含特殊徽章不可自助领取, uid: {}, badgeIds: {}", uid, requestBadgeIds);
return ResponseDto.failure(ErrorMapping.get("10612"));
}
if (hasUnknownType) {
log.error("[claimBadges] 含未知徽章类型, uid: {}, badgeIds: {}", uid, requestBadgeIds);
return ResponseDto.failure(ErrorMapping.get("10613"));
}
if (type == 1) { if (hasType1) {
AdamCaomeiPassport bound = adamCaomeiPassportMapper.selectOne( AdamCaomeiPassport bound = adamCaomeiPassportMapper.selectOne(
Wrappers.lambdaQuery(AdamCaomeiPassport.class) Wrappers.lambdaQuery(AdamCaomeiPassport.class)
.eq(AdamCaomeiPassport::getUserId, uid) .eq(AdamCaomeiPassport::getUserId, uid)
...@@ -94,57 +128,92 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi ...@@ -94,57 +128,92 @@ public class AdamCaomeiBadgeUserServiceImpl implements IAdamCaomeiBadgeUserServi
.last("limit 1") .last("limit 1")
); );
if (bound == null) { if (bound == null) {
log.error("[claimBadge] 认领护照纪念徽章需先绑定护照, uid: {}, badgeId: {}", uid, badgeId); log.error("[claimBadges] 认领护照纪念徽章需先绑定护照, uid: {}, badgeIds: {}", uid, requestBadgeIds);
return ResponseDto.failure(ErrorMapping.get("10609")); return ResponseDto.failure(ErrorMapping.get("10609"));
} }
}
// 发放徽章 (source: 1-绑定护照自动发放/护照徽章认领):先写 Redis,再 MQ 落库 Set<String> paidPerformanceSet = Collections.emptySet();
grantUserBadgeRedisThenMq(uid, badge, 1, badgeVos); Set<String> passedApplyBadgeIds = Collections.emptySet();
log.info("[claimBadge] 护照纪念徽章认领成功, uid: {}, badgeId: {}", uid, badgeId); Set<String> passedApplyPerformanceIds = Collections.emptySet();
return ResponseDto.success(badgeId); Map<String, Set<String>> perfAllBadgeIds = Collections.emptyMap();
if (hasType2) {
} else if (type == 2) {
AdamRealInfoVo real = adamRdmService.getRealInfoVoByUidPlain(uid); AdamRealInfoVo real = adamRdmService.getRealInfoVoByUidPlain(uid);
if (real == null || real.getState() == null || real.getState() != 1 || StringUtils.isBlank(real.getIdCard())) { if (real == null || real.getState() == null || real.getState() != 1 || StringUtils.isBlank(real.getIdCard())) {
log.error("[claimBadge] 认领演出徽章需先实名, uid: {}, badgeId: {}", uid, badgeId); log.error("[claimBadges] 认领演出徽章需先实名, uid: {}, badgeIds: {}", uid, requestBadgeIds);
return ResponseDto.failure(ErrorMapping.get("10610")); return ResponseDto.failure(ErrorMapping.get("10610"));
} }
List<String> paidPerformanceIds = adamRdmService.getPaidPerformanceIdsByIdCard(real.getIdCard());
paidPerformanceSet = paidPerformanceIds == null ? Collections.emptySet() : new HashSet<>(paidPerformanceIds);
String idCard = real.getIdCard(); List<AdamCaomeiBadgeApplyRecord> passedApplyRecords = badgeApplyRecordMapper.selectList(
List<String> paidPerformanceIds = adamRdmService.getPaidPerformanceIdsByIdCard(idCard); Wrappers.lambdaQuery(AdamCaomeiBadgeApplyRecord.class)
boolean hasPaidRecord = paidPerformanceIds != null && paidPerformanceIds.contains(badge.getPerformanceId()); .eq(AdamCaomeiBadgeApplyRecord::getUserId, uid)
String perfId = StringUtils.trimToEmpty(badge.getPerformanceId()); .eq(AdamCaomeiBadgeApplyRecord::getAuditStatus, 1)
boolean hasPassedApply; );
if (StringUtils.isNotBlank(perfId)) { passedApplyBadgeIds = new HashSet<>();
hasPassedApply = countApplyForUserPerformanceAudit(uid, perfId, 1) > 0; passedApplyPerformanceIds = new HashSet<>();
} else { if (passedApplyRecords != null) {
Integer passedApplyCount = badgeApplyRecordMapper.selectCount( for (AdamCaomeiBadgeApplyRecord r : passedApplyRecords) {
Wrappers.lambdaQuery(AdamCaomeiBadgeApplyRecord.class) if (r == null) {
.eq(AdamCaomeiBadgeApplyRecord::getUserId, uid) continue;
.eq(AdamCaomeiBadgeApplyRecord::getBadgeId, badgeId) }
.eq(AdamCaomeiBadgeApplyRecord::getAuditStatus, 1) if (StringUtils.isNotBlank(r.getBadgeId())) {
passedApplyBadgeIds.add(r.getBadgeId());
}
if (StringUtils.isNotBlank(r.getPerformanceId())) {
passedApplyPerformanceIds.add(r.getPerformanceId());
}
}
}
Set<String> targetPerfIds = orderedBadges.stream()
.filter(b -> b.getType() != null && b.getType() == 2)
.map(AdamCaomeiBadge::getPerformanceId)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
if (!targetPerfIds.isEmpty()) {
List<AdamCaomeiBadge> perfBadges = adamCaomeiBadgeMapper.selectList(
Wrappers.lambdaQuery(AdamCaomeiBadge.class)
.eq(AdamCaomeiBadge::getType, 2)
.in(AdamCaomeiBadge::getPerformanceId, targetPerfIds)
); );
hasPassedApply = passedApplyCount != null && passedApplyCount > 0; perfAllBadgeIds = perfBadges.stream()
.filter(b -> StringUtils.isNotBlank(b.getPerformanceId()) && StringUtils.isNotBlank(b.getBadgeId()))
.collect(Collectors.groupingBy(AdamCaomeiBadge::getPerformanceId,
Collectors.mapping(AdamCaomeiBadge::getBadgeId, Collectors.toSet())));
} }
}
if (!hasPaidRecord && !hasPassedApply) { List<String> claimedBadgeIds = new ArrayList<>();
log.error("[claimBadge] 无购票记录且无通过的补签申请,无法认领, uid: {}, badgeId: {}", uid, badgeId); for (AdamCaomeiBadge badge : orderedBadges) {
return ResponseDto.failure(ErrorMapping.get("10611")); int type = badge.getType() == null ? 0 : badge.getType();
int source = 1;
if (type == 2) {
String perfId = StringUtils.trimToEmpty(badge.getPerformanceId());
boolean hasPaidRecord = StringUtils.isNotBlank(perfId) && paidPerformanceSet.contains(perfId);
boolean hasPassedApply = false;
if (StringUtils.isNotBlank(perfId)) {
if (passedApplyPerformanceIds.contains(perfId)) {
hasPassedApply = true;
} else {
Set<String> badgeIdSet = perfAllBadgeIds.getOrDefault(perfId, Collections.emptySet());
hasPassedApply = badgeIdSet.stream().anyMatch(passedApplyBadgeIds::contains);
}
}
if (!hasPaidRecord && !hasPassedApply) {
log.error("[claimBadges] 无购票记录且无通过补签,无法认领, uid: {}, badgeId: {}", uid, badge.getBadgeId());
return ResponseDto.failure(ErrorMapping.get("10611"));
}
source = hasPaidRecord ? 2 : 3;
} }
int source = hasPaidRecord ? 2 : 3;
grantUserBadgeRedisThenMq(uid, badge, source, badgeVos); grantUserBadgeRedisThenMq(uid, badge, source, badgeVos);
claimedBadgeIds.add(badge.getBadgeId());
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"));
} }
log.error("[claimBadge] 未知的徽章类型, uid: {}, badgeId: {}, type: {}", uid, badgeId, type); log.info("[claimBadges] 批量认领成功, uid: {}, badgeIds: {}", uid, claimedBadgeIds);
return ResponseDto.failure(ErrorMapping.get("10613")); return ResponseDto.success(claimedBadgeIds);
} }
/** /**
......
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