「黑马点评」八、达人探店

23 天前
2

「黑马点评」八、达人探店

探店笔记

数据库建表:

  • tb_blog 探店笔记表,包含标题、文字、图片等
  • tb_blog_comments 对某篇探店笔记的评价

建表 sql

image.png|500

image.png|500

上传图片接口:POST /api/upload/blog

@PostMapping("blog")
public Result uploadImage(@RequestParam("file") MultipartFile image) {
    try {
        // 获取原始文件名称
        String originalFilename = image.getOriginalFilename();
        // 生成新文件名
        String fileName = createNewFileName(originalFilename);
        // 保存文件
        image.transferTo(new File(SystemConstants.IMAGE_UPLOAD_DIR, fileName));
        // 返回结果
        log.debug("文件上传成功,{}", fileName);
        return Result.success(fileName);
    } catch (IOException e) {
        throw new RuntimeException("文件上传失败", e);
    }
}

上传笔记接口:POST /api/blog

@PostMapping
public Result saveBlog(@RequestBody Blog blog) {
    // 获取登录用户
    UserDTO user = UserHolder.getUser();
    blog.setUserId(user.getId());
    // 保存探店博文
    blogService.save(blog);
    // 返回id
    return Result.success(blog.getId());
}

查看探店笔记

实现查看笔记的接口:GET /api/blog/{blogId}

这里有个设计就是 entity 中,使用 TableFiled 为用户信息字段的 exits 置 false,需要设置信息

@GetMapping("/{id}")
public Result<Blog> queryBlogById(@PathVariable("id") Long id) {
    return Result.success(blogService.getById(id));
}

@Override
public Blog getById(Long id) {
    Blog blog = blogMapper.selectById(id);
    return setUserInfo(blog);
}

@GetMapping("/hot")
public Result<List<Blog>> queryHotBlog(@RequestParam(value = "current", defaultValue = "1") Integer current) {
    return Result.success(blogService.queryHotBlog(current, SystemConstants.MAX_PAGE_SIZE));
}

private Blog setUserInfo(Blog blog) {
    Long userId = blog.getUserId();
    User user = userService.getById(userId);
    blog.setName(user.getNickName());
    blog.setIcon(user.getIcon());
    return blog;
}

@Override
public List<Blog> queryHotBlog(int current, int size) {
    // 计算偏移量
    int offset = (current - 1) * size;
    List<Blog> blogs = blogMapper.selectHotBlogs(offset, size);
    blogs.forEach(this::setUserInfo);
    return blogs;
}

点赞

为某篇图文点赞:PUT /api/blog/like/{blogId}

完善功能:

  1. 一帖一人只能点赞一次
  2. 如果点赞过需要标记

实现:

  1. 给 Blog 添加一个 isLike 字段,用于前端展示
  2. 利用 Redis 的 SET 判断是否点赞过,点赞数依次加减
  3. 是否点赞赋值到 isLike 字段

比较粗糙的点赞实现以及根据 Blog id 查询图文及作者及是否点赞

@Override
public Blog getById(Long id) {
    Blog blog = blogMapper.selectById(id);
    setUserInfo(blog);
    setIsLike(blog);
    return blog;
}

@Override
public boolean likeBlog(Long id) {
    Long userId = UserHolder.getUser().getId();
    String key = RedisConstants.BLOG_LIKED_KEY + id;
    Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
    if(Boolean.FALSE.equals(isMember)) {
        // 点赞
        boolean isSuccess = blogMapper.increaseLiked(id) > 0;
        if(isSuccess) {
            stringRedisTemplate.opsForSet().add(key, userId.toString());
        }
    } else {
        // 取消点赞
        boolean isSuccess = blogMapper.decreaseLiked(id) > 0;
        if(isSuccess) {
            stringRedisTemplate.opsForSet().remove(key, userId.toString());
        }
    }
    return !isMember;
}

private void setIsLike(Blog blog) {
    blog.setIsLike(Boolean.TRUE.equals(stringRedisTemplate.opsForSet().isMember(RedisConstants.BLOG_LIKED_KEY + blog.getId(), UserHolder.getUser().getId().toString())));
}

private void setUserInfo(Blog blog) {
    Long userId = blog.getUserId();
    User user = userService.getById(userId);
    blog.setName(user.getNickName());
    blog.setIcon(user.getIcon());
}

点赞排行榜

图文点赞列表中显示最早点赞的 TOP5,形成点赞排行榜

方案选择

根据下图对比,明显 SortedSet 更符合要求,利用时间戳即可实现排行榜

image.png|500

image.png|500

常用命令 ZADD setName score1 member1 score2 member2 ZSCORE setName member ZRANGE setName minRank maxRank

在 java 中利用 Double score 并根据 redis 返回的 score 是否为空判断存不存在

获取当前笔记点赞的 TopN 用户的集合:GET /api/blog/likes/{blogId}

@Override
public List<UserDTO> queryBlogLikes(Long id) {
    String key = RedisConstants.BLOG_LIKED_KEY + id;
    Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4);
    if(top5 == null || top5.isEmpty()) {
        return Collections.emptyList();
    }
    List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList());
    List<UserDTO> userDTOs = userService.listByIds(ids)
        .stream()
        .map(user -> BeanUtil.copyProperties(user, UserDTO.class))
        .collect(Collectors.toList());
    return userDTOs;
}

<select id="findByIds" resultType="com.hmdp.entity.User" parameterType="java.util.List">
    select id, phone, password, nick_name, icon, create_time, update_time
    from tb_user 
    where id in 
    <foreach collection="ids" item="id" separator="," open="(" close=")">
        #{id}
    </foreach>
    order by FIELD(id, 
    <foreach collection="ids" item="id" separator=",">
        #{id}
    </foreach>
    )
</select>

使用社交账号登录

  • Loading...
  • Loading...
  • Loading...
  • Loading...
  • Loading...