关注、取关、Redis实现共同关注、 博客推送与分页查询

news2024/11/28 18:58:48
@Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private IUserService userService;
    @Override
    public Result follow(Long followUserId, Boolean isFollow) {
        //1.获取登陆的用户
        Long userId = UserHolder.getUser().getId();
        //1.判断是关注还是取关
        if(isFollow){
            //关注,新增数据
            Follow follow = new Follow();
            follow.setUserId(userId);
            follow.setFollowUserId(followUserId);
            boolean isSuccess = this.save(follow);
            if(isSuccess){
                // 把关注用户的id,放入到redis的set集合 sadd userId followerUserId
                String key = "follows:" + userId;
                stringRedisTemplate.opsForSet().add(key, followUserId.toString());
            }
        }else {
            //取关,删除
            QueryWrapper<Follow> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("follow_user_id", followUserId).eq("user_id", userId);
            boolean isSuccess = this.remove(queryWrapper);
            if(isSuccess){
                //从redis集合中移除
                String key = "follows:" + userId;
                stringRedisTemplate.opsForSet().remove(key, followUserId.toString());
            }

        }
        return Result.ok();
    }

    @Override
    public Result isFollow(Long followUserId) {
        //1.获取登陆的用户
        Long userId = UserHolder.getUser().getId();
        //查询是否关注
        Integer count = this.query().eq("follow_user_id", followUserId).eq("user_id", userId).count();
        return Result.ok(count > 0);
    }

    @Override
    public Result followCommons(Long id) {
        //获取当前的用户
        Long userId = UserHolder.getUser().getId();
        //知道两个用户在Redis中求交集
        String key1 = "follows:" + userId;
        String key2 = "follows:" + id;
        Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key1, key2);
        if(intersect == null || intersect.isEmpty()){
            //无交集
            return Result.ok(Collections.emptyList());
        }
        //通过Set集合解析出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);
    }

 博客推送与分页查询

 查询的控制层

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

 发布与查询的服务层

    //大V发布,并进行推送
    @Override
    public Result saveBlog(Blog blog) {
        // 获取登录用户
        UserDTO user = UserHolder.getUser();
        blog.setUserId(user.getId());
        // 保存探店博文
        boolean isSuccess = this.save(blog);
        if(!isSuccess){
            return Result.fail("新增笔记失败");
        }
        //查询笔记作者的所有粉丝  follow_user_id时大V的id
        List<Follow> follows = followService.query().eq("follow_user_id", user.getId()).list();
        //推送笔记id给所有粉丝
        for (Follow follow : follows) {
            //获取粉丝id
            Long userId = follow.getUserId();
            //推送
            String key = "feed:" + userId;
            stringRedisTemplate.opsForZSet().add(key, blog.getId().toString(), System.currentTimeMillis());
        }
        // 返回id
        return Result.ok(blog.getId());
    }

    //粉丝收到,并实现滚动分页查询
    @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);
        //非空判断
        if(typedTuples == null || typedTuples.isEmpty()){
            return Result.ok();
        }
        //3.解析数据:blogId,minTime(时间戳)、offset
        List<Long> ids = new ArrayList<>(typedTuples.size());
        long minTime = 0;
        int os = 1; //最少为一个与最小一样
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            //获取id
            ids.add(Long.valueOf(typedTuple.getValue()));
            //获取分数
            long time = typedTuple.getScore().longValue();
            if(time == minTime){
                os++;
            }else {
                minTime = time;
                os = 1;
            }
        }
        //4.根据id查询blog
        String idStr = StrUtil.join(",", ids);
        List<Blog> blogs = this.query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();
        for (Blog blog : blogs) {
            //查询blog有关的用户
            this.queryBlogUser(blog);
            //查询blog是否被点赞
            this.isBlogLiked(blog);
        }
        //5.封装并返回
        ScrollResult r = new ScrollResult();
        r.setList(blogs);
        r.setOffset(os);
        r.setMinTime(minTime);
        return Result.ok(r);
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2189393.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Springboot+Vue的小区运动中心预约管理系统的设计与实现 (含源码数据库)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 这段数…

