天机学堂day8作业,完善查询学霸积分榜功能

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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值