Redis实践之点赞排行榜
1.项目背景
探店笔记类似点评网站的评价,往往是图文结合。对应的表有两个:
- tb_blog:探店笔记表,包含笔记中的标题、文字、图片等
- tb_blog_comments:其他用户对探店笔记的评价
涉及的相关接口包括上传图片接口、发布笔记接口、查看笔记详情接口:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| 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.ok(fileName); } catch (IOException e) { throw new RuntimeException("文件上传失败", e); } }
private String createNewFileName(String originalFilename) { String suffix = StrUtil.subAfter(originalFilename, ".", true); String name = UUID.randomUUID().toString(); int hash = name.hashCode(); int d1 = hash & 0xF; int d2 = (hash >> 4) & 0xF; File dir = new File(SystemConstants.IMAGE_UPLOAD_DIR, StrUtil.format("/blogs/{}/{}", d1, d2)); if (!dir.exists()) { dir.mkdirs(); } return StrUtil.format("/blogs/{}/{}/{}.{}", d1, d2, name, suffix); }
public Result saveBlog(@RequestBody Blog blog) { UserDTO user = UserHolder.getUser(); blog.setUserId(user.getId()); blogService.save(blog); return Result.ok(blog.getId()); }
public Result queryBlogById(Long id) { Blog blog = getById(id); if (blog == null) { return Result.fail("笔记不存在!"); } Long userId = blog.getUserId(); User user = userService.getById(userId); blog.setName(user.getNickName()); blog.setIcon(user.getIcon()); blog.setIsLike(isMember(blog, userId)); return Result.ok(blog); }
private Boolean isMember(Blog blog, Long userId) { String key = "blog:liked:" + blog.getId(); return stringRedisTemplate.opsForZSet().score(key, userId.toString()) != null; }
|
前端需要知道当前用户是否已点赞过某篇笔记,以便高亮显示,同时需要保证一人一赞功能,重复点赞等同于取消点赞,这些依赖于Redis中的sorted set数据结构实现(保存某篇笔记的点赞用户列表,按照点赞时间戳排序)。
2.点赞功能
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public Result likeBlog(Long id) { String key = "blog:liked:" + id; Long userId = UserHolder.getUser().getId(); Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString()); if (score == null) { boolean updated = update().setSql("liked = liked + 1").eq("id", id).update(); if (updated) { stringRedisTemplate.opsForZSet().add(key, userId.toString(), System.currentTimeMillis()); } } else { boolean updated = update().setSql("liked = liked - 1").eq("id", id).update(); if (updated) { stringRedisTemplate.opsForZSet().remove(key, userId.toString()); } } return Result.ok(); }
|
3.点赞排行榜
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public Result queryBlogLikes(Long id) { String key = "blog:liked:" + id; Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4); if (top5 == null || top5.isEmpty()) { return Result.ok(Collections.emptyList()); } List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList()); String idStr = StrUtil.join(",", ids); List<UserDTO> userDTOS = userService.query() .in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list() .stream() .map(user -> BeanUtil.copyProperties(user, UserDTO.class)) .collect(Collectors.toList()); return Result.ok(userDTOS); }
|