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

news2024/9/21 23:30:55

好友关注

数据模型

数据库中的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);
}

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

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

相关文章

【RtpRtcp】1: webrtc m79:audio的ChannelReceive 创建并使用

m79中,RtpRtcp::Create 的调用很少 不知道谁负责创建ChannelReceiveclass ChannelReceive : public ChannelReceiveInterface,public MediaTransportAudioSinkInterface {接收编码后的音频帧:接收rtcp包:

nodejs微信小程序+python+PHP -留学信息查询系统的设计与实现-安卓-计算机毕业设计

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

如何提高希音、亚马逊、国际站店铺流量转化,自养号优势及测评底层环境逻辑

随着全球贸易数字化程度加快&#xff0c;尤其是跨境电商的发展日新月异&#xff0c;在外贸出口占比越来越高&#xff0c;在这其中&#xff0c;亚马逊作为全球实力强劲的在线零售平台之一&#xff0c;吸引了大量的优秀卖家。 而这也加剧了亚马逊平台的竞争程度&#xff0c;尤其…

Java核心知识点整理大全9-笔记

目录 null文章浏览阅读9w次&#xff0c;点赞7次&#xff0c;收藏7次。Java核心知识点整理大全https://blog.csdn.net/lzy302810/article/details/132202699?spm1001.2014.3001.5501 Java核心知识点整理大全2-笔记_希斯奎的博客-CSDN博客 Java核心知识点整理大全3-笔记_希斯…

二十四、RestClient操作文档

目录 一、新增文档 1、编写测试代码 二、查询文档 1、编写测试代码 三、删除文档 1、编写测试代码 四、修改文档 1、编写测试代码 五、批量导入文档 批量查询 一、新增文档 1、编写测试代码 SpringBootTest public class HotelDocumentTest {private RestHighLevelC…

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;注意一开…

node版本管理工具-nvm

1、 下载地址 https://github.com/coreybutler/nvm-windows/releases/tag/1.1.11 2、 选择安装地址不能有空格&#xff0c;中文 3、 使用命令

【图论】关键路径求法c++

代码结构如下图&#xff1a; 其中topologicalSort(float**, int, int*, bool*, int, int)用来递归求解拓扑排序&#xff0c;topologicalSort(float**, int*&, int, int, int)传参图的邻接矩阵mat与结点个数n&#xff0c;与一个引用变量数组topo&#xff0c;返回一个布尔值…

【网络奇缘】- 计算机网络|分层结构|ISO模型

&#x1f308;个人主页: Aileen_0v0&#x1f525;系列专栏: 一见倾心,再见倾城 --- 计算机网络~&#x1f4ab;个人格言:"没有罗马,那就自己创造罗马~" 目录 计算机网络分层结构 OSI参考模型 OSI模型起源 失败原因: OSI模型组成 协议的作用 &#x1f4dd;全文…

C语言——求分段函数 y=f(x)的值

求分段函数 yf(x)的值,f(x)的表达式如下: #define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int x,y;printf("请输入x的值&#xff1a;");scanf("%d",&x);if(x>5){yx3;}else if(x>0 && x<5){y0;}elsey2*x30;pr…

使用vcpkg安装库失败的解决方法

1、前言 vcpk是是一款开源的c/c库管理工具&#xff0c;尤其是在windows平台&#xff0c;可以帮助我们很好的管理各种依赖包。 在windows环境做c/c开发的人应该都深有体会&#xff0c;有时候编译需要下载一堆依赖库&#xff0c;导致搭建编译环境特别麻烦。但是&#xff0c;通过v…

深入理解Spring AOP的工作流程

文章目录 引言什么是AOP&#xff1f;Spring AOP的工作原理1. JDK动态代理2. CGLIB代理 Spring AOP的注解方式Aspect注解EnableAspectJAutoProxy注解 Spring AOP的工作流程拓展应用1. 自定义注解2. 异常处理3. 切面优先级 结论 &#x1f389;深入理解Spring AOP的工作流程 ☆* o…

vue - - - - - vue-qr插件生成二维码

vue-qr插件生成二维码 1. 安装插件2. 组件使用示例图&#xff1a;扫码结果 1. 安装插件 【vue-qr 官网地址】 npm install vue-qr --save // or yarn add vue-qr --save2. 组件使用 <template><vue-qr :logo-src"logoSrc":size"237":margin&qu…

Cache学习(2):Cache结构 命中与缺失 多级Cache结构 直接映射缓存

1 Cache名词解释 命中&#xff08;hit&#xff09;&#xff1a; CPU要访问的数据在Cache中有缓存缺失&#xff08;miss&#xff09;&#xff1a; CPU要访问的数据在Cache中没有缓存Cache Size&#xff1a;Cache的大小&#xff0c;代表Cache可以缓存最大数据的大小Cache Line&a…

Java设计模式系列:单例设计模式

Java设计模式系列&#xff1a;单例设计模式 介绍 所谓类的单例设计模式&#xff0c;就是采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法&#xff08;静态方法&#xff09; 比如 Hiberna…

西门子(Siemens)仿真PLC启动报错处理

目录 一、背景&#xff1a; 二、卸载软件 三、安装软件 三、启动软件 四、下载PORTAL项目 五、测试 一、背景&#xff1a; 在启动S7-PLCSIM Advanced V3.0仿真PLC时报错&#xff0c;报错信息为&#xff1a;>>Siemens PLCSIM Virtual Switch<<is misconfigu…

iframe内部子页面与外部主页面通讯

文章目录 一、问题二、解决2.1、子页面2.2、主页面 三、知识点3.1、[浏览器兼容性](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage#%E6%B5%8F%E8%A7%88%E5%99%A8%E5%85%BC%E5%AE%B9%E6%80%A7)3.2、详解3.2.1、发送方3.2.2、接收方 一、问题 如上所示&a…

Vue3中如何响应式解构 props

目录 1&#xff0c;前言2&#xff0c;解决2.1&#xff0c;利用插件&#xff0c;实现编译时转换2.2&#xff0c;toRef 和 toRefs 1&#xff0c;前言 Vue3 中为了保持响应性&#xff0c;始终需要以 props.x 的方式访问这些 prop。这意味着不能够解构 defineProps 的返回值&#…

【云原生 Prometheus篇】Prometheus架构详解与核心组件的应用实例(Exporters、Grafana...)

Prometheus Part1 一、常用的监控系统1.1 简介1.2 Prometheus和zabbix的区别 二、Prometheus2.1 简介2.2 Prometheus的主要组件1&#xff09;Prometheus server2&#xff09;Exporters3&#xff09;Alertmanager4&#xff09;Pushgateway5&#xff09;Grafana 2.3 Prometheus的…

【性能优化】CPU利用率飙高与内存飙高问题

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;2022年度博客之星全国TOP3&#xff0c;专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化&#xff0c;文章内容兼具广度、深度、大厂技术方案&#xff0c;对待技术喜欢推理加验证&#xff0c;就职于…