当前位置: 代码网 > it编程>编程语言>Java > SpringBoot+Redission实现排行榜功能的示例代码

SpringBoot+Redission实现排行榜功能的示例代码

2024年05月28日 Java 我要评论
springboot+redission实现排行榜功能demo地址:ranking-demo: 排行榜demo (gitee.com)一、业务需求实现一个排行榜,要求按照分数和达成这个分数的时间排序,

springboot+redission实现排行榜功能

demo地址:ranking-demo: 排行榜demo (gitee.com)

一、业务需求

实现一个排行榜,要求按照分数和达成这个分数的时间排序,即相同分数下,时间早的在上面

二、redis中的zset(有序集合)

1.简介

redis 的 zset(也称为有序集合)是一种特殊的数据结构,它同时包含了集合和有序列表的特性。在 zset 中,每个成员都有一个分数(score)与之关联,这个分数可以是浮点数,用于对集合中的元素进行排序。

2.特点

  • 元素唯一:就像集合一样,zset 中不允许有重复成员。
  • 有序性:集合中的元素按照其关联的分数值进行升序排序。
  • 操作丰富:支持添加、删除成员,获取指定范围的成员,根据分数查询成员,计算交集、并集、差集等操作。

3.常用命令

  • zadd:向有序集合中添加一个或多个成员,或者更新已存在成员的分数。
  • zrange:返回有序集合中指定区间内的成员,通过索引位置来获取,从0开始。
  • zrangebyscore:返回有序集合中指定分数区间的成员。
  • zcard:获取有序集合的成员数量。
  • zrem:移除有序集合中的一个或多个成员。
  • zrevrange:类似于 zrange,但返回的是从高分到低分的成员。
  • zincrby:为有序集合中的成员的分数加上给定值。
  • zcount:计算有序集合中指定分数区间的成员数量。
  • zrank/zrevrank:获取成员在有序集合中的排名,zrank 是从低分到高分,zrevrank 是从高分到低分。

4.测试

> zadd zsetkey 1 member1
1
> zadd zsetkey 1 member2
1
> zadd zsetkey 1 member9
1
> zadd zsetkey 1 member5
1
> zrevrange zsetkey 0 10 withscores
member9
1
member5
1
member2
1
member1
1

5.总结

zset可以很好的实现分数排序,但是在相同的分数下,会按照成员的名称进行排序,所以要在此基础上增加时间

三、增加时间数据

为了增加完成时间,我们可以引进一个倒计时的概念,假设一共9秒

用户a在获得1分的时候在第2秒,那可以在redis中存储1*10+(9-2) => 18

用户b在获得1分的时候在第6秒,那可以在redis中存储1*10+(9-6) => 13

这样我们在获取分数的时候,可以倒推出分数和完成时间

四、springboot代码

1.引入redis和redission依赖

<!-- redis -->  
<dependency>  
    <groupid>org.springframework.boot</groupid>  
    <artifactid>spring-boot-starter-data-redis</artifactid>  
</dependency>  
  
<!-- redisson -->  
<dependency>  
    <groupid>org.redisson</groupid>  
    <artifactid>redisson-spring-boot-starter</artifactid>  
    <version>3.20.1</version>  
</dependency>

2.application.yml配置

--- # redis配置  
spring:  
  redis:  
    # 地址  
    host: localhost  
    # 端口,默认为6379  
    port: 6379  
    # 数据库索引  
    database: 0  
    # 密码(如没有密码请注释掉)  
    # password:    # 连接超时时间  
    timeout: 10s  
    # 是否开启ssl  
    ssl: false  
  
--- # redisson配置  
redisson:  
  # redis key前缀  
  keyprefix: ${spring.application.name}  
  # 线程池数量  
  threads: 4  
  # netty线程池数量  
  nettythreads: 8  
  # 单节点配置  
  singleserverconfig:  
    # 客户端名称  
    clientname: ${spring.application.name}  
    # 最小空闲连接数  
    connectionminimumidlesize: 8  
    # 连接池大小  
    connectionpoolsize: 32  
    # 连接空闲超时,单位:毫秒  
    idleconnectiontimeout: 10000  
    # 命令等待超时,单位:毫秒  
    timeout: 3000  
    # 发布和订阅连接池大小  
    subscriptionconnectionpoolsize: 50

