黑马点评12-实现好友关注/取关功能,查看好友共同关注列表

好友关注

数据模型

数据库中的tb_follow记录博主与粉丝的关系

在这里插入图片描述

tb_follow表对应的实体类

@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("tb_follow")
public class Follow implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 主键
     */
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    /**
     * 用户id
     */
    private Long userId;

    /**
     * 关联的用户id
     */
    private Long followUserId;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;
}

是否关注/关注/取关

需求: 在探店图文的详情页面中,可以查看用户是否关注了笔记博主,用户也可以手动关注/取消关注发布笔记的作者

在这里插入图片描述

第一步: 在FollowController层中编写判断是否关注关注/取关的两个方法

@RestController
@RequestMapping("/follow")
public class FollowController {
    @Resource
    private IFollowService followService;
    // 判断当前用户是否关注了笔记博主,参数是发布笔记的博主Id
    @GetMapping("/or/not/{id}")
    public Result isFollow(@PathVariable("id") Long followUserId) {
        return followService.isFollow(followUserId);
    }
    // 实现取关/关注,参数是发布笔记的博主Id以及是否关注(true表示关注,false表示取关)
    @PutMapping("/{id}/{isFollow}")
    public Result follow(@PathVariable("id") Long followUserId, @PathVariable("isFollow") Boolean isFellow) {
        return followService.follow(followUserId,isFellow);
    }
}

第二步: 在FellowServiceImp中来编写具体的业务逻辑

  • 判断当前用户是否关注了笔记博主: 将请求参数携带的发布笔记的博主Id和当前登陆的用户Id作为条件去数据库中查询是否有对应的记录
  • 关注和取消关注: 请求参数中的true(关注)/fasle(取关),关注是将用户和博主的关联信息保存到数据库,取关即将他们的关联信息从数据库移除,避免堆积数据
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {
    @Override
    public Result isFollow(Long followUserId) {
        // 获取当前登录的用户Id
        Long userId = UserHolder.getUser().getId();
        LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
        // 查询tb_follow表判断当前用户是否关注了该笔记的博主
        queryWrapper.eq(Follow::getUserId, userId).eq(Follow::getFollowUserId, followUserId);
        // 没必要查询出具体数据,只需要判断数据存不存在即可
        //select count(*) from tb_follow where user_id = ? and follow_user_id = ?
        int count = this.count(queryWrapper);
        return Result.ok(count > 0);
    }

    @Override
    public Result follow(Long followUserId, Boolean isFellow) {
        // 获取当前登录的用户Id
        Long userId = UserHolder.getUser().getId();
        // 判断用户是要关注还是取关,true表示关注,false表示取关
        if (isFellow) {
            // 关注则将用户和笔记博主的关联信息保存到数据库
            Follow follow = new Follow();
            follow.setUserId(userId);
            follow.setFollowUserId(followUserId);
            save(follow);
        } else {
            // 取关则将用户和博主的关联信息从数据库中移除,避免数据库中堆积大量数据
            //delete from tb_follow where user_id = ? and follow_user_id = ?
            LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Follow::getUserId, userId).eq(Follow::getFollowUserId, followUserId);
            remove(queryWrapper);
        }
        return Result.ok();
    }
}

共同关注

需求:当我们点击博主用户头像时进入到详情页,可以查看到博主发布的笔记以及用户和博主的好友共同关注列表

在这里插入图片描述

第一步: 在UserController中编写查询博主信息的方法

@GetMapping("/{id}")
public Result queryUserById(@PathVariable("id") Long userId) {
    // 查询详情
    User user = userService.getById(userId);
    if (user == null) {
        // 查不到返回空
        return Result.ok();
    }
    // 查到则转为userDTO对象
    UserDTO userDTO = BeanUtil.copyProperties(user, UserDTO.class);
    // 返回查询到的数据
    return Result.ok(userDTO);
}

第二步: 在BlogController中编写分页查询博主发布的所有笔记的方法

