用户关注功能

介绍

本文将介绍如何通过redis,mysql数据库实现用户关注,以及查看共同关注的功能。、

前置准备

创建一个tb_follow表,用于记录关注信息。

以及一个redis数据库。

实现思路

主要实现3个接口:

  • isFollow接口(进入up主页时调用):判断用户是否关注了当前up主,如果已经关注,返回true,否则返回false。
  • follow接口(点击关注按钮时调用):如果已经关注了该up,则取关,反之,关注up。
  • followCommons接口(点击共同关注按钮时调用):查看你和up都关注了哪些用户。

isFollow

controller

接收请求参数id(up主id),调用service中的业务逻辑。

java 复制代码
@GetMapping("/or/not/{id}")  
public Result isFollow(@PathVariable Long id) {  
    return followService.isFollow(id);  
}

service

java 复制代码
@Override  
public Result isFollow(Long id) {  
    Long userId = UserHolder.getUser().getId();  
    long count = query().eq("user_id", userId).eq("follow_user_id", id).count();  
    return Result.ok(count > 0);  
}

业务逻辑 :

从上下文(threadlocal)中获取当前用户id,根据用户id和up主id在tb_follow中查询数据,返回数据count > 0,如果有数据则为true,否则为false。

follow

controller

接收请求参数id(up主id),isFollow(true代表执行关注,false代表执行取关),调用service中的业务逻辑。

java 复制代码
@PutMapping("{id}/{isFollow}")  
public Result follow(@PathVariable Long id, @PathVariable Boolean isFollow) {  
    return followService.follow(id, isFollow);  
}

service

java 复制代码
@Override  
public Result follow(Long id, Boolean isFollow) {  
    Long userId = UserHolder.getUser().getId();  
    //判断当前用户是否关注  
    String key = "follow:" + userId;  
    if (isFollow) {  
        //关注,新增数据  
        Follow follow = new Follow();  
        follow.setUserId(userId);  
        follow.setFollowUserId(id);  
        boolean isSuccess = save(follow);  
        if (isSuccess) {  
            //把关注用户的id放入redis的set集合中,key:follow:userId value:followUserId  
            stringRedisTemplate.opsForSet().add(key, id.toString());  
        }  
    } else {  
        //取关,删除数据  
        boolean isSuccess = update().eq("user_id", userId).eq("follow_user_id", id).remove();  
        if (isSuccess) {  
            //把关注用户的id从redis的set集合中移除  
            stringRedisTemplate.opsForSet().remove(key, id.toString());  
        }  
    }  
    return Result.ok();  
}

业务逻辑:

  1. 从上下文(threadlocal)中获取当前用户id。
  2. 执行关注或取关
    关注:将信息写入follow实体(属性与tb_follow表字段一致),并写入数据库,如果操作成功,再放入redis的set集合中。
    取关:删除数据库信息,如果成功,再移除redis的set集合中的id。

followCommons

controller

接收请求参数id(当前查看up主的id)。

java 复制代码
@GetMapping("/common/{id}")  
public Result followCommons(@PathVariable Long id) {  
    return followService.followCommons(id);  
}

service

java 复制代码
@Override  
public Result followCommons(Long id) {  
    Long userId = UserHolder.getUser().getId();  
    String myKey = "follow:" + userId;  
    String targetKey = "follow:" + id;  
    //求交集  
    Set<String> intersect = stringRedisTemplate.opsForSet().intersect(myKey, targetKey);  
    if (intersect == null || intersect.isEmpty()) {  
        //没有共同关注  
        return Result.ok("没有共同关注");  
    }  
    //解析id集合  
    List<Long> commonIds = intersect.stream().map(Long::valueOf).collect(Collectors.toList());  
    //查询用户  
    List<User> users = userService.listByIds(commonIds);  
    //转换为DTO  
    List<UserDTO> userDTOS = users  
            .stream()  
            .map(user -> BeanUtil.copyProperties(user, UserDTO.class))  
            .collect(Collectors.toList());  
    return Result.ok(userDTOS);  
}

业务逻辑:

  1. 获取两者在redis中的key。
  2. 求两者交集。
    交集为空->直接返回结果
    有交集->解析出id集合
  3. 根据id集合查询用户,返回数据。

核心要点:

关注时将id放入redis中的set集合,优点:

查询效率 Redis Set 的 SINTER 命令可以一次求出交集,时间复杂度 O(min(n,m)),非常高效
去重 Set 自动去重,保证关注列表不重复
内存优化 相比数据库查询,Redis 内存操作快几十倍
相关推荐
学长毕设4 小时前
基于springboot的食品仓库管理系统
java·spring boot·后端
滴滴答答哒4 小时前
ASP.NET Core + FaceRecognitionDotNet 人脸识别实战:DI 单例、特征向量持久化与 1:N 比对
后端·asp.net
captain3766 小时前
MyBatis操作数据库(入门2)
java·数据库·spring boot·后端·spring·mybatis
IT_陈寒8 小时前
Java序列化踩坑记:对象循环引用让我加班两小时
前端·人工智能·后端
泡海椒8 小时前
05-雷达图多维画像-信用评级多维画像
后端
王中阳Go8 小时前
5.27 分钟干完后端和全部测试:一场三小时笔试的五个失分点,四个不在代码上
大数据·数据库·人工智能·后端·大语言模型
大哥43098 小时前
Modbus 的"字序":一个配错就变成天文数字,或者干脆变成 0
后端
岩钧8 小时前
New API 源码解析:一个生产级 AI 网关的架构与实现
后端
学到老活到老8 小时前
第 24 集:配置文件写了 80,Spring Boot 为什么读到 90?
java·后端·spring
用户360055579008 小时前
Kestrel_VLLM - 25 · 全注意力层设备化、整层对拍与访存粒度
后端