項目名稱: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加載資料,這些我們先留着,先到這裡,以上是我們之前課程講過的内容,大家先行消化一下。