Public account: MarkerHub (pay attention to get more project resources)

Eblog codebase: github.com/markerhub/e…

Eblog project video: www.bilibili.com/video/BV1ri…


Development Document Catalog:

(Eblog) 1. Set up the project architecture and initialized the home page

(EBLOG) 2. Integrate Redis and project elegant exception handling and return result encapsulation

(eblog) 3, using Redis zset ordered set to achieve a hot feature of the week

(EBLOG) 4, customize Freemaker label to achieve blog homepage data filling

(Eblog) 5, blog classification filling, login registration logic

(EBLOG) 6. Set up blog publishing collection and user center

(eblog) 7, message asynchronous notification, details adjustment

8. Blog search engine development and background selection

(Eblog) 9. Instant group chat development, chat history, etc


Front and back end separation project vueblog please click here: super detailed! 4 hours to develop a SpringBoot+ Vue front and back separated blog project!!


Hot this week

The most talked about articles of the week, and the most commented articles of the week, can be achieved quickly by querying the database directly, just limit the time when the article was created, and then retrace the number of comments to the previous articles.

But here we use Redis to do it. As we said earlier in class, we can use zset, an ordered set of Redis, to complete the leaderboard function. Now let’s use this data structure to accomplish the functionality discussed this week.

Before coding, we need to review a few basic commands for zset.

  • zrange key start stop [WITHSCORES]

Withscores indicates whether to display the index of the position where the ordinals start and stop represent. Start and stop limit the scope of the traversal

  • zincrby key increment member

Add increment to score value of member of ordered set key.

  • ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]

Computes the union of a given one or more ordered sets, where the number of given keys must be specified as numkeys, and stores the union (result set) to Destination.

By default, the score value of a member in a result set is the sum of the score values of that member in a given set.

Other commands are available here: doc.redisfans.com/

Here’s what I did:

Let’s analyze our requirements. We want to use caching for this week’s hot leaderboards feature, independent of the database (except for initialization data). After someone posts a comment, add one directly using the command and recalculate the union to get the leaderboard.

When the project starts, we initialize the number of comments on recent articles. The basic logic is as follows:

  1. Search for all posts in the last 7 days (or add a condition that the number of comments is greater than 0)

  2. The number of comments on the article is then stored in zset as the score of the ordered set and the article ID as the ID.

  3. Hot topics of the week have titles and comment counts, so we also need to store the basic information of the article in redis General. After obtaining the id of the article, we can retrieve the title and other information from the cache. Here we can use the hash structure to store the information of the article.

  4. In addition, since it is hot this week, articles are useless after 7 days, so we can give the ordered collection of articles a valid time. After 7 days, the cache is automatically deleted.

The specific code is as follows:

  • com.example.service.impl.PostServiceImpl#initIndexWeekRank
/** * Override public void Override public void OverrideinitIndexWeekRankList<Post> last7DayPosts = this.list(new QueryWrapper<Post>().ge())"created", DateUtil.offsetDay(new Date(), -7).toJdkDate())
            .select("id, title, user_id, comment_count, view_count, created"));
    for (Post post : last7DayPosts) {
        String key = "day_rank:"+ DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_PATTERN); Long between = dateutil. between(new Date(), post.getCreated(), dateUnit.day); long expireTime = (7 - between) * 24 * 60 * 60; // Cache the article tosetRedisutil.zset (key, post.getid (), post.getCommentCount()); Redisutil. expire(key, expireTime); // Cache basic article information (hashStructure) enclosing hashCachePostIdAndTitle (post); } //7 days of reading add up. this.zUnionAndStoreLast7DaysForLastWeekRank(); }Copy the code
  • The corresponding method of caching article information is as follows:
/ * * *hashStructure caches the article title and ID * @param post */ private voidhashCachePostIdAndTitle(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; // Cache basic article information (hashStructure) redisUtil. Hset ("rank_post_" + post.getId(), "post:id", post.getId(), expireTime);
        redisUtil.hset("rank_post_" + post.getId(), "post:title", post.getTitle(), expireTime);
        //redisUtil.hset("rank_post_" + post.getId(), "post:comment_count", post.getCommentCount(), expireTime); }}Copy the code
  • Count the number of article set intersection of 7 days:
/** * count the number of comments in the last 7 days */ public voidzUnionAndStoreLast7DaysForLastWeekRank() {
    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");
}

Copy the code

Once it’s done, we call it in our project startup class to complete the initialization.

@Slf4j
@Order(1000)
@Component
public class ContextStartup implements ApplicationRunner, ServletContextAware {
    private ServletContext servletContext;
    @Autowired
    PostService postService;
    @Override
    public void setServletContext(ServletContext servletContext) {
        this.servletContext = servletContext;
    }
    @Override
    public void run(ApplicationArguments args) throws Exception {
        servletContext.setAttribute("base", servletContext.getContextPath()); / / initializes the week of the first page of comments list postService. InitIndexWeekRank (); }}Copy the code

That completes the initialization. At this point we can see the effects of this week’s hot topic module. We already have the data we want in the cache, and then we fetch it in the Controller and return it to our page. The page uses asynchronous loading mode, so here we define an asynchronous interface:

  • com.example.controller.PostController
@ResponseBody
@GetMapping("/post/hots")
public Result hotPost() {
    Set<ZSetOperations.TypedTuple> lastWeekRank = redisUtil.getZSetRank("last_week_rank", 0, 6);
    List<Map<String, Object>> hotPosts = new ArrayList<>();
    for (ZSetOperations.TypedTuple typedTuple : lastWeekRank) {
        Map<String, Object> map = new HashMap<>();
        map.put("comment_count", typedTuple.getScore());
        map.put("id", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:id"));
        map.put("title", redisUtil.hget("rank_post_" + typedTuple.getValue(), "post:title"));
        hotPosts.add(map);
    }
    return Result.succ(hotPosts);

Copy the code

}

Test results:

To this, we have completed to obtain data of this week, however, it’s just an initialization, when critics should also add data to our cache, and the content of the page we should write some ajax loading data, these we keep, first come here, about the content of the above is our previous course, everybody first digest.

(after)

MarkerHub Article Index:

Github.com/MarkerHub/J…