SpringBoot整合Redis之粉丝关注实战

一、使用Jedis操作Redis

Jedis是老牌的 Redis 的 Java 实现客户端,提供了比较全面的 Redis 命令的支持,其官方网址是https://github.com/redis/jedis
Jedis的语法与redis的API相同,所以学习成本低,但是其实例不是线程安全的,所以需要通过连接池来使用 Jedis。

Jedis初体验

  1. 添加jedis依赖
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.7.0</version>
        </dependency>
  1. 编写测试类
public class JedisTest {
    
    

    private Jedis jedis;
    @BeforeEach
    void setUp(){
    
    
    	//redis的IP及端口号
        jedis = new Jedis("XXX.XX.XXX.XX",6379);
//        jedis = JedisConnFactory.getJedis();
        //redis的密码
        jedis.auth("123465");
        //选择第几个数据库
        jedis.select(0);

    }

    @Test
    void testString(){
    
    
        String res = jedis.set("name", "张三");
        String name = jedis.get("name");
        System.out.println(name);

    }
    @AfterEach
    void tearDown(){
    
    
        if (jedis!=null){
    
    
        //记得关闭连接
            jedis.close();
        }
    }
}
  1. 测试结果

在这里插入图片描述
在这里插入图片描述

通过连接池使用Jedis

上面说到,因为Jedis的实例是线程不安全的,所以我们要通过连接池来使用 Jedis。

  1. 编写Jedis连接工厂类
public class JedisConnFactory {
    
    
    private static final JedisPool jedisPool;
    static {
    
    
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        //设置最大连接数
        jedisPoolConfig.setMaxTotal(8);
        //设置最大空闲连接数
        jedisPoolConfig.setMaxIdle(8);
        //设置最小空闲连接数
        jedisPoolConfig.setMaxIdle(0);
        //设置最大等待时长
        jedisPoolConfig.setMaxWaitMillis(1000);
        jedisPool = new JedisPool(jedisPoolConfig,"XXX.XX.XXX.XX",6379,1000,"123465");
    }

    public static Jedis getJedis(){
    
    
        return jedisPool.getResource();
    }

}
  1. 修改测试类,并且我们这次测试Hash类型
public class JedisTest {
    
    

    private Jedis jedis;
    @BeforeEach
    void setUp(){
    
    
        jedis = JedisConnFactory.getJedis();
    }

    @Test
    void testString(){
    
    
        String res = jedis.set("name", "张三");
        String name = jedis.get("name");
        System.out.println(name);

    }

    @Test
    void testHash(){
    
    
        jedis.hset("user:4","name","IDEA");
        jedis.hset("user:4","age","23");
        Map<String, String> res = jedis.hgetAll("user:4");
        System.out.println(res);
    }

    @AfterEach
    void tearDown(){
    
    
        if (jedis!=null){
    
    
            jedis.close();
        }
    }
}

  1. 测试结果
    在这里插入图片描述
    在这里插入图片描述

二、SpringDataRedis操作redis

redisTemplate操作redis,不像Jedis那样有和redis API完全一样的语句,但是redisTemplate更接近java语法。
在这里插入图片描述
例如,opsForValue操作String类型,opsForHash操作Hash类型等,我将在下面给大家演示。

  1. 添加依赖
  2. 编写配置文件
spring:
  redis:
    host: XXX.XX.XXX.XX
    port: 6379
    password: 123465
    lettuce:
      pool:
        max-idle: 8
        max-wait: 1000ms
        max-active: 8
        min-idle: 0
  1. 编写测试类
@SpringBootTest
public class RedisTest {
    
    
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    void testString(){
    
    
        redisTemplate.opsForValue().set("name3","操作工");
        Object name = redisTemplate.opsForValue().get("name3");
        System.out.println("name3 = " + name);
    }
}
  1. 测试结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

通过控制台打印的“name3 = 操作工”,这个结果似乎是正确的,的确是我们存进去的key和value。
但是在redis的可视化工具中我们看到的是有乱码。不管是key还是value。
其实,这是因为我们没有序列化key-value。那接下来我们就设置一下。

redis序列化

  1. 编写配置类
@Configuration
public class RedisConfig {
    
    
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
    
    
        //创建redistem对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        //设置连接工厂
        template.setConnectionFactory(redisConnectionFactory);
        //创建json序列化工具
        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        //设置key的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        //设置value的序列化
        template.setValueSerializer(genericJackson2JsonRedisSerializer);
        template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
        return template;
    }
}
  1. 修改测试类,并测试存入一个对象
@SpringBootTest
public class RedisTest {
    
    
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Test
    void testSaveUser(){
    
    
        redisTemplate.opsForValue().set("user:1",new User("操作工",22));
        User user = (User) redisTemplate.opsForValue().get("user:1");
        System.out.println(user);
    }
}
  1. 测试结果

在这里插入图片描述
通过测试结果可以看到,虽然我们存入对象成功了,但是数据里多了一行@class的数据,这会占用我们的内存。

使用StringRedisTemplate

StringRedisTemplate的key,value都是String类型,所以当我们的value是对象的时候,要先转换成String类型的json串。

  • 编写测试类
