用户关注功能

介绍

本文将介绍如何通过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 内存操作快几十倍
相关推荐
前端一小卒6 小时前
我用 Claude Code 的 Superpowers 技能链写了个服务,部署前差点把服务器搞炸
前端·javascript·后端
曹牧7 小时前
Spring:@RequestMapping注解,匹配的顺序与上下文无关
java·后端·spring
阿丰资源9 小时前
SpringBoot+Vue实战:打造企业级在线文档管理系统
vue.js·spring boot·后端
Rust研习社9 小时前
使用 Axum 构建高性能异步 Web 服务
开发语言·前端·网络·后端·http·rust
0xDevNull9 小时前
Spring Boot 自动装配:从原理到实践
java·spring boot·后端
IT_陈寒9 小时前
SpringBoot配置加载顺序把我坑惨了
前端·人工智能·后端
Moment10 小时前
面试官:给 llm 传递上下文,有哪几个身份 role ❓❓❓
前端·后端·面试
snakeshe101010 小时前
SpringBoot 多人协作平台实战(5):从零开始集成 MyBatis ORM 连接 MySQL 数据库
后端
SamDeepThinking10 小时前
中小团队需要一个资源微服务
后端·微服务·架构
超梦dasgg11 小时前
Spring AI 智能航空助手项目实战
java·人工智能·后端·spring·ai编程