FPGA-UART串口接收模块的理解

UART串口接收模块 背景 在之前就有写过关于串口模块的文章——《串口RS232的学习》。工作后很多项目都会用到串口模块&#xff0c;又来重新理解一下FPGA串口接收的代码思路。 关于串口相关的参数&#xff0c;以及在文章《串口RS232的学习》中已有详细的描述&#xff0c;这里就…

Linux启动mysql报错

甲方公司意外停电&#xff0c;所有服务器重启后&#xff0c;发现部署在Linux上的mysql数据库启动失败.再加上老员工离职&#xff0c;新接手项目&#xff0c;对Linux系统了解不多&#xff0c;解决起来用时较多&#xff0c;特此记录。 1.启动及报错 1.1 启动语句1 启动语句1&a…

Java编程基础(Scanner类==>循环语句)

文章目录 前言一、Scanner类1.创建Scanner对象2.使用3.实践 二、if条件语句1.简单if语句2.if-else语句3.if-else if-else语句3.实践 三、switch 开关语句四、循环语句1.for语句2.while语句3.do-while语句4.break和continue语句 总结 前言 我们发现在学习Java语言编程基础时&am…

【GEE数据库】WRF常用数据集总结

【GEE数据库】WRF常用数据集总结 GEE数据集介绍数据1:MODIS数据集LAI(叶面积指数)和Fpar(绿色植被率)年尺度土地利用类型数据2:月反射率(Monthly Albedo)数据3:LULC和ISA参考GEE数据集介绍 GEE数据搜索网址-A planetary-scale platform for Earth science data &…

(PyTorch) 深度学习框架-介绍篇

前言 在当今科技飞速发展的时代&#xff0c;人工智能尤其是深度学习领域正以惊人的速度改变着我们的世界。从图像识别、语音处理到自然语言处理&#xff0c;深度学习技术在各个领域都取得了显著的成就&#xff0c;为解决复杂的现实问题提供了强大的工具和方法。 PyTorch 是一个…

9.30学习记录(补)

手撕线程池: 1.进程:进程就是运行中的程序 2.线程的最大数量取决于CPU的核数 3.创建线程 thread t1; 在使用多线程时&#xff0c;由于线程是由上至下走的&#xff0c;所以主程序要等待线程全部执行完才能结束否则就会发生报错。通过thread.join()来实现 但是如果在一个比…

08.STL简介

1. 什么是STL STL(standard template libaray-标准模板库)&#xff1a;是C标准库的重要组成部分&#xff0c;不仅是一个可复用的 组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架 2.发展历史 1. 起源与早期探索&#xff08;20世纪80年代初期&#xff09;&#xff…

可变形卷积(Deformable Convolution)是什么?

普通卷积 普通卷积&#xff08;dilation1&#xff09; 普通卷积就是特征图与卷积核的权重W相乘再求和 y(p0​) 表示输出特征图在位置 p0​ 的值。&#x1d465;(&#x1d45d;0&#x1d45d;&#x1d45b;)表示输入特征图在位置 pn​ 的值。&#x1d464;(&#x1d45d;&…

烟火烟雾检测数据集 9600张 烟雾火焰检测 带标注 voc yolo 2类 烟火数据集 烟雾数据集 烟火检测烟雾检测

烟火检测数据集 9600张 烟雾火焰检测 带标注 voc yolo 烟火检测数据集介绍 数据集名称 烟火检测数据集 (Fire and Smoke Detection Dataset) 数据集概述 该数据集专为训练和评估基于YOLO系列目标检测模型&#xff08;包括YOLOv5、YOLOv6、YOLOv7等&#xff09;而设计&#x…

malloc源码分析之 ----- 你想要啥chunk

