PointsBoardServiceImpl
package com.tianji.learning.service.impl;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tianji.api.client.user.UserClient;
import com.tianji.api.dto.user.UserDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.StringUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.constant.RedisConstant;
import com.tianji.learning.domain.po.PointsBoard;
import com.tianji.learning.domain.po.PointsBoardSeason;
import com.tianji.learning.domain.query.PointsBoardQuery;
import com.tianji.learning.domain.vo.PointsBoardItemVO;
import com.tianji.learning.domain.vo.PointsBoardSeasonVO;
import com.tianji.learning.domain.vo.PointsBoardVO;
import com.tianji.learning.mapper.PointsBoardMapper;
import com.tianji.learning.service.IPointsBoardService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
/**
* <p>
* 学霸天梯榜 服务实现类
* </p>
*
* @author wyy
* @since 2025-04-21
*/
@RequiredArgsConstructor
@Slf4j
@Service
public class PointsBoardServiceImpl extends ServiceImpl<PointsBoardMapper, PointsBoard> implements IPointsBoardService {
private final StringRedisTemplate redisTemplate;
private final UserClient userClient;
/**
* 查询学霸积分榜--当前赛季和历史赛季均可用
* @param query
* @return
*/
@Override
public PointsBoardVO queryPointsBoardList(PointsBoardQuery query) {
//1、获取当前登录用户id
Long userId = UserContext.getUser();
//2、判断是查询当前赛季,还是查询历史赛季 query.season 赛季id 为0或bull 查询当前赛季
boolean isCurrent = query.getSeason() == null || query.getSeason() == 0; //isCurrent为true表示查询当前赛季从redis查询
LocalDate now = LocalDate.now();
String format = now.format(DateTimeFormatter.ofPattern("yyyyMM"));
String key = RedisConstant.POINTS_BOARD_KEY_PREFIX + format;
Long season = query.getSeason(); //历史赛季id
//3、查询我的排名和积分 根据query.season 判断是查询redis还是DB
PointsBoard board = isCurrent ? queryMyCurrentBoard(key) : queryMyHistoryBoard(season);
//4、分页查询赛季列表 根据query.season 判断是查询redis还是DB
List<PointsBoard> list = isCurrent ? queryCurrentBoard(key, query.getPageNo() , query.getPageSize()) : queryHistoryBoard(query);
//5、封装用户id集合,远程调用用户服务,获取用户信息 转map
Set<Long> uids = list.stream().map(PointsBoard::getUserId).collect(Collectors.toSet());
List<UserDTO> userDTOS = userClient.queryUserByIds(uids);
if (CollUtils.isEmpty(userDTOS)) {
throw new BizIllegalException("用户不存在!");
}
//转map key为userId value为用户名
Map<Long, String> userDtoMap = userDTOS.stream().collect(Collectors.toMap(UserDTO::getId, c -> c.getName()));
//6、封装VO并返回
PointsBoardVO vo = new PointsBoardVO();
vo.setRank(board.getRank()); //我的排名
vo.setPoints(board.getPoints()); //我的积分值
ArrayList<PointsBoardItemVO> voList = new ArrayList<>();
for (PointsBoard pointsBoard : list) {
PointsBoardItemVO itemVO = new PointsBoardItemVO();
itemVO.setName(userDtoMap.get(pointsBoard.getUserId())); //用户名
itemVO.setRank(pointsBoard.getRank()); //排名
itemVO.setPoints(pointsBoard.getPoints()); //积分值
voList.add(itemVO);
}
vo.setBoardList(voList);
return vo;
}
/*
* 查询当前赛季 我的积分和排名 查redis
*/
private PointsBoard queryMyCurrentBoard(String key) {
//获取当前登录用户id
Long userId = UserContext.getUser();
//获取积分值
Double score = redisTemplate.opsForZSet().score(key, userId.toString());
//获取排名,从0开始,需要加 1
Long rank = redisTemplate.opsForZSet().reverseRank(key, userId.toString());
//封装vo,并返回
PointsBoard board = new PointsBoard();
board.setRank(rank == null ? 0 : rank.intValue() + 1);
board.setPoints(score == null ? 0 : score.intValue());
return board;
}
/*
* 查询历史赛季 我的积分和排名 查DB
*/
private PointsBoard queryMyHistoryBoard(Long season) {
//1、校验参数
if (season == null) {
throw new BizIllegalException("赛季id不能为空!");
}
//2、获取当前登录用户id
Long userId = UserContext.getUser();
//3、获取积分值、排名
PointsBoard board = this.lambdaQuery()
.eq(PointsBoard::getUserId, userId)
.eq(PointsBoard::getSeason, season)
.one();
return board;
}
/*
* 查询当前赛季排行榜列表 查redis ZSet结构
*/
public List<PointsBoard> queryCurrentBoard(String key, Integer pageNo, Integer pageSize) {
//1、计算起始位置和结束位置 分页值
int start = (pageNo - 1) * pageSize;
int end = start + pageSize - 1;
//2、利用zrevrange 按分值倒序查询分页数据
Set<ZSetOperations.TypedTuple<String>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
if (CollUtils.isEmpty(typedTuples)) {
return CollUtils.emptyList();
}
//3、封装vo
int rank = start + 1; //每一页排名的起始值
List<PointsBoard> list = new ArrayList<>();
for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
String value = typedTuple.getValue(); //userId
Double score = typedTuple.getScore(); //总积分值
if (StringUtils.isBlank(value) || score == null) {
continue;
}
PointsBoard board = new PointsBoard();
board.setUserId(Long.valueOf(value)); //userId
board.setPoints(score.intValue()); //积分
board.setRank(rank++); //排名
list.add(board);
}
//4、返回
return list;
}
/*
* 查询历史赛季排行榜列表 查DB
*/
private List<PointsBoard> queryHistoryBoard(PointsBoardQuery query) {
// 1.参数校验
if (query.getSeason() == null || query.getSeason() <= 0) {
throw new BizIllegalException("赛季ID参数不合法");
}
//2、获取历史榜单列表
Page<PointsBoard> page = this.lambdaQuery()
.eq(PointsBoard::getSeason, query.getSeason())
.page(query.toMpPage());
List<PointsBoard> records = page.getRecords();
if (CollUtils.isEmpty(records)) {
return CollUtils.emptyList();
}
//3、返回结果
return records;
}
}