// 根据博主id查询博主的探店笔记
@GetMapping("/of/user")
public Result queryBlogByUserId(
    @RequestParam(value = "current", defaultValue = "1") Integer current, 
    @RequestParam("id") Long id) {
    LambdaQueryWrapper<Blog> queryWrapper = new LambdaQueryWrapper<>();
    // 根据博主id查询用户信息
    queryWrapper.eq(Blog::getUserId, id);
    Page<Blog> pageInfo = new Page<>(current, SystemConstants.MAX_PAGE_SIZE);
    blogService.page(pageInfo, queryWrapper);
    // 获取查询到的所有用户信息
    List<Blog> records = pageInfo.getRecords();
    return Result.ok(records);
}


// 根据博主id查询博主的探店笔记
@GetMapping("/of/user")
public Result queryBlogByUserId(
    @RequestParam(value = "current", defaultValue = "1") Integer current,
    @RequestParam("id") Long id) {
    // 根据博主id查询用户信息
    Page<Blog> page = blogService.query()
        .eq("user_id", id).page(new Page<>(current, SystemConstants.MAX_PAGE_SIZE));
    // 获取查询到的所有用户信息
    List<Blog> records = page.getRecords();
    return Result.ok(records);
}

第三步: 修改关注/取关的逻辑,以follows:userId作为Set集合的Key,存放当前用户关注的所有博主Id

  • 关注/取关: 将关注的博主Id放到当前登陆用户关注的Set集合中,取关就是将关注的博主Id从当前登陆用户的Set集合中移除
  • 共同关注:通过SINTER key1 key2查询登陆用户的Set集合和其关注博主的Set集合中元素的交集
@Resource
private StringRedisTemplate stringRedisTemplate;
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {
    @Override
    public Result follow(Long followUserId, Boolean isFellow) {
        // 获取当前登录的用户Id
        Long userId = UserHolder.getUser().getId();
        String key = "follows:" + userId;
        // 判断用户是要关注还是取关,true表示关注,false表示取关
        if (isFellow) {
            // 关注则将用户和笔记博主的关联信息保存到数据库
            Follow follow = new Follow();
            follow.setUserId(userId);
            follow.setFollowUserId(followUserId);
        	boolean iSsuccess = save(follow);
        	// 如果更新成功则将关联信息也写入Redis,key是当前的用户id,value就是关注的博主id
        	if (iSsuccess) {
            	stringRedisTemplate.opsForSet().add(key, followUserId.toString());
        	}
        } else {
            // 取关则将用户和博主的关联信息从数据库中移除,避免数据库中堆积大量数据
            //delete from tb_follow where user_id = ? and follow_user_id = ?
            LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Follow::getUserId, userId).eq(Follow::getFollowUserId, followUserId);
        	boolean iSsuccess = remove(queryWrapper);
        	// 如果取关成功则将关联的博主Id从当前登陆用户的set集合中移除
        	if (iSsuccess){
            	stringRedisTemplate.opsForSet().remove(key,followUserId.toString());
        	}
        }
        return Result.ok();
    } 
}

第四步: 编写控制器方法,查看登陆用户和其关注博主的好友共同关注列表

