Springboot系列(十四):集成redis,文末附完整源码(Redis零基础教学-完结篇)

450 阅读6分钟

👨‍🎓作者:bug菌
✏️博客:CSDN掘金infoQ51CTO
🎉简介:CSDN博客专家,C站历届博客之星Top50,掘金/InfoQ/51CTO等社区优质创作者,全网合计8w粉+,对一切技术感兴趣,重心偏Java方向;硬核公众号「 猿圈奇妙屋」,欢迎小伙伴们的加入,一起秃头,一起变强。
..
✍️温馨提醒:本文字数:1999字, 阅读完需:约 5 分钟

       嗨,家人们,我是bug菌呀,我又来啦。今天我们来聊点什么咧,OK,接着为大家更《springboot零基础入门教学》系列文章吧。希望能帮助更多的初学者们快速入门!

      小伙伴们在批阅文章的过程中如果觉得文章对您有一丝丝帮助,还请别吝啬您手里的赞呀,大胆的把文章点亮👍吧,您的点赞三连(收藏⭐+关注👨‍🎓+留言📃)就是对bug菌我创作道路上最好的鼓励与支持😘。时光不弃🏃🏻‍♀️,创作不停💕,加油☘️

一、前言🔥

环境说明:Windows10 + Idea2021.3.2 + Jdk1.8 + SpringBoot 2.3.1.RELEASE

       经过前几期的由浅入深式的redis教学,想必你们也应该掌握的差不多了,现在我就来对这一块知识点进行一个大复盘,按照我的教学内容进度,我觉得你们应该要有如下能力,我先给大家一一罗列出来啊。

       你们对应自身的学习情况,看看还有那一块内容是自己没有掌握的,尽快查缺补漏,凡是学习期间有任何疑问,欢迎下方留言或者加我的扣扣交流群,我会想尽办法帮助大家,让大家能把我这块知识点消化掉。好吧?

通过这几期教学内容,我觉得你们应该要掌握的能力有一下几点:

  1. 能独立完成springboot框架集成redis等相关配置。
  2. 能独立实现test-case并进行redis类方法实例测试。
  3. 能独立操作redis客户端玩转redis基本命令。
  4. 能独立实现redis相关业务代码。
  5. 能独立代码实现短信验证码场景等完整逻辑。
  6. ...

       你们都对照下自己自身的学习情况,有任何不懂的及时提出来,不懂就问!好吧?

        ... ...

        其实啊,我上边所教学的都是基于redis的数据类型之一字符串(String)。所以我不能够让大家"发育不良"啦。

       接下来我再给大家重点介绍下redisd的其他几种数据类型吧。

二、redis常用数据类型

(1)String 

      这个其实没啥好说的,最常规的set/get操作,value可以是String也可以是数字。一般做一些复杂的计数功能的缓存。我上几期的内容教学,都是使用的String字符串。

我们再整体归纳一下,String型 redis命令操作:

  • set key value   表示:设置key对应string类型的值。设置成功返回ok,失败则error。

  • setnx key value   表示:如果key不存在,则设置key对应string类型的值。如果key已经存在,返回0

  • get key  表示:获取指定key的值,如果key不存在,则返回nil,若key存在,则返回值。

  • getset key value 表示:先获取key的值然后值覆盖,若key存在则返回旧值,若key不存在则返回nil。

  • mget key1key2 ... keyN  表示:一次性获取多个key的值,如果对应key不存在,则对应位置返回nil。若存在,则对应返回对应的key的值。

  • mset key1value1 ... keyN   表示:一次性设置多个key的值,如果对应key不存在,则返回ok,若存在,直接进行值覆盖。

  • ...

(2)hash 

       这里value存放的是结构化的对象,比较方便的就是操作其中的某个字段。博主在做单点登录的时候,就是用这种数据结构存储用户信息,以cookieId作为key,设置30分钟为缓存过期时间,能很好的模拟出类似session的效果。

我们再整体归纳一下,Hash型 redis命令操作:

  • hset keyfield value  表示:设置hash field为指定值,如果key不存在,则创建。

  • hget keyfield  表示:获取指定的hash field值。

  • hmget keyfiled1....fieldN   表示:获取全部指定的hash filed。

  • hmset keyfiled1 value1 ...... filedN valueN 表示:同时设置hash的多个field。

  • hincrbykey field integer 表示: 将指定的hashfiled 加上指定值。成功返回hashfiled变更后的值。

  • hexistskey field 表示:检测指定field是否存在。

  • hlen key 表示:返回指定hash的field数量。 hkeys key 返回hash的所有field。

  • hvals key 表示:返回hash的所有value。

  • hgetall 表示:返回hash的所有filed和value。

  • ...