文章目录 malloc源码分析之 ----- 你想要啥chunktcachefastbinsmall binunsorted binbin处理top malloc源码分析之 ----- 你想要啥chunk tcache malloc源码&#xff0c;这里以glibc-2.29为例&#xff1a; void * __libc_malloc (size_t bytes) {mstate ar_ptr;void *victim;vo…

Qt Quick 3D 入门:QML 3D场景详解

随着 Qt 6 的发布&#xff0c;QtQuick3D 模块带来了新的 3D 渲染和交互能力&#xff0c;使得在 Qt 中创建 3D 场景变得更加简单和直观。本文将带您从一个简单的 QML 3D 应用开始&#xff0c;详细讲解各个相关领域的概念、代码实现以及功能特点。 什么是 Qt Quick 3D&#xff1…

C++拾趣——绘制Console中Check Box

大纲 居中显示窗口清屏并重设光标绘制窗口绘制窗口顶部绘制复选项绘制按钮行绘制窗口底部 修改终端默认行为对方向键的特殊处理过程控制Tab键的处理Enter键的处理上下左右方向键的处理 完整代码代码地址 这次我们要绘制复选框&#xff0c;如下图。 居中显示窗口 按照界面库的…

网约班车升级手机端退票

背景 作为老古董程序员&#xff0c;不&#xff0c;应该叫互联网人员&#xff0c;因为我现在做的所有的事情&#xff0c;都是处于爱好&#xff0c;更多的时间是在和各行各业的朋友聊市场&#xff0c;聊需求&#xff0c;聊怎么通过IT互联网 改变实体行业的现状&#xff0c;准确的…

ExcelToWord-Excel套打Word-Word邮件合并工具分享

Excel to Word转换工具分享 在日常工作或学习中&#xff0c;我们常常需要将Excel中的数据导出到Word文档中&#xff0c;以便更好地展示信息。市场上有许多Excel to Word的转换工具&#xff0c;它们各有特色。今天&#xff0c;我们就来推荐几款这样的工具&#xff0c;并探讨一下…

如何使用虚拟机充当软路由

文章目录 前言下载系统把 iso 转为虚拟机使用 VMware 创建虚拟机 前言 很多人需要软路由&#xff0c;但是软路由需要设备的投入&#xff0c;我这里使用虚拟机充当软路由。省下了设备的投入。不过多花了电费。大家自己取舍吧。 下载系统 ImmortalWrt Firmware Selector 在上…

蓝桥等级考试C++组18级真题-2023-06-18

选择题 1 C L18(15分) 已定义double rate 3.921576&#xff1b;以下可以正确输出变量rate 的是()。 A printf("%d",rate)&#xff1b; B printf("%f",rate)&#xff1b; C printf("%ld",rate)&#xff1b; D printf("%r",rate)&#…

PhpStudy-PHP5.4.45后门漏洞应用程序(C++/base64/winhttp)

PhpStudy-PHP5.4.45后门漏洞应用程序&#xff08;C/base64/winhttp&#xff09; 前言引言&#xff08;时间回到多年前&#xff09; PhpShellCmd.exe使用介绍&#xff1a;&#xff08;1&#xff09;输入网址检测是否存在PHP/5.4.45&#xff08;2&#xff09;whoami&#xff08;3…

新闻推荐系统:Spring Boot与大数据

4系统概要设计 4.1概述 本系统采用B/S结构(Browser/Server,浏览器/服务器结构)和基于Web服务两种模式&#xff0c;是一个适用于Internet环境下的模型结构。只要用户能连上Internet,便可以在任何时间、任何地点使用。系统工作原理图如图4-1所示&#xff1a; 图4-1系统工作原理…

IP协议报文

一.IP协议报头结构 二.IP协议报头拆解 1.4位版本 实际上只有两个取值&#xff0c;分别是4和6&#xff0c;4代表的是IPv4&#xff0c;6代表的是IPv6。 2.4位首部长度 IP协议报头的长度也是边长的&#xff0c;单位是*4&#xff0c;这里表示的大小为0~15&#xff0c;当数值为1…