目錄
實現關注與取關
實現共同關注功能
關注推送
Feed流的模式
拉模式
推模式
推拉結合模式
總結
基于推模式實現關注推送功能
Feed流的分頁問題
實現關注推送頁面的分頁查詢
實現
redis的用法。Controller層
@RestController
@RequestMapping("/follow")
public class FollowController {@Resourceprivate IFollowService followService;@PutMapping("/{id}/{isFollow}")public Result follow(@PathVariable("id")Long followUserId,@PathVariable("isFollow") Boolean isFollow){return followService.follow(followUserId,isFollow);}@GetMapping("/or/not/{id}")public Result follow(@PathVariable("id")Long followUserId){return followService.isFollow(followUserId);}
}
?
Service層
@Overridepublic Result follow(Long followUserId, Boolean isFollow) {//1.獲取登錄用戶UserDTO user = UserHolder.getUser();Long userId = user.getId();//判斷是取關還是關注if(isFollow){//2.關注,新增數據Follow follow = new Follow();follow.setUserId(userId);follow.setFollowUserId(followUserId);follow.setCreateTime(LocalDateTime.now());boolean isSuccess = save(follow);}else{//取關,刪除數據//sql: delete from tb_follow where user_id = ? and follow_user_id = ?remove(new QueryWrapper<Follow>().eq("user_id",userId).eq("follow_user_id",followUserId));}return Result.ok();}@Overridepublic Result isFollow(Long followUserId) {//1.獲取用戶UserDTO user = UserHolder.getUser();Long userId = user.getId();//查詢是否關注//sql: select * from tb_follow where user_id = ? and follow_user_idInteger count = query().eq("user_id", userId).eq("follow_user_id", followUserId).count();return Result.ok(count>0);}
redis清理策略?
?
修改前面的關注接口,關注的對象不僅僅存入數據庫中,還需存入redis中(共同關注功能需要set數據結構完成)?
修改
@Overridepublic Result follow(Long followUserId, Boolean isFollow) {//1.獲取登錄用戶UserDTO user = UserHolder.getUser();Long userId = user.getId();String key = "follows:"+userId;//判斷是取關還是關注if(isFollow){//2.關注,新增數據Follow follow = new Follow();follow.setUserId(userId);follow.setFollowUserId(followUserId);follow.setCreateTime(LocalDateTime.now());
//修改部分boolean isSuccess = save(follow);if(isSuccess){//按關注用戶的id放入redis的set集合中stringRedisTemplate.opsForSet().add(key,followUserId.toString());}}else{//取關,刪除數據//sql: delete from tb_follow where user_id = ? and follow_user_id = ?
//修改部分boolean isSuccess = remove(new QueryWrapper<Follow>().eq("user_id", userId).eq("follow_user_id", followUserId));if(isSuccess){stringRedisTemplate.opsForSet().remove(key,followUserId.toString());}}return Result.ok();}
關注再取關對方有顯示嗎?
實現
Controller層
@GetMapping("/common/{id}")public Result followCommons(@PathVariable("id")Long id){return followService.followCommons(id);}
?
怎么關閉快捷功能、Service層
@Overridepublic Result followCommons(Long id) {//1.獲取當前用戶idLong userId = UserHolder.getUser().getId();String key1 = "follows:"+userId;//2.求交集String key2= "follows:"+id;Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key1, key2);if(intersect==null||intersect.isEmpty()){//無共同關注return Result.ok(Collections.emptyList());}//解析id集合List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());//查詢用戶List<UserDTO> users = userService.listByIds(ids).stream().map(user -> BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());return Result.ok(users);}
?
如何關閉借唄功能。?
(msg后面數據為時間戳)如下所示,趙六收件箱一般是空的,只有在趙六在讀消息時才會來拉取他關注目標的發件箱,并按照時間排序
優點:節省內存空間,收件箱讀完以后,就不用了可以清理,所以消息只保存一份在發件人的發件箱中
關注關注、缺點:每次去讀消息時,都要去拉取再做排序,耗時時間長,讀取時間較
彌補拉模式的缺點,每次都會把消息發給每一個粉絲,并排序,等粉絲讀取
把關人,缺點:這種擴散方式,每次更新消息時,都會發給每個粉絲,所以內存占用率很高
普通人采取推模式
大V,活躍粉絲采用推模式,普通的粉絲采用拉模式
redis高級用法?
?
redis基本用法、
?
思考應該用Redis中哪種數據結構進行時間戳的排序?是sortedset還是list?
????????list查詢數據只能按照角標查詢,或者首尾查詢,不支持滾動分頁
redis注解、????????sortedset按照score值排序,得出排名,如果按照排名查詢則跟角標查詢無區別,但是sortedset支持按照score值范圍進行查詢(把時間戳按照從大到小進行排列,每次排序都記住最小的時間戳,然后下次查詢時再找比這個時間戳更小的,這樣就實現了滾動分頁查詢)
小結:如果數據會有變化,盡量使用sortedset實現分頁查詢
采用傳統角標查詢會出現下列問題
?
?
使用滾動分頁,每次存入頁的最后一次角標
?
實現
Controller層
@PostMappingpublic Result saveBlog(@RequestBody Blog blog) {return blogService.saveBlog(blog);}
Service層
@Overridepublic Result saveBlog(Blog blog) {//獲取登錄用戶UserDTO user = UserHolder.getUser();blog.setUserId(user.getId());//2.保存筆記boolean isSuccess = save(blog);if(isSuccess == false){return Result.fail("新增筆記失敗!");}//3.查詢筆記作者所有粉絲//sql: select * from tb_follow where follow_user_id = ?List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();//4.推送筆記id給所有粉絲for (Follow follow : follows) {//4.1獲取粉絲idLong userId = follow.getUserId();//4.2推送sortedSetString key = "feed:" + userId;stringRedisTemplate.opsForZSet().add(key,blog.getId().toString(),System.currentTimeMillis());}//3.返回idreturn Result.ok(blog.getId());}
?
角標查詢 和 通過記錄最后一個的范圍查詢的對比
一開始redis中z1集合存入的數據("m6" : 6,"m5" : 5,"m4" : 4,"m3" : 3,"m2" : 2,"m1" : 1)
實現滾動分頁查詢一定要傳入四個參數:
分數的最大值(max),分數的最小值(min),偏移量(offset),數量(count)(其中分數最小值,數量固定不變)
最大值每次都要找上一次查詢的最小分數(除了第一次)
偏移量(第一次采取0,以后采取1,小于等于與小于的區別)
注意:如果分數一樣會出現以下問題,所以offset應是上一次查詢的最小分數的總個數
?
接口說明
?
Controller層
@GetMapping("/of/follow")public Result queryBlogOfFollow(@RequestParam("lastId") Long max,@RequestParam(value = "offset",defaultValue = "0") Integer offset){return blogService.queryBlogOfFollow(max,offset);}
?
Service層
@Overridepublic Result queryBlogOfFollow(Long max, Integer offset) {//1.獲取當前用戶Long userId = UserHolder.getUser().getId();//2.查詢收件箱//ZREVRANGEBYSCORE key Max Min LIMIT offset countString key = "feed:" + userId;//元組Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet().reverseRangeByScoreWithScores(key, 0, max, offset, 2);//非空判斷if(typedTuples==null||typedTuples.isEmpty()){return Result.ok();}//3.解析數據:blogId、minTime(時間戳)、offsetList<Long> ids = new ArrayList<>(typedTuples.size());long minTime = 0;int os = 1;//偏移量for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {//3.1獲取id(blogId)ids.add(Long.valueOf(typedTuple.getValue()));//3.2獲取分數(時間戳)//執行到最一定是最小時間戳long time = typedTuple.getScore().longValue();if(time == minTime){os++;}else{minTime = time;os = 1;}}//4。根據id查詢blog//不能采用下面方法查詢 in 語句無序//List<Blog> blogs = listByIds(ids);//應使用String idStr = StrUtil.join(",", ids);List<Blog> blogs = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();//5.封裝并返回//需要將blog的信息完善for (Blog blog : blogs) {//查詢blog相關用戶queryBlogUser(blog);//查詢blog是否被點贊isBlogLiked(blog);}ScrollResult scrollResult = new ScrollResult();scrollResult.setList(blogs);scrollResult.setOffset(offset);scrollResult.setMinTime(minTime);return Result.ok(scrollResult);}
?
?
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态