欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Redis 實現(xiàn)好友關注和關注推送的示例代碼

 更新時間:2025年03月11日 10:20:56   作者:快樂的小三菊  
本文介紹了使用Redis實現(xiàn)好友關注和關注推送功能,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、關注和取關

1.1 簡介

在探店圖文的詳情頁面中,可以關注發(fā)布筆記的作者:

1.2 需求描述

實現(xiàn)兩個接口:關注和取關接口、判斷是否關注的接口

1.3 代碼實現(xiàn)

涉及到的 controller 層代碼如下:

@RestController
@RequestMapping("/follow")
public class FollowController {

    @Resource
    private 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 isFollow(@PathVariable("id") Long followUserId) {
        return followService.isFollow(followUserId);
    }
}

涉及到的 service 層代碼如下:

@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IUserService userService;

    @Override
    public Result follow(Long followUserId, Boolean isFollow) {
        // 1.獲取登錄用戶
        Long userId = UserHolder.getUser().getId();
        String key = "follows:" + userId;
        // 1.判斷到底是關注還是取關
        if (isFollow) {
            // 2.關注,新增數(shù)據(jù)
            Follow follow = new Follow();
            follow.setUserId(userId);
            follow.setFollowUserId(followUserId);
            boolean isSuccess = save(follow);
            if (isSuccess) {
                // 把關注用戶的id,放入redis的set集合 sadd userId followerUserId
                stringRedisTemplate.opsForSet().add(key, followUserId.toString());
            }
        } else {
            // 3.取關,刪除 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) {
                // 把關注用戶的id從Redis集合中移除
                stringRedisTemplate.opsForSet().remove(key, followUserId.toString());
            }
        }
        return Result.ok();
    }

    @Override
    public Result isFollow(Long followUserId) {
        // 1.獲取登錄用戶
        Long userId = UserHolder.getUser().getId();
        // 2.查詢是否關注 select count(*) from tb_follow where user_id = ? and follow_user_id = ?
        Integer count = query().eq("user_id", userId).eq("follow_user_id", followUserId).count();
        // 3.判斷
        return Result.ok(count > 0);
    }
}

二、共同關注

2.1 簡介

點擊博主頭像,可以進入博主首頁:

2.2 需求描述

利用 Redis 中恰當?shù)臄?shù)據(jù)結構,實現(xiàn)共同關注功能。在博主個人頁面展示出當前用戶與博主的共同好友。

2.3 代碼實現(xiàn)

涉及到的 controller 層代碼如下:

@RestController
@RequestMapping("/follow")
public class FollowController {

    @Resource
    private IFollowService followService;

    @GetMapping("/common/{id}")
    public Result followCommons(@PathVariable("id") Long id){
        return followService.followCommons(id);
    }
}

涉及到的 service 層代碼如下:

@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IUserService userService;

    @Override
    public Result followCommons(Long id) {
        // 1.獲取當前用戶
        Long userId = UserHolder.getUser().getId();
        String key = "follows:" + userId;
        // 2.求交集
        String key2 = "follows:" + id;
        Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key, key2);
        if (intersect == null || intersect.isEmpty()) {
            // 無交集
            return Result.ok(Collections.emptyList());
        }
        // 3.解析id集合
        List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());
        // 4.查詢用戶
        List<UserDTO> users = userService.listByIds(ids)
                .stream()
                .map(user -> BeanUtil.copyProperties(user, UserDTO.class))
                .collect(Collectors.toList());
        return Result.ok(users);
    }
}

三、關注推送

3.1 簡介

關注推送也叫做 Feed 流,直譯為投喂。為用戶持續(xù)的提供 “沉浸式” 的體驗,通過無限下拉刷新獲取新的信息。

3.2 Feed 流的模式

3.2.1 TimeLine

不做內容篩選,簡單的按照內容發(fā)布時間排序,常用于好友或關注。例如朋友圈。

優(yōu)點:信息全面,不會有缺失。并且實現(xiàn)也相對簡單

缺點:信息噪音較多,用戶不一定感興趣,內容獲取效率低

