Redis筆記點贊排行榜的實現示例
一、發佈探店筆記
探店筆記類似點評網站的評價,往往是圖文結合。對應的表有兩個
- 探店筆記表(主鍵、商戶id、用戶id、標題、文字、圖片、探店文字描述、點贊數量、評論數量)
- 評價表(筆記的評價)
先上傳圖片請求一次保存圖片接口,再點發佈請求發佈接口。這兩個接口已經寫好
二、實現查看筆記接口
BlogController
@RestController @RequestMapping("/blog") public class BlogController { @Resource private IBlogService blogService; @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); } }
IBlogService
public interface IBlogService extends IService<Blog> { Result queryBlogById(String id); Result queryHotBlog(Integer current); }
BlogServiceImpl
@Service public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService { @Autowired private IUserService userService; @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(this::queryBlogUser); return Result.ok(records); } 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); return Result.ok(blog); } }
三、點贊功能
現在已經寫好的點贊接口
問題:這樣寫接口,可以一直按點贊重復點贊
需求
- 同一個用戶隻能點贊一次,再次點贊則取消點贊
- 如果當前用戶已經點贊,則點贊按鈕高亮顯(前端已經實現,判斷blog類的isLike屬性)
實現步驟
- 給Blog類中添加一個isLike字段,表示是否被當前用戶點贊
- 修改點贊功能,利用redis的set集合判斷用戶是否贊過,未贊則點贊數+1,贊過則-1
- 修改根據id查詢blog的業務,判斷當前用戶是否點贊過,賦值給isLike字段
- 修改分頁查詢blog業務,判斷當前用戶是否贊過,賦值isLike字段
業務實現
@RestController @RequestMapping("/blog") public class BlogController { @Resource private IBlogService blogService; @PutMapping("/like/{id}") public Result likeBlog(@PathVariable("id") Long id) { return blogService.likeBlog(id); } @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 public class BlogServiceImpl extends ServiceImpl<BlogMapper, Blog> implements IBlogService { @Autowired private IUserService userService; @Autowired private StringRedisTemplate stringRedisTemplate; @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); } @Override public Result likeBlog(Long id) { // 1、獲取登錄用戶 UserDTO user = UserHolder.getUser(); // 2、判斷當前登錄用戶是否已經點贊 Boolean isMember = stringRedisTemplate.opsForSet().isMember(RedisConstants.BLOG_LIKED_KEY + id, user.getId().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(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString()); } } else { // 4、如果已點贊,取消點贊 // 4.1、數據庫點贊數 -1 boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update(); // 4.2、把用戶從 Redis 的 set 集合移除 if(isSuccess){ stringRedisTemplate.opsForSet().remove(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString()); } } return Result.ok(); } 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)); } }
四、點贊排行榜
查出給這個筆記點贊的人,類似微信朋友圈的點贊,可以展示誰點贊瞭,而且我們要進行排序
所以我們得用SortedSet這種數據類型
1、修改點贊邏輯
把原本存入set改為存入zset多加個分數,分數就是時間戳
@Override public Result likeBlog(Long id) { // 1、獲取登錄用戶 UserDTO user = UserHolder.getUser(); // 2、判斷當前登錄用戶是否已經點贊 Double score = stringRedisTemplate.opsForZSet().score(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString()); if(score == null) { // 3、如果未點贊,可以點贊 // 3.1、數據庫點贊數 +1 boolean isSuccess = update().setSql("liked = liked+1").eq("id", id).update(); // 3.2、保存用戶到 Redis 的 set 集合 if(isSuccess){ // 時間作為 key 的 score stringRedisTemplate.opsForZSet().add(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString(), System.currentTimeMillis()); } } else { // 4、如果已點贊,取消點贊 // 4.1、數據庫點贊數 -1 boolean isSuccess = update().setSql("liked = liked - 1").eq("id", id).update(); // 4.2、把用戶從 Redis 的 set 集合移除 if(isSuccess){ stringRedisTemplate.opsForZSet().remove(RedisConstants.BLOG_LIKED_KEY + id, user.getId().toString()); } } return Result.ok(); }
然後是否被點贊的方法也要修改,根據key取出分數,分數不為null就是點贊過瞭
private void isBlogLiked(Blog blog) { UserDTO user = UserHolder.getUser(); if(user == null){ return; } Long userId = user.getId(); String key = RedisConstants.BLOG_LIKED_KEY + blog.getId(); Double score = stringRedisTemplate.opsForZSet().score(key, userId.toString()); blog.setIsLike(score != null); }
2、點贊排行榜功能
需求:實現前五個點贊的用戶返回
我們先用動態id去redis中查詢出前五個點贊用戶的id
然後根據id去數據庫中查詢信息封裝到dto再返回
@GetMapping("/likes/{id}") public Result queryBlogLikes(@PathVariable("id") String id) { return blogService.queryBlogLikes(id); }
@Override public Result queryBlogLikes(String id) { String key = RedisConstants.BLOG_LIKED_KEY + id; // 查詢 top5 的點贊用戶 Set<String> top5 = stringRedisTemplate.opsForZSet().range(key, 0, 4); if(top5 == null){ return Result.ok(Collections.emptyList()); } // 解析出其中的用戶id List<Long> ids = top5.stream().map(Long::valueOf).collect(Collectors.toList()); String join = StrUtil.join(",", ids); // 根據用戶id查詢用戶 List<UserDTO> userDTOS = userService.query().in("id", ids).last("order by filed(id, "+join+")").list() .stream() .map(user -> BeanUtil.copyProperties(user, UserDTO.class)) .collect(Collectors.toList()); return Result.ok(userDTOS); }
註意:如果我們mp直接用in來查詢根本不能保證點贊的順序,因為in查詢出來的是按照id順序返回的,沒有排序,我們要按照查詢id的順序來查,order by field(id,5,1)這樣
到此這篇關於Redis筆記點贊排行榜的實現示例的文章就介紹到這瞭,更多相關Redis筆記點贊內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Redis實現好友關註的示例代碼
- 微服務 Spring Boot 整合 Redis BitMap 實現 簽到與統計功能
- Redis實現附近商鋪的項目實戰
- SpringBoot使用Redis的zset統計在線用戶信息
- Redis解決優惠券秒殺應用案例