(3)list 

       使用List的数据结构,可以做简单的消息队列的功能。另外还有一个就是,可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。

(4)set 

      因为set堆放的是一堆不重复值的集合。所以可以做全局去重的功能。为什么不用JVM自带的Set进行去重?因为我们的系统一般都是集群部署,使用JVM自带的Set,比较麻烦,难道为了一个做一个全局去重,再起一个公共服务,太麻烦了。 另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。

(5)sorted set

       sorted set多了一个权重参数score,集合中的元素能够按score进行排列。可以做排行榜应用,取TOP N操作。

       ...

       其实还有另外几种非常用的特殊数据类型,比如bitMap、Geospatial(地理位置)、HyperLogLog(基数统计).这个由于不是很常用,所以自行摸索哈。

... ...

       接下来,是这几期redis教学的所有核心源码,我都一滴不剩的展示给的大家,就是希望大家能从我教的内容中真正学到东西,我也毫无保留的把我所学尽可能详细的阐述给大家听,毕竟都是这么过来的,对吧,我帮大家,我有不会的同时也希望大家不吝赐教哦。

三、附完整演示代码

1、PhoneCodeBuilder.java

      如下是整个短信验证码场景实现代码:

package com.example.demo.component.redis.build;

import com.example.demo.component.redis.mediat.RedisMediator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 手机验证码组件
 * * @author luoYong
 * @version 1.0
 * @date 2022/1/21 14:06 
 */
@Component
public class PhoneCodeBuilder {
    @Autowired
    private RedisMediator redisMediator;

/**
 * 随机获取六位数字
 *
 * @return
 */
public String getCode() {
    int code = (int) ((Math.random() * 9 + 1) * 100000);
    return String.valueOf(code);
}

/**
 * 获取验证码,存入redis中并设置过期时间
 */
public void verifyCode(String phone) {

    //1、定义手机号、验证码标识
    String phoneKey = phone + "_count";
    String codeKey = phone + "_code";

    //2、每个号码只能发送三次
    String count = redisMediator.get(phoneKey);

    //3、从次数进行判断
    if (count == null) {

        //说明此号码第一次申请
        //插入phone标识,并设置过期时间
        redisMediator.set(phoneKey, "1", Long.valueOf(24 * 60 * 60));
    } else if (Integer.parseInt(count) <= 2) {

        //获取当前用户验证码剩余时间
        long keyExpirationTime = redisMediator.getKeyExpirationTime(phoneKey);
        System.out.println("keyExpirationTime:" + keyExpirationTime);
        //获取当前次数
        String codeCount = redisMediator.get(phoneKey);
        //次数+1
        int newCount = Integer.parseInt(codeCount) + 1;
        redisMediator.set(phoneKey, String.valueOf(newCount), keyExpirationTime);
    } else {

        //当天3次机会用完了
        System.out.println("当天3次机会用完了!请明日再试");
        return;
    }
    //获取随机6位验证码
    String code = this.getCode();
    //验证码存入redis并设置过期时间(2min)
    redisMediator.set(codeKey, code, Long.valueOf(2 * 60));
}

/**
 * 校验验证码是否有效
 */
public boolean checkCode(String phone, String code) {
    String codeKey = phone + "_code";
    String redisCode = redisMediator.get(codeKey);
    if (code.equals(redisCode)) {
        return true;
    }
    return false;
}

2、RedisMediator.java

       如下是封装的一些对redis进行操作的方法类。大家自行进行新增,需要就加在里头即可。

package com.example.demo.component.redis;

import com.example.demo.util.JsonUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Redis中介类,用于从redis中读取内容或者更新数据
 *
 * @Author luoYong
 * @Date 2022-01-20 17:47
 */
@Slf4j
@Component
public class RedisMediator {

   @Resource
   private StringRedisTemplate stringRedisTemplate;

   @Value("${luoyong.redis.login-time-out:1800}")
   private Integer timeOut;

   /**
    * 普通缓存放入
    *
    * @param key   键
    * @param value 值
    */
   public void set(String key, String value) {
      set(key, value, timeOut);
   }

   /**
    * 普通缓存放入并设置时间
    *
    * @param key   键
    * @param value 值 String
    * @param time  过期时间
    */
   public void set(String key, String value, long time) {
      this.checkKey(key);
      stringRedisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
   }