3.2.2 智能排序

利用智能算法屏蔽掉違規(guī)的、用戶不感興趣的內容。推送用戶感興趣信息來吸引用戶。

優(yōu)點:投喂用戶感興趣信息,用戶粘度很高,容易沉迷

缺點:如果算法不精準,可能起到反作用

3.3 實現(xiàn)方案

本例中的個人頁面,是基于關注的好友來做 Feed 流,因此采用 Timeline 的模式。該模式的實現(xiàn)方案有三種:拉模式、推模式、推拉結合模式。

3.3.1 拉模式

拉模式也叫做讀擴散,假設現(xiàn)在有三個 up 主,張三李四和王五,它們三個人將來會發(fā)一些消息,此時,給他們每個人都準備一個發(fā)件箱,將來它們發(fā)送消息的時候就會發(fā)送到發(fā)件箱里面去,發(fā)送的消息除了本身以外還需要攜帶一個時間戳,因為后面要按照時間排序。

此時有一個粉絲趙六,它有一個收件箱,平常是空的,只有他要去讀消息的時候我們才會給他去拉取,即從它所關注的 up 主的發(fā)件箱去拉取消息,拉過來之后按照時間去排序,這樣就可以去讀取了。

這種模式的優(yōu)點是節(jié)省內存空間,因為收件箱讀取完畢之后就可以清空,下次再重新拉取。缺點是每次讀消息的時候都要重新去拉取發(fā)件箱的消息,然后再做排序,這一系列的動作耗時會比較久,讀取的延遲較高。 

3.3.2 推模式

推模式也叫寫擴散。假設此時有兩個 up 主,張三和李四,粉絲1關注了張三、粉絲2關注了張三和李四、粉絲3也關注了張三和李四,假設此時張三要發(fā)送消息,它所發(fā)送的消息會直接推送到所有粉絲的收件箱里面去,然后對收件箱里面的消息進行排序,此時粉絲可以直接從收件箱里面讀取消息

此種模式的優(yōu)點是延遲非常的低,彌補了拉模式的缺點。缺點是由于沒有了發(fā)件箱,不得不把消息發(fā)送給每一個粉絲,內存占用會很高,即一個消息要寫N份 

3.3.3 推拉結合模式

推拉結合模式也叫做讀寫混合,兼具推和拉兩種模式的優(yōu)點。假設現(xiàn)在有一個大 V 和普通人張三,還有兩個普通粉絲和一個活躍粉絲,每個粉絲都有自己的收件箱。假設此時普通人張三要發(fā)送消息,他的粉絲很少,就可以采用推模式,即直接將消息推送到每一個粉絲的收件箱里面。

而大 V 則不一樣,大 的粉絲很多,雖然粉絲多,但是粉絲存在差異,有活躍粉絲和一般粉絲。針對于活躍粉絲采用推模式,而針對于一般粉絲采取拉模式,因為大 V 需要有一個發(fā)件箱。

這種推拉結合的模式,既節(jié)省了內存又照顧了活躍用戶的感受

3.3.4 總結

3.4 Feed 流的分頁問題

Feed 流中的數(shù)據(jù)會不斷更新,所以數(shù)據(jù)的角標也在變化,因此不能采用傳統(tǒng)的分頁模式。接下來我們分析下原因。

以下圖為例,橫線代表時間軸,此時時間來到了 t1 時刻,收件箱里面已經有了 10 條消息了,數(shù)字越大代表越新,讀取第一頁數(shù)據(jù)沒啥問題。

此時來到了 t2 時刻,有人插入了一條新的數(shù)據(jù),此時我們的 11 數(shù)據(jù)就跑到了最前面去了

等到來到了 t3 時刻,此時需要讀取第二頁的內容,此時就會出現(xiàn)重復讀取的問題,分頁就出現(xiàn)了混亂。

這就是 Feed 流不能采用傳統(tǒng)的分頁模式的原因。

3.5 Feed 流的滾動分頁