@GetMapping("/common/{id}")
public Result followCommons(@PathVariable Long id){
    return followService.followCommons(id);
}
@Resource
private IUserService userService;
@Override
public Result followCommons(Long id) {
    // 获取当前登陆用户的id
    Long userId = UserHolder.getUser().getId();
    // // 获取当前登陆对应的set集合的key
    String key1 = "follows:" + userId;
    // 获取当前登陆用户关注博主所对应的set集合的key
    String key2 = "follows:" + id;
    // 对当前登陆用户和其关注博主的Set集合取交集
    Set<String> intersect = stringRedisTemplate.opsForSet().intersect(key1, key2);
    // 无交集就返回个空的List集合
    if (intersect == null || intersect.isEmpty()) {
        return Result.ok(Collections.emptyList());
    }
    // 将String类型的用户id转化为Long类型的用户id然后使用List集合收集
    List<Long> ids = intersect.stream().map(Long::valueOf).collect(Collectors.toList());
    // 根据ids集合中的用户id去数据库中查询登陆用户和博主共同关注的用户信息并封装成UserDto对象,最后存入List集合中返回
    List<UserDTO> userDTOS = userService.listByIds(ids).stream().map(user ->
            BeanUtil.copyProperties(user, UserDTO.class)).collect(Collectors.toList());
    return Result.ok(userDTOS);
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从0开始学习JavaScript--JavaScript元编程

JavaScript作为一门灵活的动态语言&#xff0c;具备强大的元编程能力。元编程是一种通过操作程序自身结构的编程方式&#xff0c;使得程序能够在运行时动态地创建、修改、查询自身的结构和行为。本文将深入探讨JavaScript中元编程的各个方面&#xff0c;包括原型、反射、代理等…

宣传技能培训1——《新闻摄影技巧》光影魔法:理解不同光线、角度、构图的摄影效果,以及相机实战操作 + 新闻摄影实例讲解

新闻摄影技巧 写在最前面摘要 构图与拍摄角度景别人物表情与叙事远景与特写 构图与拍摄角度案例 主体、陪体、前景、背景强调主体利用前景和背景层次感的创造 探索新闻摄影中的构图技巧基本构图技巧构图技巧的应用实例实例分析1. 黄金分割和九宫格2. 三角型构图3. 引导线构图4.…

JS中的OOP

JS中的OOP OOP 为我们解决了什么问题&#xff1f;想象一下&#xff0c;我们希望为教师提供一个平台&#xff0c;每位注册的教师都可以提交分数&#xff0c;并为课程分配作业和其他内容。 如果有一个地方&#xff08;在本例中是一个对象&#xff09;&#xff0c;可以访问所有教…

补充:如何提高selenium的运行速度?

已经通读该专栏文章的同学,或许对UI自动化测试有了一定的掌握,细心的同学肯定会发现一个问题,当用例量达到一定程度时,对于整体用例的执行速度肯定不会很满意。除了应用多线程运行用例的方式加快速度,有没有其他的方法呢? 今天告诉大家,方法是有的!也是本人新学的。即…

C#串口通信从入门到精通(27)——高速通信下解决数据处理慢的问题(20ms以内)

前言 我们在开发串口通信程序时,有时候会遇到比如单片机或者传感器发送的数据速度特别快,比如10ms、20ms发送一次,并且每次发送的数据量还比较大,如果按照常规的写法,我们会发现接收的数据还没处理完,新的数据又发送过来了,这就会导致处理数据滞后,软件始终处理的不是…

Django中间件与csrf

一. django中间件 1. 什么是django中间件 # django中间件是django的门户1. 请求来的时候需要先经过中间件才能到达真正的django后端2. 响应走的时候最后也需要经过中间件才能发送出去 2. django中间件的个数 django自带七个中间件, 分别是SecurityMiddleware, SessionMiddle…

WordPress站点屏蔽过滤垃圾评论教程(Akismet反垃圾评论插件)

前段时间我的WordPress站点经常收到垃圾评论的轰炸&#xff0c;严重时一天会收到几十条垃圾评论。我这个小破站一没啥流量&#xff0c;二又不盈利&#xff0c;实在是不太理解为啥有人要这么执着地浪费资源在上面。 Akismet反垃圾评论插件 其实用了 Akismet 反垃圾评论插件后&a…

Python BDD 框架比较之 pytest-bdd vs behave

pytest-bdd和behave是 Python 的两个流行的 BDD 测试框架&#xff0c;两者都可以用来编写用户故事和可执行的测试用例&#xff0c; 具体选择哪一个则需要根据实际的项目状况来看。 先简单看一下两者的功能&#xff1a; pytest-bdd 基于pytest测试框架&#xff0c;可以与pytest…

PCIE链路训练-状态机描述2

Configuration.Lanenum.Accept 如果use_modified_TS1_TS2_Ordered_Set为1&#xff0c;需要注意&#xff1a; &#xff08;1&#xff09;tx需要发送Modified TS1而不是正常的TS1&#xff1b; &#xff08;2&#xff09;rx端必须检查是否收到Modified TS1&#xff08;注意一开…

STM32_6(TIM)

TIM定时器&#xff08;第一部分&#xff09; TIM&#xff08;Timer&#xff09;定时器定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时不仅…

测试Bard和ChatGPT对双休有关法规的认知和简单推理

Bard是试验品&#xff0c;chatgpt是3.5版的。 首先带着问题&#xff0c;借助网络搜索&#xff0c;从政府官方网站等权威网站进行确认&#xff0c;已知正确答案的情况下&#xff0c;再来印证两个大语言模型的优劣。 想要了解的问题是&#xff0c;在中国&#xff0c;跟法定工作…

通过Whisper模型将YouTube播放列表中的视频转换成高质量文字稿的项目

项目简介 一个通过Whisper模型将YouTube播放列表中的视频转换成高质量文字稿的项目。 这个基于 Python 的工具旨在将 YouTube 视频和播放列表转录为文本。它集成了多种技术&#xff0c;例如用于转录的 Fast-Whisper、用于自然语言处理的 SpaCy 以及用于 GPU 加速的 CUDA&…

使用Pytorch从零开始构建LSTM

长短期记忆&#xff08;LSTM&#xff09;网络已被广泛用于解决各种顺序任务。让我们了解这些网络如何工作以及如何实施它们。 就像我们一样&#xff0c;循环神经网络&#xff08;RNN&#xff09;也可能很健忘。这种与短期记忆的斗争导致 RNN 在大多数任务中失去有效性。不过&a…

解决mv3版本浏览器插件,不能注入js脚本问题

文章目录 背景引入ifream解决ifream和父页面完全跨域问题参考链接 背景 浏览器插件升级mv3版本后&#xff0c;不能再使用content_script内容脚本向原浏览器&#xff08;top&#xff09;注入script标签达到注入脚本的目的。浏览器认为插入未经审核的脚本是不安全的行为。 引入…

经常喝羊奶,羊大师告诉你会有何不同

经常喝羊奶&#xff0c;羊大师告诉你会有何不同 羊奶&#xff0c;与人们日常饮用的牛奶相比&#xff0c;一直都没有得到足够的关注。然而&#xff0c;羊奶在一些特定方面却具有独特的优势。它不仅具有丰富的营养价值&#xff0c;还有助于提升人体的健康水平。本文小编羊大师将…

【Skynet 入门实战练习】游戏模块划分 | 基础功能模块 | timer 定时器模块 | logger 日志服务模块

文章目录 游戏模块基础功能模块定时器模块日志模块通用模块 游戏模块 游戏从逻辑方面可以分为下面几个模块&#xff1a; 注册和登录网络协议数据库玩法逻辑其他通用模块 除了逻辑划分&#xff0c;还有几个重要的工具类模块&#xff1a; Excel 配置导表工具GM 指令测试机器人…

【CCF-PTA】第03届Scratch第01题 -- 梦醒时分

梦醒时分 【题目描述】 睡眠是人体正常的生理需要&#xff0c;同年龄男女睡眠时间无明显差别&#xff0c;一般是8小时左右。居家的小明作息生活很规律&#xff0c;晚上11点睡觉&#xff0c;早晨7点起床学习。请你编写程序来判断&#xff0c;每周&#xff08;共168小时&#x…

Elasticsearch:ES|QL 函数及操作符

如果你对 ES|QL 还不是很熟悉的话&#xff0c;请阅读之前的文章 “Elasticsearch&#xff1a;ES|QL 查询语言简介​​​​​​​”。ES|QL 提供了一整套用于处理数据的函数和运算符。 功能分为以下几类&#xff1a; 目录 ES|QL 聚合函数 AVG COUNT COUNT_DISTINCT 计数为近…

【计算机网络笔记】数据链路层概述

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…