3.java代码

constant

/**  
 * @author baisu  
 * @classname rankingconstant  
 * @description 排行榜常量数据  
 * @since 2024/5/6  
 */
public class rankingconstant {  
  
    public static final long basic_quantity = 10000000000000l;  
  
    public static final long maximum_time_timit = 29991231235959l;  
}

controller

import cn.hutool.core.date.datetime;  
import cn.hutool.core.date.dateutil;  
import com.ranking.demo.common.r;  
import com.ranking.demo.common.constant.rankingconstant;  
import com.ranking.demo.demain.rankingvo;  
import com.ranking.demo.utils.rankingutil;  
import com.ranking.demo.utils.rediskey;  
import com.ranking.demo.utils.redisutil;  
import org.redisson.client.protocol.scoredentry;  
import org.springframework.beans.factory.annotation.value;  
import org.springframework.web.bind.annotation.*;  
  
import java.util.arraylist;  
import java.util.collection;  
import java.util.list;  
  
/**  
 * @author baisu  
 * @since 2024/4/28  
 */
@restcontroller  
public class demorankingcontroller {  
  
    @value("${spring.application.name}")  
    private string applicationname;  
  
    /**  
     * 项目启动测试方法  
     *  
     * @return applicationname  
     */    
    @getmapping("")  
    public string demo() {  
        return applicationname;  
    }  
  
    /**  
     * 生成测试数据  
     *  
     * @return ok  
     */    
	@getmapping("/generate_test_data")  
    public r<object> generatetestdata() {  
        redisutil.addscorebymember(rediskey.getrankingdemokey(), 1l, "10001");  
        redisutil.addscorebymember(rediskey.getrankingdemokey(), 2l, "10002");  
        redisutil.addscorebymember(rediskey.getrankingdemokey(), 3l, "10003");  
        redisutil.addscorebymember(rediskey.getrankingdemokey(), 4l, "10004");  
        redisutil.addscorebymember(rediskey.getrankingdemokey(), 5l, "10005");  
        return r.ok();  
    }  
  
    /**  
     * 获取排行榜数据  
     *  
     * @param top 数量  
     * @return 排行榜数据  
     */  
    @getmapping("/get_ranking")  
    public r<object> getranking(@requestparam("top") integer top) {  
        collection<scoredentry<object>> ranking = redisutil.getranking(rediskey.getrankingdemokey(), 0, top - 1);  
        if (ranking.size() == 0) {  
            return r.fail("暂无排行榜数据");  
        }  
        list<rankingvo> list = new arraylist<>();  
        for (scoredentry<object> entry : ranking) {  
            rankingvo vo = new rankingvo();  
            vo.setmember(entry.getvalue().tostring());  
            vo.setscore(rankingutil.getscore(entry.getscore()));  
            vo.settime(rankingutil.gettimestr(entry.getscore()));  
            list.add(vo);  
        }  
        return r.ok(list);  
    }  
  
    /**  
     * 增加成员分数值  
     *  
     * @param member 成员  
     * @return 是否增加成功  
     */  
    @getmapping("/add_score_by_member")  
    public r<object> addscorebymember(@requestparam("member") string member) {  
        double scorebymember = redisutil.getscorebymember(rediskey.getrankingdemokey(), member);  
        if (scorebymember == null) {  
            scorebymember = 0.0;  
        }  
        redisutil.addscorebymember(rediskey.getrankingdemokey(), rankingutil.getscore(scorebymember) + 1, member);  
        return r.ok();  
    }  
  
