1.使用场景
现在公司有个项目,类似于今日头条,需要实现对应分类阅读排行榜的功能。
每一篇文章所属于一个分类,当用户阅读该文章时,阅读次数+1,排行榜实时变化。
2.redis的ZSet数据结构
zset为有序集合。就是在set的基础上,添加了一个score值。zset的每一个成员都有一个分数与之对应,并且分数可以重复。score就相当于权重,可以根据score值进行排序展示。
项目中使用了SpringBoot整合的redisTemplate
常用方法如下:
-
Boolean add(K key, V value, double score):新增一个有序集合,存在的话为false,不存在的话为true
-
Long add(K key, Set<TypedTuple<V>> tuples):新增一个有序集合
-
Long remove(K key, Object... values):从有序集合中移除一个或者多个元素
-
Double incrementScore(K key, V value, double delta):增加元素的score值,并返回增加后的值
-
Set<V> range(K key, long start, long end):通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
-
Set<TypedTuple<V>> rangeWithScores(K key, long start, long end):通过索引区间返回有序集合成指定区间内的成员对象,其中有序集成员按分数值递增(从小到大)顺序排列
-
Set<V> rangeByScore(K key, double min, double max):通过分数返回有序集合指定区间内的成员,其中有序集成员按分数值递增(从小到大)顺序排列
-
Set<V> reverseRange(K key, long start, long end):通过索引区间返回有序集合成指定区间内的成员,其中有序集成员按分数值递减(从大到小)顺序排列
-
Double score(K key, Object o):获取指定成员的score值
3.代码实例
(1)项目中的缓存常量类
CacheConstant.java
-
/**
-
* 分类研报购买次数
-
*/
-
public
static
final String REPORT_CATEGORY_BUY_COUNT =
"report_report_category_buy_count:";
(2)CacheService.java
-
@Autowired
-
private RedisTemplate<String, Object> template;
-
-
/**
-
* 增加研报分类阅读次数(查看文章详情接口时调用)
-
*
-
* @param categoryId
-
*/
-
public void incrReportCategoryReadCount(Long categoryId) {
-
template.opsForZSet().incrementScore(CacheConstant.REPORT_CATEGORY_READ_COUNT, categoryId,
1);
-
}
-
-
/**
-
* 获取研报分类阅读排行榜
-
*/
-
public Set<Object> getReportCategoryReadCountRank() {
-
if (template.hasKey(CacheConstant.REPORT_CATEGORY_READ_COUNT)) {
-
//0,-1的参数代表查询该key下的所有value
-
return template.opsForZSet().reverseRange(CacheConstant.REPORT_CATEGORY_READ_COUNT,
0, -
1);
-
}
else {
-
return
new HashSet<>();
-
}
-
}
-
-
-
/**
-
* 获取研报分类阅读排行榜具体分类次数
-
*/
-
public Double getReportCategoryBuyCount(Object o) {
-
return template.opsForZSet().score(CacheConstant.REPORT_CATEGORY_BUY_COUNT, o);
-
}
-
这里我们将分类在数据库中的主键id存进去,以便按顺序查出来之后去数据库中查询对应的分类名。
-
score值就是该文章的阅读次数,可以直接调用接口获取
4.Rank.java
-
public
static
class Rank implements Serializable {
-
private Long id;
-
private String name;
-
private Integer times;
-
}
5.StatisticService.java
-
@Autowired
-
private CacheService cacheService;
-
-
public StatisticsPlatformResponse platform() {
-
//查询一级分类下的研报阅读排行
-
List<Rank> readRank =
new ArrayList<>();
-
//一次性查询出所有一级分类,然后和分类排行榜的对应id去匹配
-
List<ReportCategory> oneCategoryList = reportCategoryService.findAllOneCategory();
-
-
Set<Object> readCountRank = cacheService.getReportCategoryReadCountRank();
-
if (readCountRank !=
null) {
-
for (Object o : readCountRank) {
-
Rank singReadRank = getRank(oneCategoryList, (Number) o);
-
singReadRank.setTimes(cacheService.getReportCategoryReadCount(o).intValue());
-
readRank.add(singReadRank);
-
}
-
}
-
return readRank;
-
}
-
-
private Rank getRank(List<ReportCategory> oneCategoryList, Number o) {
-
Rank rank =
new Rank();
-
rank.setId(o.longValue());
-
rank.setName(getCategoryName(o.longValue(), oneCategoryList));
-
return rank;
-
}
-
-
/**
-
* 获取分类名
-
*
-
* @param categoryId
-
* @param list
-
* @return
-
*/
-
private String getCategoryName(Long categoryId, List<ReportCategory> list) {
-
for (ReportCategory category : list) {
-
if (category.getId().equals(categoryId)) {
-
return category.getName();
-
}
-
}
-
return
null;
-
}