用户关注功能

介绍

本文将介绍如何通过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 内存操作快几十倍
相关推荐
Lee川3 小时前
mini-cursor 揭秘:从 Tool 定义到 Agent 循环的完整实现
前端·人工智能·后端
星浩AI5 小时前
OpenHuman 对比 OpenClaw、Hermes Agent
人工智能·后端·agent
小江的记录本5 小时前
【Java基础】泛型:泛型擦除、通配符、上下界限定(附《思维导图》+《面试高频考点清单》)
java·数据结构·后端·mysql·spring·面试·职场和发展
geovindu7 小时前
go: Semaphore Pattern
开发语言·后端·设计模式·golang·企业级信号量模式
IT_陈寒7 小时前
Redis内存用爆了,原来我们都忽略了这个配置
前端·人工智能·后端
武子康7 小时前
Java-02 深入浅出MyBatis 3 快速入门:环境配置、项目创建与 CRUD 操作
java·后端
未若君雅裁8 小时前
Spring Boot 自动配置原理与常用注解
java·spring boot·后端
Xiacqi18 小时前
Java数据库连接--JDBC--DRUID
数据库·后端
浮游本尊8 小时前
用结构化 Prompt 让大模型「干活」:以数据库巡检告警建议生成为例
后端
snakeshe10109 小时前
SpringBoot 多人协作平台实战(8):Cookie 与登录状态维持
后端