重学SpringBoot3-集成Redis(十三)之点排行榜实现

重学SpringBoot3-集成Redis(十三)之点排行榜实现

CoderJia 24 2024-10-11

在现代应用程序中,排行榜功能常用于展示用户或内容的排名,如游戏中的分数排名、社交平台上的活跃度排名等。Redis 提供的有序集合(Sorted Set)结构,能够通过分数进行排序,非常适合用来构建排行榜。本文将介绍如何使用 Spring Boot 3Redis 实现一个简单的排行榜功能。

1. 为什么选择 Redis 来实现排行榜?

Redis 的有序集合(Sorted Set)具备以下优点:

  • 高效排序:有序集合是通过分数(Score)来进行排序的,支持快速的插入、删除和排序操作。
  • 高性能:Redis 是内存数据库,读写速度非常快,特别适合实时性要求高的应用。
  • 丰富的操作:Redis 提供了多种操作命令,如按分数范围查询、获取前 N 名等,非常适合排行榜的需求。

Redis 有序集合通过 zadd 命令向集合中添加成员,并为每个成员设置一个分数。通过 zrange 等命令可以按分数从小到大或从大到小获取成员的排名。

排行榜举例

2. 项目环境准备

2.1. 添加依赖

首先,在 pom.xml 中引入 Spring Boot 3Redis 的相关依赖,具体参考重学SpringBoot3-集成Redis(一)之基本使用

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

2.2. 配置 Redis 连接

application.yml 中配置 Redis:

spring:
  data:
    redis:
      host: localhost
      port: 6379            # Redis 端口
      password: redis123456 # 如果有密码可以在这里配置
      lettuce:
        pool:
          max-active: 100    # 最大并发连接数
          max-idle: 50       # 最大空闲连接数
          min-idle: 10       # 最小空闲连接数

3. 排行榜功能实现

3.1 排行榜服务的实现

我们使用 Redis 的有序集合(Sorted Set)来存储排行榜的数据。成员(用户或内容)作为集合的元素,得分(如游戏分数、点赞数)作为排序依据。

package com.coderjia.boot310redis.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author CoderJia
 * @create 2024/10/7 下午 09:13
 * @Description
 **/
@Service
public class LeaderboardService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final String LEADERBOARD_KEY = "leaderboard";
   

    // 添加用户及其得分到排行榜
    public void addUserToLeaderboard(String userId, double score) {
        redisTemplate.opsForZSet().add(LEADERBOARD_KEY, userId, score);
    }

    // 获取前N名用户
    public Set<String> getTopUsers(int n) {
        return redisTemplate.opsForZSet().reverseRange(LEADERBOARD_KEY, 0, n - 1);
    }

    // 获取某个用户的排名
    public Long getUserRank(String userId) {
        return redisTemplate.opsForZSet().reverseRank(LEADERBOARD_KEY, userId);
    }

    // 获取某个用户的得分
    public Double getUserScore(String userId) {
        return redisTemplate.opsForZSet().score(LEADERBOARD_KEY, userId);
    }

    // 获取用户的排名和得分
    public Map<String, Object> getUserRankAndScore(String userId) {
        Map<String, Object> result = new HashMap<>();
        result.put("rank", getUserRank(userId));
        result.put("score", getUserScore(userId));
        return result;
    }
}

3.2 排行榜功能的 REST 接口

为排行榜功能创建简单的 REST API,用户可以通过该接口添加分数、查看前几名和用户排名等操作。

package com.coderjia.boot310redis.demos.web;

import com.coderjia.boot310redis.service.LeaderboardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;
import java.util.Set;

/**
 * @author CoderJia
 * @create 2024/10/10 下午 10:36
 * @Description
 **/
@RestController
@RequestMapping("/api/leaderboard")
public class LeaderboardController {

    @Autowired
    private LeaderboardService leaderboardService;

    // 添加用户得分
    @PostMapping("/add")
    public ResponseEntity<String> addUser(@RequestParam("userId") String userId, @RequestParam("score") double score) {
        leaderboardService.addUserToLeaderboard(userId, score);
        return ResponseEntity.ok("User added to leaderboard.");
    }

    // 获取前N名
    @GetMapping("/top")
    public ResponseEntity<Set<String>> getTopUsers(@RequestParam("topN") int topN) {
        return ResponseEntity.ok(leaderboardService.getTopUsers(topN));
    }

    // 获取某个用户的排名和得分
    @GetMapping("/user/{userId}")
    public ResponseEntity<Map<String, Object>> getUserRankAndScore(@PathVariable String userId) {
        return ResponseEntity.ok(leaderboardService.getUserRankAndScore(userId));
    }
}

3.3 测试接口

你可以使用 Postman 或 curl 来测试这些接口。例如,添加用户的接口请求可以这样发起:

curl -X POST "http://localhost:8080/api/leaderboard/add?userId=1&score=100"

添加用户

获取前 5 名的接口请求:

curl -X GET "http://localhost:8080/api/leaderboard/top?topN=5"

Top5

获取某个用户的排名和得分:

curl -X GET "http://localhost:8080/api/leaderboard/user/1"

获取某个用户的排名

4. 关键代码解析

  • redisTemplate.opsForZSet().add(key, value, score):将用户 ID 和分数作为一对数据添加到有序集合中,key 为排行榜的键。
  • redisTemplate.opsForZSet().reverseRange(key, start, end):根据分数从高到低获取排行榜前几名用户。
  • redisTemplate.opsForZSet().reverseRank(key, value):获取用户的排名,返回值是排名(从 0 开始)。
  • redisTemplate.opsForZSet().score(key, value):获取用户的分数。

5. 小结

使用 Spring Boot 3Redis 实现排行榜非常高效且简便。Redis 的有序集合为我们提供了强大的排序功能,能够轻松处理各种排行榜需求。通过该方案,我们可以实现以下功能:

  • 动态添加用户得分到排行榜
  • 实时获取前几名的用户
  • 查询用户的排名和分数

Redis 由于其快速的读写性能,非常适合用于实时性要求高的排行榜应用场景。如果你需要开发类似的功能,Redis 无疑是一个理想的选择。