这里写自定义目录标题
- 日榜的实现
- 周榜数据
- 月榜数据
主要使用redis的zset数据接口进行实现,zset的结构为key,value,score,以score值对集合中的各个数据进行排序。本次的排行榜数据实现是利用每当有用户的分数score发生变化时,就进行日榜,周榜,月榜的统计,从而实现排行榜功能。 只是功能实现,如有不足请各位指正
日榜的实现
日榜数据只需要以当天的用户分数进行统计排名处理,设计方式为key=20220613:dayRank value=用户姓名 score=用户分值
//当前日期字符串
String today = LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd");
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
ZSetOperations operation = redisTemplate.opsForZSet();
//添加日榜数据 incrementScore方法当对应的key不存在时,会自动创建对应key的集合,已存在则会增加对应value的score
operation.incrementScore("2022-06-13:dayRank","lyx",30);
operation.incrementScore("2022-06-13:dayRank","lisi",5);
operation.incrementScore("2022-06-13:dayRank","zhangsan",10);
运行结果
后续对应排名信息利用redisTemplate对应的api即可
周榜数据
周榜数据为一周第一天到一周最后一天的所有用户的分数排行数据,默认一周第一天为周一,最后一天为周二。 设计思路为:获取一周第一天,循环从redis中获取这周每天的zset数据至今天为止,并进行合集处理,那么此时合集的数据就为这周到今天为止的周榜数据。
//添加测试数据
operation.incrementScore("2022-06-01:dayRank","lyx",30);
operation.incrementScore("2022-06-02:dayRank","lisi",5);
operation.incrementScore("2022-06-03:dayRank","zhangsan",10);
operation.incrementScore("2022-06-04:dayRank","lyx",30);
operation.incrementScore("2022-06-05:dayRank","lisi",5);
operation.incrementScore("2022-06-06:dayRank","zhangsan",10);
operation.incrementScore("2022-06-10:dayRank","lyx",30);
operation.incrementScore("2022-06-10:dayRank","lisi",20);
operation.incrementScore("2022-06-10:dayRank","zhangsan",10);
//当前日期所在周的第一天
Calendar calendar = CalendarUtil.calendar();
LocalDateTime weekBeginDay = CalendarUtil.toLocalDateTime(CalendarUtil.beginOfWeek(calendar));
String weekBeginDayStr = LocalDateTimeUtil.format(weekBeginDay, "yyyy-MM-dd");
String weekRankKey = weekBeginDayStr; //周榜缓存key yyyy-MM-dd:weekRank
LocalDateTime weekNextDay = weekBeginDay;
String weekNextDayStr = weekBeginDayStr; //周榜初始下一天为一周的第一天
两个Util需要引入hutool依赖,此时获取了该周的第一天以及第一天下一天的数据(初始值为该周的第一天)
//计算周榜数据 周榜数据为 当前日期所在周的第一天至当前日期的数据 周榜数据需要累加的key集合
ArrayList<String> weekKeyList = new ArrayList<>();
//计算周榜数据
while (true) {
//下一天为当天跳出循环,不存入需要计算的周榜key集合,直接在操作方法中添加当天key
if (weekNextDayStr.equals(today)) {
break;
}
weekKeyList.add(weekNextDayStr+":dayRank");
//在一周第一天的基础上加一天 至到日期与今天相同为周榜到今天为止的数据
weekNextDay = weekNextDay.plusDays(1);
weekNextDayStr = LocalDateTimeUtil.format(weekNextDay,"yyyy-MM-dd");
}
//循环结束后,集合中的数据为一周第一天到今天前一天的日榜key
ZSetOperations<String, Object> zsetOperation = redisTemplate.opsForZSet();
//对集合及今天的日榜数据进行合集计算获取周榜数据
zsetOperation.unionAndStore(today+":dayRank",weekKeyList,"weekRank_"+weekRankKey);
运行结果
月榜数据
实现思路与月榜数据相同,获取当月第一天,循环至今天的前一天添加key到集合中
//当前日期所在月的第一天
LocalDateTime monthBeginDay = CalendarUtil.toLocalDateTime(CalendarUtil.beginOfMonth(CalendarUtil.calendar()));
String monthBeginDayStr = LocalDateTimeUtil.format(monthBeginDay, "yyyy-MM-dd");
String monthRankKey = monthBeginDayStr; //月榜缓存key yyyy-MM-dd:monthRank
LocalDateTime monthNextDay = monthBeginDay;
String monthNextDayStr = monthBeginDayStr;
//月榜数据需要累加的key集合
ArrayList<String> monthKeyList = new ArrayList<>();
while (true) {
//下一天为当天,或者是当月的最后一天跳出循环(解决today日期,循环会将下月的日榜数据也统计,正确的是统计到该月月底的日榜数据)
if (monthNextDayStr.equals(today)) {
break;
}
monthKeyList.add(monthNextDayStr+":dayRank");
//在一月第一天的基础上加一天,至到日期与今天相同或者与当月最后一天数据相同为月榜到今天为止的数据
monthNextDay = monthNextDay.plusDays(1);
monthNextDayStr = LocalDateTimeUtil.format(monthNextDay, "yyyy-MM-dd");
}
zsetOperation.unionAndStore(today+":dayRank",monthKeyList,"monthRank_"+monthRankKey);
运行结果