1:首先先看以前写的代码。

    @PutMapping("/like/{id}")
    public Result likeBlog(@PathVariable("id") Long id) {
        // 修改点赞数量
        blogService.update()
                .setSql("liked = liked + 1").eq("id", id).update();
        return Result.ok();
    }

分析一下问题:

(1):这样的修改直接修改的就是数据库,会给数据库带来极大的压力(修改一次相当于与调用两次接口,也就是操作了两次数据库,一次修改一次查询。

(2):可以一直进行点赞,也就是达到了刷赞的效果,没有取消点赞的操作。

改进思路

(1):需要有取消点赞的效果,也就是一个item一个用户最多点赞一次。

(2):数据库修改,查询时利用redis进行查询。这样就需要在redis中进行存储item对应的点赞用户,并且需要不可重复(确保用户id唯一),所以采用set集合。

2:进行代码改进。

1:需求分析。

  • 同一个用户只能点赞一次,再次点击则取消点赞
  • 如果当前用户已经点赞,则点赞按钮高亮显示(前端已实现,判断字段 Blog 类的 isLike 属性)

2:实现步骤:

① 给 Blog 类中添加一个 isLike 字段,标识是否被当前用户点赞
② 修改点赞功能,利用 Redis 的 set 集合判断是否点赞过,未点赞过则点赞数 +1,已点赞过则点赞数 -1.
需要一个集合去记录所有点赞过的用户,同时一个用户只能点赞一次,要求用户 id 不能重复,即集合中元素唯一,而 Redis 中 set 集合满足这种需求。
③ 修改根据 id 查询 Blog 的业务,判断当前登录用户是否点赞过,赋值给 isLike 字段
④ 修改分页查询 Blog 业务,判断当前登录用户是否点赞过,赋值给 isLike 字段 

3:点赞业务实现。

controller层。

    @PutMapping("/like/{id}")
    public Result likeBlog(@PathVariable("id") Long id) {

        return blogService.likeBlog(id);
    }

service层。 

  @Autowired
    private IUserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    //点赞业务。
    @Override
    public Result likeBlog(Long id) {
        // 1、获取登录用户
        UserDTO user = UserHolder.getUser();
        // 2、判断当前登录用户是否已经点赞(redis)
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(RedisConstants.BLOG_LIKED_KEY + id, user.getId());
        // 3、如果未点赞,可以点赞
        if (BooleanUtil.isFalse(isMember)) {
            // 3.1、数据库点赞数 +1
            boolean isSuccess = update().setSql("liked = liked + 1").eq("id", user.getId().toString()).update();
            if (isSuccess) {
                // 3.2、保存用户到 Redis 的 set 集合
                stringRedisTemplate.opsForSet().add(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
            }
            // 4、如果已点赞,取消点赞
        } else {
            // 4.1、数据库点赞数 -1
            boolean isSuccess = update().setSql("liked = liked - 1").eq("id", user.getId().toString()).update();
            if (isSuccess) {
                // 4.2、把用户从 Redis 的 set 集合移除
                stringRedisTemplate.opsForSet().remove(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString());
            }
        }
        return Result.ok();
    }

 4:查询业务实现。

controller

 //首页分页热门  
 @GetMapping("/hot")
    public Result queryHotBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {
        return blogService.queryHotBlog(current);
    }
//具体博客。
    @GetMapping("/{id}")
    public Result queryBlogById(@PathVariable("id") String id) {
        return blogService.queryBlogById(id);
    }

service

  //首页展示。
    @Override
    public Result queryHotBlog(Integer current) {
        // 根据用户查询
        Page<Blog> page = query()
                .orderByDesc("liked")
                .page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
        // 获取当前页数据
        List<Blog> records = page.getRecords();
        // 查询用户
        records.forEach(blog -> {
            this.queryBlogUser(blog);
            this.isBlogLiked(blog);
        });
        return Result.ok(records);
    }

    //具体id展示。
    private void queryBlogUser(Blog blog) {
        Long userId = blog.getUserId();
        User user = userService.getById(userId);
        blog.setName(user.getNickName());
        blog.setIcon(user.getIcon());
    }

    @Override
    public Result queryBlogById(String id) {
        Blog blog = getById(id);

        if (blog == null) {
            return Result.fail("笔记不存在!");
        }

        queryBlogUser(blog);
        // 查询 Blog 是否被点赞
        isBlogLiked(blog);

        return Result.ok(blog);
    }

    private void isBlogLiked(Blog blog) {
        Long userId = blog.getUserId();
        String key = RedisConstants.BLOG_LIKED_KEY + blog.getId();
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        blog.setIsLike(BooleanUtil.isTrue(isMember));
    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