此時就需要采用 Feed 流的滾動分頁,即記錄每次分頁的最后一條,下次再從這個位置開始查。第一次讀取時 lastId 設置成無窮大就可以了,如下圖:

到了 t2 時刻有人插入了新的數(shù)據(jù) 11,如下圖:

等到 t3 時刻,讀取第二頁的時候,讓 lastId = 6,向后查 條就不會出現(xiàn)問題了,如下圖:

此時的查詢是不依賴于腳標的,所以數(shù)據(jù)不受影響。所以只能使用 zset 結構。

3.6 需求描述

基于推模式實現(xiàn)關注推送功能:

1、修改新增探店筆記的業(yè)務,在保存 blog 到數(shù)據(jù)庫的同時,推送到粉絲的收件箱

2、收件箱滿足可以根據(jù)時間戳排序,必須用 Redis 的數(shù)據(jù)結構實現(xiàn)

3、查詢收件箱數(shù)據(jù)時,可以實現(xiàn)分頁查詢

3.7 代碼實現(xiàn)

首先完成修改新增探店筆記的業(yè)務,在保存 blog 到數(shù)據(jù)庫的同時,推送到粉絲的收件箱功能,涉及到的 controller 層代碼如下:

@RestController
@RequestMapping("/blog")
public class BlogController {

    @Resource
    private IBlogService blogService;

    @PostMapping
    public Result saveBlog(@RequestBody Blog blog) {
        return blogService.saveBlog(blog);
    }
}

涉及到的 service 層代碼如下:

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

    @Resource
    private IUserService userService;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    IFollowService followService;

    @Override
    public Result saveBlog(Blog blog) {
        // 1.獲取登錄用戶
        UserDTO user = UserHolder.getUser();
        blog.setUserId(user.getId());
        // 2.保存探店筆記
        boolean isSuccess = save(blog);
        if(!isSuccess){
            return Result.fail("新增筆記失敗!");
        }
        // 3.查詢筆記作者的所有粉絲 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.獲取粉絲id
            Long userId = follow.getUserId();
            // 4.2.推送
            String key = "feed:" + userId;
            stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());
        }
        // 5.返回id
        return Result.ok(blog.getId());
    }
	
}

接下來完成剩下的兩小點需求,界面請求的參數(shù)如下:

涉及到的 controller 層代碼如下:

@RestController
@RequestMapping("/blog")
public class BlogController {

    @Resource
    private IBlogService blogService;

    @PostMapping
    public Result saveBlog(@RequestBody Blog blog) {
        return blogService.saveBlog(blog);
    }

    @GetMapping("/of/follow")
    public Result queryBlogOfFollow(
            @RequestParam("lastId") Long max, @RequestParam(value = "offset", defaultValue = "0") Integer offset){
        return blogService.queryBlogOfFollow(max, offset);
    }
}

涉及到的 service 層代碼如下:

    @Override
    public Result queryBlogOfFollow(Long max, Integer offset) {
        // 1.獲取當前用戶
        Long userId = UserHolder.getUser().getId();
        // 2.查詢收件箱 ZREVRANGEBYSCORE key Max Min LIMIT offset count
        String key = FEED_KEY + userId;
        Set<ZSetOperations.TypedTuple<String>> typedTuples = stringRedisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(key, 0, max, offset, 2);
        // 3.非空判斷
        if (typedTuples == null || typedTuples.isEmpty()) {
            return Result.ok();
        }
        // 4.解析數(shù)據(jù):blogId、minTime(時間戳)、offset
        List<Long> ids = new ArrayList<>(typedTuples.size());
        long minTime = 0; // 2
        int os = 1; // 2
        for (ZSetOperations.TypedTuple<String> tuple : typedTuples) { // 5 4 4 2 2
            // 4.1.獲取id
            ids.add(Long.valueOf(tuple.getValue()));
            // 4.2.獲取分數(shù)(時間戳)
            long time = tuple.getScore().longValue();
            if(time == minTime){
                os++;
            }else{
                minTime = time;
                os = 1;
            }
        }
        // 5.根據(jù)id查詢blog
        String idStr = StrUtil.join(",", ids);
        List<Blog> blogs = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();

        for (Blog blog : blogs) {
            // 5.1.查詢blog有關的用戶
            queryBlogUser(blog);
            // 5.2.查詢blog是否被點贊
            isBlogLiked(blog);
        }

        // 6.封裝并返回
        ScrollResult r = new ScrollResult();
        r.setList(blogs);
        r.setOffset(os);
        r.setMinTime(minTime);

        return Result.ok(r);
    }