   /**
    * 普通缓存获取
    *
    * @param key 键
    */
   public String get(String key) {
      this.checkKey(key);
      return stringRedisTemplate.opsForValue().get(key);
   }

   /**
    * 判断key是否存在
    *
    * @param key 键
    * @return true 存在 false不存在
    */
   public boolean hasKey(String key) {
      this.checkKey(key);
      return stringRedisTemplate.hasKey(key);
   }

   /**
    * 删除缓存
    *
    * @param key 健
    */
   public void del(String key) {
      this.checkKey(key);
      stringRedisTemplate.delete(key);
   }

   /**
    * 刷新缓存时间
    *
    * @param key
    */
   public Boolean expire(String key) {
      return this.expire(key, timeOut);
   }

   /**
    * 指定缓存失效时间
    * 
    * @param key  键
    * @param time 时间(秒)
    * @return
    */
   public Boolean expire(String key, long time) {
      return stringRedisTemplate.expire(key, time, TimeUnit.SECONDS);
   }

   /**
    * 检查key是否为空
    *
    * @param key 健
    */
   private void checkKey(String key) {
      if (StringUtils.isBlank(key)) {
         throw new RuntimeException("redis key不能为空");
      }
   }
/**
 * 获取key的过期时间
 */
public long getKeyExpirationTime(String key){
   this.checkKey(key);
   return stringRedisTemplate.getExpire(key);
}}

3、PhoneCodeBuilderTest.java

       如下是对手机号验证码功能的测试样例,大家可以参考一下:自己也可以封装自己想要测试的数据,这个随大家,开心就行。

package com.example.demo.component.redis.build;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class PhoneCodeBuilderTest {

    @Autowired
    private PhoneCodeBuilder phoneCodeBuilder;

    @Test
    void testGetCode(){
        String code = phoneCodeBuilder.getCode();
        System.out.println(code);
    }

    @Test
    void testVerifyCode(){
       phoneCodeBuilder.verifyCode("10010");
    }
}

4、RedisMediator.java

       如下是对redis工具类的一些常用方法的测试用例,大家可以借鉴一下:同样,还有自己新增的一些工具类,大家也记得进行测试用例测试哦,别到时候拍上用场的时候,直接当场社死,毕竟没上过测试的代码,都不敢确保百分百一定没有问题,这点大家还是需要严谨一些。

package com.example.demo.component.redis.mediat;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RedisTest {

    @Autowired
    private RedisMediator redisMediator;
    /**
     * 插入一个key
     */
    @Test
    void testSetKey() {
        redisMediator.set("name", "diaochan");
    }

    @Test
    void testHasKey() {
        boolean has = redisMediator.hasKey("name");
        System.out.println("是否存在:" + has);
    }

    /**
     * 获取一个key
     */
    @Test
    void testGetKey() {
        String name = redisMediator.get("name");
        System.out.println("获取到的name对于的值为:" + name);
    }

    /**
     * 指定缓存失效时间(秒)
     */
    @Test
    void testExpireKey() {
        redisMediator.expire("name", 3600);
    }

    /**
     * 删除一个key
     */
    @Test
    void testDelKey() {
        redisMediator.del("name");
    }
}

        好啦,redis的零基础入门,就止步于此啦!核心源码我都给大家了,大家可千万别辜负了bug菌的一片良苦用心啊。

        俗话也说师傅带进门,修行靠个人,后边还有很多跟redis相关的知识点,像什么redis主从复制、redis的哨兵模式、redis的淘汰策略、redis持久化等等,这些都是日后需要大家自己慢慢摸索的,慢慢来吧,一起学习。谁都是从不会到会的,一点一滴积累,一定可以啃完吃透的哦,加油喔!我们都是最棒的。

... ...

       OK,以上就是这期所有的内容啦,如果有任何问题欢迎评论区批评指正,咱们下期见。

四、往期热门推荐

文末🔥

       如果还想要学习更多,小伙伴们可关注bug菌专门为大家创建的专栏《springboot零基础入门教学》,从无到有,从零到一!希望能帮助到更多小伙伴们。

我是bug菌,一名想走👣出大山改变命运的程序猿。接下来的路还很长,都等待着我们去突破、去挑战。来吧,小伙伴们,我们一起加油!未来皆可期,fighting!

感谢认真读完我博客的铁子萌,在这里呢送给大家一句话,不管你是在职还是在读,绝对终身受用。
时刻警醒自己:
抱怨没有用,一切靠自己;
想要过更好的生活,那就要逼着自己变的更强,生活加油!!!