從零開始搭建博客03----本週熱議處理(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 值之 和

實現步驟

  1. 查庫獲取最近7天的所有評論數量大於 0文章
  2. 把文章的評論數量作爲有序集合的分數,文章id作爲id存儲到zset中
  3. 緩存文章到set中,評論數量作爲排行標準
  4. 設置有效期爲7天,因爲超過了7天也就失去了時效性

具體代碼實現

com.fly.service.impl.PostServiceImpl#initIndexWeekRank

    @Override
    public void initIndexWeekRank() {
//        查庫獲取最近7天的所有文章
        List<Post> last7DayPosts = this.list(new QueryWrapper<Post>()
                .ge("created", DateUtil.offsetDay(new Date(), -7).toJdkDate())
                .gt("comment_count", 0)
                .select("id, title, user_id, comment_count, view_count, created"));
//        然後把文章的評論數量作爲有序集合的分數,文章id作爲ID存儲到zset中。
        for (Post post : last7DayPosts) {
            String key = "day_rank" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_PATTERN);
//            設置有效期,7天之內有效
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 24 * 60 * 60;

//            緩存文章到set中,評論數量作爲排行標準
            redisUtil.zSet(key, post.getId(), post.getCommentCount());
            //設置有效期
            redisUtil.expire(key, expireTime);
//            緩存文章基本信息(hash結構)
            this.hashCachePostIdAndTitle(post);

        }

//        7天閱讀相加
        this.zUnionAndStroreLast7DaysForWeekRand();

    }


因爲要顯示文章的標題等基本信息

  /**
     * hash結構緩存文章標題和id
     *
     * @param post
     */
    private void hashCachePostIdAndTitle(Post post) {
        boolean isExist = redisUtil.hasKey("rank_post_" + post.getId());
        if (!isExist) {
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 24 * 60 * 60;

//            緩存文章基本信息
            redisUtil.hset("rank_post_" + post.getId(), "post:id", post.getId(), expireTime);
            redisUtil.hset("rank_post_" + post.getId(), "post:title", post.getTitle(), expireTime);
        }
    }

    /**
     * 把最近7天的文章評論數量統計一下
     * 用於首頁的7天評論排行榜
     */
    public void zUnionAndStroreLast7DaysForWeekRand() {
        String prifix = "day_rank";

        List<String> keys = new ArrayList<>();
        String key = prifix + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);

        for (int i = -7; i < 0; i++) {
            Date date = DateUtil.offsetDay(new Date(), i).toJdkDate();
            keys.add(prifix + DateUtil.format(date, DatePattern.PURE_DATE_PATTERN));
        }

        redisUtil.zUnionAndStore(key, keys, "last_week_rank");

    }

我們在項目啓動之時初始化,代碼如下:
在這裏插入圖片描述

增加評論數量

用戶發表評論之後應該要數據庫中的comment_count 加1,也要讓緩存中數量加1,這樣才能保證數據的一致性,在com.fly.controller.PostController#commentAdd 中
在這裏插入圖片描述

    @Override
    public void incrZsetValueAndUnionForLastWeekRank(Long postId) {
        String dayRank = "day_rank" + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
//        文章閱讀加一
        redisUtil.zIncrementScore(dayRank, postId, 1);
        this.hashCachePostIdAndTitle(this.getById(postId));

//      重新union最近7天
        this.zUnionAndStroreLast7DaysForWeekRand();
    }

其實邏輯也和初始化差不多,首先給文章數量加一。集合名稱是對應當天的。比如今天是12月21,對應的key就是day_rank:20181221。在這個上面給對應的文章id加一。這樣每天都有評論這篇文章的話,我們再做交集處理,把每天的評論數量都加起來。得到的就是總的評論數量了。

前端引用的代碼
common/templates.html

<!--本週熱議-->
<div th:fragment="weekPopular">
    <dl class="fly-panel fly-list-one" id="post-hots">
        <dt class="fly-panel-title">本週熱議</dt>
        <script id="hostDd" type="text/html">
            {{#  layui.each(d.list, function(index, item){ }}
            <dd>
                <a href="/post/{{item.id}}">{{item.title}}</a>
                <span><i class="iconfont icon-pinglun1"></i>{{item.comment_count}}</span>
            </dd>
            {{#  }); }}
            {{#  if(d.list.length === 0){ }}
            <div class="fly-none">沒有相關數據</div>
            {{#  } }}
        </script>
    </dl>
    <script>
        layui.use(['laytpl'], function () {
            var laytpl = layui.laytpl;

            var post_hosts = document.getElementById("post-hots");
            var tpl = document.getElementById("hostDd").innerHTML;
            var data = {};
            $.ajax({
                url: "/post/hosts",
                async: false,
                success: function (res) {
                    if (res.code == 0) {
                        data.list = res.data;
                    }
                }
            });
            laytpl(tpl).render(data, function (html) {
                post_hosts.innerHTML += html;

            });

        });

    </script>
</div>

代碼參考:
https://github.com/XWxiaowei/FlyBlog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章