@SpringBootTest
public class StringRedisTest {
    
    
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Test
    void testString(){
    
    
        stringRedisTemplate.opsForValue().set("name2","操作工2");
        String name2 = stringRedisTemplate.opsForValue().get("name2");
        System.out.println(name2);

    }

    @Test
    void testSaveUser(){
    
    
        User user = new User("操作工2",23);
        String s = JSONObject.toJSONString(user);
        stringRedisTemplate.opsForValue().set("user:2",s);
        String s1 = stringRedisTemplate.opsForValue().get("user:2");
        System.out.println(s1);
    }

    @Test
    void testHash(){
    
    
        stringRedisTemplate.opsForHash().put("user:3","name","操作工3");
        stringRedisTemplate.opsForHash().put("user:3","age","23");
        Map<Object, Object> entries = stringRedisTemplate.opsForHash().entries("user:3");
        System.out.println(entries);
    }
}

三、实现粉丝和关注

  1. 创建用户表、关注数据表
CREATE TABLE `tb_user` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
  `userId` varchar(50) COLLATE utf8mb4_general_ci NOT NULL,
  `phone` varchar(11) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号码',
  `password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '密码,加密存储',
  `userName` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '昵称,默认是用户id',
  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT '人物头像',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uniqe_key_phone` (`phone`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1019 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT;
CREATE TABLE `tb_follow` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
  `user_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '用户id',
  `follow_user_id` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '关注的用户id',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT;
  1. 使用mybatisPlus生成pojo、service、mapper

  2. 编写controller层代码

@RestController
@RequestMapping("/follow")
@Api("粉丝关注")
public class FollowController {
    
    

    @Resource
    private FollowService followService;

    @PostMapping("/follow")
    @ApiOperation("关注/取关")
    public Result follow(@RequestBody FollowParam followParam){
    
    
        Boolean follow = followService.follow(followParam);
        return Result.success(follow);
    }

    @GetMapping("/queryFollow")
    @ApiOperation("关注列表")
    public Result queryFollow(@RequestParam String userId){
    
    
        List<FollowInfo> list = followService.queryFollows(userId);
        return Result.success(list);
    }
}
  1. 编写service接口
public interface FollowService extends IService<Follow> {
    
    

    Boolean follow(FollowParam followParam);

    List<FollowInfo> queryFollows(String userId);
}
  1. 编写service实现类
@Slf4j
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow>
    implements FollowService{
    
    

    private final StringRedisTemplate stringRedisTemplate;
    private final UserMapper userMapper;

    public FollowServiceImpl(StringRedisTemplate stringRedisTemplate, UserMapper userMapper) {
    
    
        this.stringRedisTemplate = stringRedisTemplate;
        this.userMapper = userMapper;
    }

    @Override
    public Boolean follow(FollowParam followParam) {
    
    
        String key = "follow:" +followParam.getCurUserId();
        LambdaQueryWrapper<User> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(User::getUserId,followParam.getFollowId());
        User user = userMapper.selectOne(wrapper1);
        String name = user.getUserName();
        String desc = user.getRemark();
        FollowInfo followInfo = new FollowInfo(followParam.getFollowId(),name,desc);
        if(followParam.getIsFollow()){
    
    
            Follow follow = new Follow();
            follow.setFollow_user_id(followParam.getFollowId());
            follow.setUser_id(followParam.getCurUserId());
            follow.setCreate_time(new Date());
            boolean save = this.save(follow);
            if(save){
    
    
                stringRedisTemplate.opsForSet().add(key, JSONObject.toJSONString(followInfo));
            }
            return save;
        }else {
    
    
            LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Follow::getFollow_user_id,followParam.getFollowId()).eq(Follow::getUser_id,followParam.getCurUserId());
            boolean remove = this.remove(wrapper);
            if (remove){
    
    
                stringRedisTemplate.opsForSet().remove(key,JSONObject.toJSONString(followInfo));
            }
            return remove;

        }

    }

    @Override
    public List<FollowInfo> queryFollows(String userId) {
    
    
        String key = "follow:" +userId;
        Set<String> follows = stringRedisTemplate.opsForSet().members(key);
        List<FollowInfo> followVos = new ArrayList<>();
        if(CollectionUtils.isEmpty(follows)){
    
    
            LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Follow::getUser_id,userId);
            List<Follow> list = this.list(wrapper);
            for (Follow follow : list) {
    
    
                LambdaQueryWrapper<User> wrapper1 = new LambdaQueryWrapper<>();
                wrapper1.eq(User::getUserId,follow.getFollow_user_id());
                User user = userMapper.selectOne(wrapper1);
                String name = user.getUserName();
                String desc = user.getRemark();
                FollowInfo followInfo = new FollowInfo(follow.getFollow_user_id(),name,desc);
                followVos.add(followInfo);

            }
            return followVos;

        }else {
    
    
            for (String fan : follows) {
    
    
                FollowInfo followInfo = JSONObject.parseObject(fan, FollowInfo.class);
                followVos.add(followInfo);
            }
            return followVos;
        }

    }
}
  1. 入参及出参
@Data
public class FollowParam implements Serializable {
    
    
    private String curUserId;
    private String followId;
    private Boolean isFollow;
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class FollowInfo implements Serializable {
    
    
    private String userId;
    private String name;
    private String desc;
}
  1. 测试结果
    在这里插入图片描述
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/zhang0305/article/details/125357439