项目名称:eblog
项目 Git 仓库:https://github.com/MarkerHub/eblog(给个 star 支持哈)
前几篇项目讲解文章:
1、Github 上最值得学习的 Springboot 开源博客项目!
2、小 Hub 手把手教你如何从 0 搭建一个开源项目架构
3、整合Redis,以及项目优雅的异常处理与返回结果封装
本周热议,本周发表并且评论最多的文章排行,如果直接查询数据库的话很快就可以实现,只需要限定一下文章创建时间,然后更加评论数量倒叙取前几篇即可搞定。
但这里我们使用redis来完成。之前上课时候我们说过,排行榜功能,我们可以使用redis的有序集合zset来完成。现在我们就这个数据结构来完成本周热议的功能。
在编码之前,我们需要先来回顾一下zset的几个基本命令。
zrange key start stop [WITHSCORES]
withscores代表的是否显示顺序号 start和stop代表所在的位置的索引。可以这样理解:将集合元素依照顺序值升序排序再输出,start和stop限制遍历的限制范围
zincrby key increment member
为有序集 key 的成员 member 的 score 值加上增量 increment 。
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。
默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之 和 。
其他命令可以参考这里:http://doc.redisfans.com/
以下是我做的实验:

我们来分析一下我们的需求。我们想用缓存来完成这本周热议排行榜功能,不依赖数据库(除了初始化数据)。有人发表评论之后,直接使用命令加一,并重新计算并集得到排行榜。
项目启动时候我们先初始化最近文章的评论数量。基本逻辑如下:
查库获取最近7天的所有文章(或者加多一个条件:评论数量大于0)
然后把文章的评论数量作为有序集合的分数,文章id作为ID存储到zset中。
本周热议上有标题和评论数量,因此,我们还需要把文章的基本信息存储到redis总。这样得到文章的id之后,我们再从缓存中得到标题等信息,这里我们可以使用hash的结构来存储文章的信息。
另外,因为是本周热议,如果文章发表超过7天了之后就没啥用了,所以我们可以给文章的有序集合一个有效时间。超过7天之后就自定删除缓存。
具体代码如下:
com.example.service.impl.PostServiceImpl#initIndexWeekRank
对应的缓存文章信息的方法如下:
统计7天的文章集合交集数量:
写好了之后,我们再我们的项目启动类中调用一下即可完成了初始化。
<code>@Slf4j</code>
<code>@Order(1000)</code>
<code>@Component</code>
<code>public class ContextStartup implements ApplicationRunner, ServletContextAware {</code>
<code> private ServletContext servletContext;</code>
<code> @Autowired</code>
<code> PostService postService;</code>
<code> @Override</code>
<code> public void setServletContext(ServletContext servletContext) {</code>
<code> this.servletContext = servletContext;</code>
<code> }</code>
<code> public void run(ApplicationArguments args) throws Exception {</code>
<code> servletContext.setAttribute("base", servletContext.getContextPath());</code>
<code> //初始化首页的周评论排行榜</code>
<code> postService.initIndexWeekRank();</code>
<code>}</code>
以上就完成了初始化。这时候我们在本周热议模块已经可以看到效果了。缓存中已经有我们想要的数据,接下我们在controller中获取出来,然后返回给个我们的页面,页面用异步加载的模式,所以这里定义一个异步接口:
com.example.controller.PostController
<code>@ResponseBody</code>
<code>@GetMapping("/post/hots")</code>
<code>public Result hotPost() {</code>
<code> Set<ZSetOperations.TypedTuple> lastWeekRank = redisUtil.getZSetRank("last_week_rank", 0, 6);</code>
<code> List<Map<String, Object>> hotPosts = new ArrayList<>();</code>
<code> for (ZSetOperations.TypedTuple typedTuple : lastWeekRank) {</code>
<code> Map<String, Object> map = new HashMap<>();</code>
<code> map.put("comment_count", typedTuple.getScore());</code>
<code> map.put("id", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:id"));</code>
<code> map.put("title", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:title"));</code>
<code> hotPosts.add(map);</code>
<code> return Result.succ(hotPosts);</code>
}
致此,我们已经完成了获取本周热议的数据,但是,只是一个初始化而已,当有评论的时候还应该添加数据到我们的缓存中,还有页面的内容我们也应该写一些ajax加载数据,这些我们先留着,先到这里,以上是我们之前课程讲过的内容,大家先行消化一下。