Skip to content
DAILY QUOTE

“ ”

  • 点赞实现流程

原始代码存在的问题:一个用户可以无限点赞。这显然是不合理的,所以我们需要对点赞功能进行一个优化,实现一人只能点赞一次。

java
/**
 * 点赞或取消点赞博客。
 *
 * @param id业务id
 * @return处理结果
 */
@PutMapping("/like/{id}")
public Result likeBlog(@PathVariable("id") Long id) {
    blogService.update()
            .setSql("liked=liked+1").eq("id", id).update();
    return Result.ok();
}

需求:

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

实现步骤:

  • 给Blog类中添加一个isLike字段,标示是否被当前用户点赞

  • 修改点赞功能,利用Redis的set集合判断是否点赞过,未点赞过则点赞数+1,已点赞过则点赞数-1

  • 修改根据id查询Blog的业务,判断当前登录用户是否点赞过,赋值给isLike字段

  • 修改分页查询Blog业务,判断当前登录用户是否点赞过,赋值给isLike字段

  • 代码实现:使用Redis的Set集合存储已点赞用户id,保证点赞唯一性

java
@Service
public class BlogServiceImpl  extends ServiceImpl<BlogMapper, Blog> implements IBlogService {

    @Resource
    private IUserService userService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 分页查询热门探店笔记。
     *
     * 作用:
     * 1.根据点赞查询博客;
     * 2.获取当前页数据;
     * 3.设置每一个热点笔记的用户,以及是否被点赞;
     *
     * @param current当前页码
     * @return处理结果
     */
    @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查询探店笔记详情。
     *
     * 作用:
     * 1.查询blog;
     * 2.查询blog有关用户;
     *
     * @param id业务id
     * @return处理结果
     */
    @Override
    public Result queryBlogById(Long id) {
        //1.查询blog
        Blog blog = getById(id);
        if (blog == null) {
            return Result.fail("笔记不存在");
        }
        //2.查询blog有关用户
        queryBlogUser(blog);
        // # 3.查询blog是否被点赞
        isBlogLiked(blog);
        return Result.ok(blog);
    }

    /**
     * 判断当前登录用户是否点赞了这篇博客。
     *
     * 作用:
     * 1.获取当前用户;
     * 2.判断当前登录用户是否已点赞;
     *
     * @param blog当前博客对象
     * @return无返回值
     */
    private void isBlogLiked(Blog blog) {
        //1.获取当前用户
        Long userId = UserHolder.getUser().getId();
        //2.判断当前登录用户是否已点赞
        String key = "blog:liked:" + blog.getId();
        Boolean isLiked = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        blog.setIsLike(BooleanUtil.isTrue(isLiked));
    }

    /**
     * 点赞或取消点赞博客。
     *
     * 作用:
     * 1.获取当前用户;
     * 2.判断当前登录用户是否已点赞;
     * 3.如果未点赞,可以点赞;
     * 4.数据库点赞数+1;
     * 5.保存用户id到Redis的Set集合;
     *
     * @param id业务id
     * @return处理结果
     */
    @Override
    public Result likeBlog(@PathVariable("id") Long id) {
        //1.获取当前用户
        Long userId= UserHolder.getUser().getId();
        //2.判断当前登录用户是否已点赞
        String key="blog:liked:"+id;
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());

        if(BooleanUtil.isFalse(isMember)) {
            //3.如果未点赞,可以点赞
            //3.1.数据库点赞数+1
            boolean isSuccess = update().setSql("liked=liked+1").eq("id",id).update();
            //3.2.保存用户到Redis的Set集合
            if (isSuccess) {
                stringRedisTemplate.opsForSet().add(key, userId.toString());
            }
        } else {
                //4.如果已点赞,取消点赞
                //4.1.数据库点赞数-1
                boolean isSuccess=update().setSql("liked=liked-1").eq("id",id).update();
                if(isSuccess){
                    stringRedisTemplate.opsForSet().remove(key, userId.toString());
                }
            }
            return Result.ok();
        }
}
  • 测试功能 登陆后,点击笔记右下角点赞功能,点赞数+1,已点赞高亮显示。

同一个用户再次点赞同一篇笔记后,点赞数-1,高亮取消,Redis的Set集合中移除该用户id,防止了用户重复点赞。