    /**  
     * 获取成员分数值  
     *  
     * @param member 成员  
     * @return 分数值  
     */  
    @getmapping("/get_score_by_member")  
    public r<object> getscorebymember(@requestparam("member") string member) {  
        double scorebymember = redisutil.getscorebymember(rediskey.getrankingdemokey(), member);  
        if (scorebymember == null) {  
            return r.fail("该成员不存在");  
        }  
        rankingvo vo = new rankingvo();  
        vo.setmember(member);  
        vo.setscore(rankingutil.getscore(scorebymember));  
        vo.settime(rankingutil.gettimestr(scorebymember));  
        return r.ok(vo);  
    }  
  
}

domain

import lombok.data;  
  
/**  
 * @author baisu  
 * @classname rankingvo  
 * @description 排行榜展示类  
 * @since 2024/5/6  
 */
@data  
public class rankingvo {  
  
    /**  
     * 成员  
     */  
    private string member;  
    /**  
     * 分数值  
     */  
    private long score;  
    /**  
     * 时间  
     */  
    private string time;  
  
}
/**  
 * @author baisu  
 * @classname rediskey  
 * @description redis索引  
 * @since 2024/5/6  
 */
public class rediskey {  
  
    private static final string ranking_demo_key = "ranking_demo";  
  
    public static string getrankingdemokey() {  
        return ranking_demo_key;  
    }  
}
import cn.hutool.core.date.datetime;  
import cn.hutool.core.date.dateutil;  
import cn.hutool.extra.spring.springutil;  
import com.ranking.demo.common.constant.rankingconstant;  
import org.redisson.api.rscoredsortedset;  
import org.redisson.api.redissonclient;  
import org.redisson.client.protocol.scoredentry;  
  
import java.util.collection;  
  
/**  
 * @author baisu  
 * @classname redisutil  
 * @description redis工具类  
 * @since 2024/5/6  
 */
public class redisutil {  
  
    private static final redissonclient redisson_client = springutil.getbean(redissonclient.class);  
  
    /**  
     * 向有序集合中添加指定分数的成员  
     *  
     * @param key    有序集索引  
     * @param score  分数  
     * @param member 成员  
     * @return 是否成功  
     */  
    public static boolean addscorebymember(string key, long score, string member) {  
        rscoredsortedset<string> rscoredsortedset = redisson_client.getscoredsortedset(key);  
        double v = score * rankingconstant.basic_quantity + (rankingconstant.maximum_time_timit - long.parselong(dateutil.format(datetime.now(), rankingutil.format)));  
        return rscoredsortedset.add(v, member);  
    }  
  
    /**  
     * 返回有序集中成员的分数值  
     *  
     * @param key    有序集索引  
     * @param member 成员  
     * @return 分数值(double)  
     */    
     public static double getscorebymember(string key, string member) {  
        rscoredsortedset<object> scoredsortedset = redisson_client.getscoredsortedset(key);  
        return scoredsortedset.getscore(member);  
    }  
  
    /**  
     * 返回有序集中指定位置的成员集合  
     *  
     * @param key   有序集索引  
     * @param start 开始索引  
     * @param end   结束索引  
     * @return 成员集合  
     */  
    public static collection<scoredentry<object>> getranking(string key, int start, int end) {  
        rscoredsortedset<object> rscoredsortedset = redisson_client.getscoredsortedset(key);  
        return rscoredsortedset.entryrangereversed(start, end);  
    }  
  
}
import cn.hutool.core.date.dateutil;  
import com.ranking.demo.common.constant.rankingconstant;  
  
/**  
 * @author baisu  
 * @classname rankingutil  
 * @description 排行榜工具类  
 * @since 2024/5/7  
 */
 public class rankingutil {  
  
    public static final string format = "yyyymmddhhmmss";  
  
    public static long getscore(double score) {  
        return math.round(math.floor(score / rankingconstant.basic_quantity));  
    }  
  
    public static string gettimestr(double score) {  
        return string.valueof(dateutil.parse(string.valueof(rankingconstant.maximum_time_timit - math.round(math.floor(score)) % rankingconstant.basic_quantity)));  
    }  
}

4、接口文档

ranking_demo接口文档

以上就是springboot+redission实现排行榜功能的示例代码的详细内容,更多关于springboot redission排行榜的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com