封裝返回給前端的實體類如下:

@Data
public class ScrollResult {
    private List<?> list;
    private Long minTime;
    private Integer offset;
}

到此這篇關于 Redis 實現(xiàn)好友關注和關注推送的示例代碼的文章就介紹到這了,更多相關 Redis 好友關注和關注推送內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家! 

相關文章

  • Govern Service 基于 Redis 的服務治理平臺安裝過程詳解

    Govern Service 基于 Redis 的服務治理平臺安裝過程詳解

    Govern Service 是一個輕量級、低成本的服務注冊、服務發(fā)現(xiàn)、 配置服務 SDK,通過使用現(xiàn)有基礎設施中的 Redis 不用給運維部署帶來額外的成本與負擔,接下來通過本文給大家分享Govern Service 基于 Redis 的服務治理平臺的相關知識,感興趣的朋友一起看看吧
    2021-05-05
  • Redis精確去重計數(shù)方法(咆哮位圖)

    Redis精確去重計數(shù)方法(咆哮位圖)

    這篇文章主要給大家介紹了關于Redis精確去重計數(shù)方法(咆哮位圖)的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用Redis具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
    2019-06-06
  • redis連接報錯error:NOAUTH Authentication required

    redis連接報錯error:NOAUTH Authentication required

    本文主要介紹了redis連接報錯error:NOAUTH Authentication required,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-05-05
  • Redis憑啥可以這么快

    Redis憑啥可以這么快

    本文詳細的介紹了為啥使用Redis的時候,可以做到非??斓淖x取速度,對于大家學習Redis非常有幫助,希望大家喜歡
    2021-02-02
  • redis中使用bloomfilter的白名單功能解決緩存穿透問題

    redis中使用bloomfilter的白名單功能解決緩存穿透問題

    本文主要介紹了redis中使用bloomfilter的白名單功能解決緩存穿透問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-07-07
  • Redis 中的布隆過濾器的實現(xiàn)

    Redis 中的布隆過濾器的實現(xiàn)

    這篇文章主要介紹了Redis 中的布隆過濾器的實現(xiàn),詳細的介紹了什么是布隆過濾器以及如何實現(xiàn),非常具有實用價值,需要的朋友可以參考下
    2018-10-10
  • Redis 使用跳表實現(xiàn)有序集合的方法

    Redis 使用跳表實現(xiàn)有序集合的方法

    Redis有序集合底層為什么使用跳表而非其他數(shù)據(jù)結構如平衡樹、紅黑樹或B+樹的原因在于其特殊的設計和應用場景,跳表提供了與平衡樹類似的效率,同時實現(xiàn)更簡單,調試和修改也更加容易,感興趣的朋友一起看看吧
    2024-09-09
  • 巧用Redis實現(xiàn)分布式鎖詳細介紹

    巧用Redis實現(xiàn)分布式鎖詳細介紹

    大家好,本篇文章主要講的是巧用Redis實現(xiàn)分布式鎖詳細介紹,感興趣的同學趕快來看一看吧,對你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • RediSearch加RedisJSON大于Elasticsearch的搜索存儲引擎

    RediSearch加RedisJSON大于Elasticsearch的搜索存儲引擎

    這篇文章主要為大家介紹了RediSearch加RedisJSON大于Elasticsearch的王炸使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • 淺談Redis處理接口冪等性的兩種方案

    淺談Redis處理接口冪等性的兩種方案

    本文主要介紹了淺談Redis處理接口冪等性的兩種方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-08-08

最新評論