当前位置: 首页 > article >正文

Redis快速入门店铺营业状态设置

Redis简介

        Redis是一种基于内存的键值对(K-V)数据库。
        这意味着它与MySQL数据库类似,都能够用于存储数据,但两者又有着本质的区别。首先两者存储数据的结构不一样,Redis通过键(key)和值(value)的映射来存储信息,其中键是唯一的标识,而值可以是灵活多样的数据结构,如字符串、列表、集合等。MySQL则采用二维表的结构来组织数据,这种结构更适合复杂的关系型数据存储。
        其次两者的存储介质不同,Redis将其数据存储在内存中,这种内存存储机制使得Redis在数据读写操作上远超基于磁盘存储的MySQL。而MySQL则将数据以文件形式存储在硬盘上,虽然这为数据持久化提供了保障,但在性能上自然无法与内存中的Redis相提并论。

        简而言之,Redis的内存存储与MySQL的磁盘存储,分别代表了性能与持久性的两种不同选择。因此两者虽都是数据库,但并不意味着能取代对方,两者互相搭配使用才合适。由于Redis存储在内存中,所以能够提供极快的访问速度,读写性能较高,但又因为内存的空间较为宝贵,所以只适合存储一些访问频率较高的数据。

Redis官网icon-default.png?t=O83Ahttps://redis.ioRedis中文网icon-default.png?t=O83Ahttps://www.redis.net.cn/

下载与安装

        下载Redis的Windows版,该版本属于绿色软件,直接解压就可使用,解压后有几个比较重要的文件:

  • redis.windows.conf:Redis配置文件—修改端口、密码等
  • redis-cli.exe:Redis客户端—连接到Redis服务
  • redis-server.exe:Redis服务端—服务端启动命令

        我们先来介绍如何通过CMD窗口操作Redis(仅供了解)

        通过CMD窗口启动须在当前目录的路径框中输入cmd:

        然后输入"redis-server.exe redis.windows.conf"(注意中间有一个空格) 显示对应页面即为启动成功,页面显示其默认端口号为6379:

        停止该服务在CDM窗口按下ctrl+c即可。我们在服务开启的前提下再使用同样的方法打开一个新的CMD窗口,然后输入redis-cli.exe客户端即可连接到本地的Redis服务器。我们也可以输入key *来验证是否连接成功:

        此时就已连接到了本地的服务器,连接外部的服务器也大差不差,我们先输入exit退出当前连接,然后输入"redis-cli -h 主机地址 -p 端口号 -a 密码"即可,我们可以使用本地服务器代替:redis-cli -h localhost -p 6379,同样可以输入key *来验证是否连接成功。

        可以注意到此时本地的redis服务器并无密码,我们可以先停止redis服务,然后到redis.windows.conf文件中搜索requirepass,修改"# requirepass foobared"为"requirepass 密码",保存即可(学习时推荐使用123456)。

        接下来下载Redis 可视化工具:Another Redis Desktop Manager github

        该可视化工具为免费的开源项目,页面非常简洁美观,基本的功能都有,支持多平台、监控统计、页面主题、集群、搜索,分组显示,多选操作。下面是Github和Gitee的下载网址

https://github.com/qishibo/AnotherRedisDesktopManager/releasesicon-default.png?t=O83Ahttp://xn--github-np7ii83deeq211d

https://gitee.com/qishibo/AnotherRedisDesktopManager/releasesicon-default.png?t=O83Ahttp://xn--gitee-gi1hh06cxd9647c        启动后输入相关信息,在启动Redis数据库的前提下,页面显示如下即为连接成功:

Redis数据类型

        上文介绍过Redis通过键(key)和值(value)的映射来存储信息,其中键(key)为string类型,值(value)则有5种常用的数据类型,分别是:

一、字符串string
        普通字符串,Redis中最简单的数据类型。它可以包含任何数据,如文本、数字或图片等。

二、哈希hash
        也叫散列,类似于java中的HashMap结构。
        注意是在value中存储K-V的数据,整体结构为K-(K-V)。例如key为user,value为(name=aaa,password=aaa......)。

三、列表list
        按照插入的顺序排序,可以有重复元素,类似于java中的LinkedList(双向链表)。

四、集合set
        无序集合,没有重复元素,类似于java中的HashSet,常用于好友列表。

五、有序集合sorted set/zset
        集合中每个元素都关联一个分数(score),根据分数升降排序,没有重复元素。

Redis常用命令

        我们可以通过这些命令来操作Redis中的数据。但其与MySQL中操作数据不同,操作Redis需要根据数据类型的不同执行不同的命令,同时Redis和MySQL一样是不区分大小写的。接下来我们来看五种类型的常用命令:

一、字符串操作命令

  • SET key value:设置指定key的值
  • GET key:获取指定key的值
  • SETEX key seconds value:设置指定key的值,并将key的过期时间设为seconds秒
  • SETNX key value:只有在key不存在时设置key的值

        接下来我们来练习如何使用这些命令,打开刚刚已配置好的图形界面,点击左上角的打开Redis控制台,即可在右下方的输入框输入命令set name jack并回车,上方就会显示已执行过的命令与"OK"字样,左侧显示已存在的Key的值,点击该Key即可在右侧新标签页查看Value的信息,包括类型、值等。

> test connected!  # 测试连接成功
> set name jack    # 设置键"name"的值为"jack"
OK
> get name         # 获取键"name"的值
jack
> get aaa          # 尝试获取不存在的键"aaa",返回null
null
> SETEX code 30 mycode  # 设置键"code"的值为"mycode",并设置过期时间为30秒
OK
> get code         # 获取键"code"的值,此时还未过期
mycode
> get code         # 再次获取键"code"的值,此时可能已经过期,返回null
null
> SETNX name aaaa  # 尝试设置键"name"的值为"aaaa",如果"name"已存在则不设置,返回0表示失败
0
> SETNX name1 aaaa # 尝试设置键"name1"的值为"aaaa",因为"name1"不存在,设置成功,返回1
1

         如果添加的key在左侧不显示,可以点击控制台旁边的刷新按钮即可。在value值标签页中,包含了key的值、value的类型、value的值、value的过期时间等信息。

 

二、哈希操作命令

        Redis hash 是一个 string 类型的 field 和 value 的映射表, hash 特别适合用于存储对象, 整体结构为K-(K-V):

        常用命令:

  • HSET key field aaaa:将哈希表 key 中的字段 field 的值设置为指定的值
  • HGET key field:获取存储在哈希表中指定字段的值
  • HDEL key field:删除存储在哈希表中的指定字段
  • HKEYS key:获取哈希表中所有字段
  • HVALS key:获取哈希表中所有值
> hset user name jack # 在哈希表"user"中设置字段"name"的值为"jack",如果字段不存在则创建,返回1表示成功
1
> hset user age 22 # 在哈希表"user"中设置字段"age"的值为"22",如果字段不存在则创建,返回1表示成功
1
> hget user name # 获取哈希表"user"中字段"name"的值
jack
> hdel user age # 删除哈希表"user"中的字段"age",如果字段存在则删除,返回1表示成功
1
> hset user age 22 # 再次在哈希表"user"中设置字段"age"的值为"22",因为字段已被删除,这里重新创建字段
1
> hkeys user # 获取哈希表"user"中所有的字段名
name
age
> hvals user # 获取哈希表"user"中所有的字段值
jack
22

三、列表操作命令

        Redis列表是简单的字符串列表,按照插入顺序排序,基本结构为:

        列表操作命令大多分类R和L两个版本,R意为right,L意为left。为这些数据生成的索引也是从0开始的。常用命令:

  • LPUSH key value1 [value2]:将一个或多个值插入到列表头部([]意为可选),多个元素直接以空格分开。其结构类似于栈,先插入的在尾部
  • LRANGE key start stop:获取列表指定范围内的元素,start和stop均为value的索引,后插入的value索引值小。
  • RPOP key:移除并获取列表最后一个元素
  • LLEN key 获取列表长度
> lpush mylist a b c  # 将字符串 'a', 'b', 'c' 依次推入列表 mylist 的头部,返回列表的长度,此时列表为 [c, b, a]
3                       # 列表操作后长度为 3
> lpush mylist d       # 将字符串 'd' 推入列表 mylist 的头部,返回列表的长度,此时列表为 [d, c, b, a]
4                       # 列表操作后长度为 4
> lrange mylist 0 -1   # 获取列表 mylist 从索引 0 到最后一个元素(-1 表示最后一个元素),即获取整个列表
d
c
b
a                      # 列表元素依次为 'd', 'c', 'b', 'a'
> lrange mylist 1 3    # 获取列表 mylist 从索引 1 到索引 3 的元素,但不包括索引 3 的元素
c
b
a                      # 列表元素依次为 'c', 'b', 'a'
> rpop mylist          # 移除列表 mylist 的最后一个元素,并返回该元素的值,此时列表最后一个元素 'a' 被移除
a                      # 移除的元素是 'a'
> llen mylist          # 获取列表 mylist 的长度
3                      # 列表操作后长度为 3,此时列表为 [d, c, b]

四、集合操作命令

        Redis set 是string类型的无序集合。 集合成员是唯一的, 集合中不能出现重复的数据。因为其是无序的,所以实际存储顺序可能和插入顺序不一致。常用命令:

  • SADD key member1 [member2]:向集合添加一个或多个成员
  • SMEMBERS key:返回集合中的所有成员,
  • SCARD key:获取集合的成员数
  • SINTER key1 [key2]:返回给定所有集合的交集
  • SUNION key1 [key2]:返回所有给定集合的并集
  • SREM key member1 [member2]:删除集合中的一个或多个成员
# 向集合 setkey 添加元素 'a', 'b', 'c', 'd',并返回成功添加的元素数量
sadd setkey a b c d
4 # 表示有4个元素被成功添加到集合中
# 尝试再次向集合 setkey 添加元素 'a',但由于 'a' 已存在,不会重复添加,返回0
sadd setkey a
0 # 表示没有元素被添加,因为 'a' 已经在集合中
# 获取并显示集合 setkey 中的所有成员
smembers setkey
c
b
d
a # 显示集合中的所有元素,注意集合是无序的
# 获取集合 setkey 的基数,即集合中元素的数量
SCARD setkey
4 # 集合 setkey 中有4个元素
# 向集合 setkey2 添加元素 'a', 'b', 'x', 'y',并返回成功添加的元素数量
sadd setkey2 a b x y
4 # 表示有4个元素被成功添加到集合 setkey2 中
# 获取集合 setkey 和 setkey2 的交集,即两个集合共有的元素
sinter setkey setkey2
b
a # 显示集合 setkey 和 setkey2 的交集元素
# 获取集合 setkey 和 setkey2 的并集,即两个集合中所有的元素,重复的只计算一次
sunion setkey setkey2
c
x
a
d
b
y # 显示集合 setkey 和 setkey2 的并集元素
# 从集合 setkey2 中移除元素 'a',并返回成功移除的元素数量
srem setkey2 a
1 # 表示成功移除了1个元素 'a'

         实际存储顺序可能和插入顺序不一致:

五、有序集合操作命令

        Redis有序集合是string类型元素的集合,且不允许有重复成员。每个元素都会关联一个double类型的分数。常用命令:

  • ZADD key score1 member1 [score2 member2]:向有序集合添加一个或多个成员
  • ZRANGE key start stop [WITHSCORES]:通过索引区间返回有序集合中指定区间的成员,添加WITHSCORES表示将分数也一起返回
  • ZINCRBY key increment member:对指定成员的分数增加increment
  • ZREM key member [member…]:移除有序集合中的一个或多个成员
# 向有序集合 zset 添加三个成员及其分数
# 成员 'a' 的分数是 10.0,成员 'b' 的分数是 10.2,成员 'c' 的分数是 10.5
# 返回值 3 表示成功添加了三个成员
ZADD zset 10.0 a 10.2 b 10.5 c
3

# 获取有序集合 zset 中所有成员及其分数,从索引 0 到最后一个成员
# withscores 参数表示输出结果中包含每个成员的分数
# 输出结果按照分数从小到大排序
ZRANGE zset 0 -1 withscores
a
10
b
10.199999999999999
c
10.5

# 将有序集合 zset 中成员 'a' 的分数增加 0.1
# 返回值是成员 'a' 增加后的新分数
ZINCRBY zset 0.1 a
10.1

# 获取有序集合 zset 中成员 'c' 的倒序排名(从分数最高到最低)
# 返回值 0 表示 'c' 是分数最高的成员
ZREVRANK zset c
0

# 从有序集合 zset 中移除成员 'c'
# 返回值 1 表示成功移除了一个成员
ZREM zset c
1

六、通用命令

        Redis的通用命令是不分数据类型的,都可以使用的命令:

  • KEYS pattern:查找所有符合给定模式(pattern)的key,pattern可以是"*"、""、""、""。
  • EXISTS key:检查给定key是否存在
  • TYPE key:返回key所储存的值的类型
  • DEL key:该命令用于在key存在是删除key
> keys *    # 列出所有以任意字符开头的键
zset
name1
user   
setkey2   
name   
setkey   
mylist

> keys set* # 列出所有以"set"开头的键
setkey2   
setkey    

> EXISTS user   # 检查键"user"是否存在,1表示存在
1

> EXISTS user1  # 检查键"user1"是否存在,0表示不存在
0

> TYPE mylist   # 查询键"mylist"的数据类型,返回"list"表示它是一个列表
list

> DEL mylist    # 删除键"mylist"及其值,返回1表示删除成功
1

使用Redis

        通过上述的命令,我们就可以操作Redis中的数据,但最终我们需要为项目服务,也就是说需要在java程序中操作Redis。

Redis的java客户端

        Redis的java客户端有很多,常用的有

一、 Jedis
        Jedis是一个简单而强大的Java客户端,用于与Redis进行通信。它提供了完整的Redis命令的API,并支持连接池管理。Jedis使用直接连接到Redis服务器的方式,是Redis的原生Java客户端之一。

二、 Lettuce
        Lettuce是一个高性能的Redis客户端,基于Netty框架实现。它使用异步和反应式编程模型,可以更有效地利用网络资源。

三、Spring Data Redis

        Spring Data Redis是Spring的一部分,对Redis底层开发包(Jedis和Lettuce)进行了高度封装。在Spring项目中,可以使用Spring Data Redis来简化操作。

idea使用Redis准备事项

        总计需要四步

一、导入Spring Data Redis 的maven坐标

        打开idea中原有的项目,原有代码已经在server模块的pom.xml中预先添加了,我们检查是否正确即可:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

二、配置Redis数据源

        之前在创建Redis数据库时,系统总计创建了从0-15总计16个数据库,每个数据库之间的数据都是相互隔离的,我们之前使用的都是默认的0号数据库。

        idea中同理,默认使用0号数据库,如需指定则需配置spring.redis.database:10,代表想要使用10号数据库。

        同样,我们不推荐使用硬编码的方式配置数据库信息,因此我们选择先在application-dev.yml中配置数据库信息,然后引用其信息。在server模块的application.yml和application-dev.yml中添加属性:

————application-dev.yml————————————————————————————
sky:
......
  redis: # Spring Boot 配置Redis属性
    host: localhost       # Redis服务器地址
    port: 6379            # Redis服务器端口
    password: 123456      # Redis服务器密码
    database: 10           # 选择哪个数据库,默认为0
————application.yml————————————————————————————————
spring:
......
  redis:
    host: ${sky.redis.host}
    port: ${sky.redis.port}
    password: ${sky.redis.password}
    database: ${sky.redis.database}

三、编写配置类,创建RedisTemplate对象

        在server模块的config包下新建RedisConfiguration类,并添加注解@Configuration将其作为配置类,然后新建一方法返回类型为RedisTemplate,在方法上加入注解@Bean并在该方法的参数中注入RedisConnectionFactory实例。
        再在方法体中新建RedisTemplate类的实例,编写对应代码以完成设置Redis连接工厂对象和设置Redis key的序列化器两任务,最后返回RedisTemplate类的实例。

@Configuration
@Slf4j
public class RedisConfiguration {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        log.info("开始创建Redis模板对象");
        RedisTemplate redisTemplate = new RedisTemplate();
        //设置Redis连接工厂对象
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //设置Redis key的序列化器
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    };
}

四、通过RedisTemplate对象操作Redis

        我们可以先调用测试方法来测试RedisTemplate对象是否能够成功创建,在server模块下的test-java包中新建与启动类一致的目录层级:com.sky.test.SpringDataRedisTest,然后添加相关注解并注入RedisTemplate:

@SpringBootTest
public class SpringDataRedisTest {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testRedis() {
        System.out.println(redisTemplate);
    }
}

        如果测试通过即代码 RedisTemplate对象可以被成功创建:

        后续操作Redis都会使用到注入的RedisTemplate对象redisTemplate。之前介绍过Redis中的五种数据类型,每种数据类型的操作命令都不同, 在redisTemplate也封装了五个接口用于操作对应的数据:

@Test
public void testRedis() {
    // 打印redisTemplate实例,用于确认Redis模板是否已经成功注入
    System.out.println(redisTemplate);
    // 获取ValueOperations对象,用于执行Redis字符串类型的操作
    ValueOperations<String, String> valueOperations = redisTemplate.opsForValue();
    // 获取HashOperations对象,用于执行Redis哈希表类型的操作
    HashOperations<String, String, String> hashOperations = redisTemplate.opsForHash();
    // 获取ListOperations对象,用于执行Redis列表类型的操作
    ListOperations<String, String> listOperations = redisTemplate.opsForList();
    // 获取SetOperations对象,用于执行Redis集合类型的操作
    SetOperations<String, String> setOperations = redisTemplate.opsForSet();
    // 获取ZSetOperations对象,用于执行Redis有序集合类型的操作
    ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();
}

        接下来学习如何在java程序中通过Spring Data Redis来操作Redis当中的数据。

Idea使用Redis

        其同样根据类型的不同,操作方法也不同。先来看如何操作Redis中字符串类的数据。

一、字符串操作命令

        其虽在Redis中保存的类型为字符串,但与java中的String仍略有不同,因此在idea中可将其视为Object类来操作,也就是说可以传入任何数据,系统会将其转为Redis的String类型再存入数据库。同理,其返回值也是Object类型,想要使用String类型接收则需强转。

        上文介绍给字符串类型的常用操作命令共有四个SET、GET、SETEX、SETNX,其在java程序中也有着对应的方法。两者之间有一定相似,但又大有不同。
        我们着重介绍SETEX命令对应的方法,也就是指定key在指定时间后过期的方法。该方法前两个参数同样为key和value,第三个参数表示键值对的过期时间,即这个键值对将在X个时间单位后过期。第四个参数,是一个枚举类型,用于指定过期时间的单位。在这个例子中,TimeUnit.MINUTES表示过期时间的单位是分钟,即key2会在三分钟后过期。

@SpringBootTest
public class SpringDataRedisTest {
    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testString() {
        // 打印redisTemplate的引用,主要用于调试查看是否注入成功
        System.out.println(redisTemplate);

        // 使用ValueOperations设置一个键值对,键为"key1",值为"value1"
        redisTemplate.opsForValue().set("key1", "value1");

        // 从Redis中获取键为"key1"的值,并将其转换为String类型
        String key1 = (String) redisTemplate.opsForValue().get("key1");
        System.out.println(key1);

        // 设置一个带有过期时间的键值对,键为"key2",值为"value2",过期时间为3分钟
        redisTemplate.opsForValue().set("key2", "value2", 3, TimeUnit.MINUTES);

        // 使用setIfAbsent方法尝试设置键值对,只有当键不存在时才会设置成功
        // 如果"key3"不存在,则设置"key3"的值为"value3"
        redisTemplate.opsForValue().setIfAbsent("key3", "value3");

        // 再次尝试设置"key3",由于"key3"已经存在,这个操作不会改变"key3"的值
        redisTemplate.opsForValue().setIfAbsent("key3", "value3");
    }
}

        同时在图形工具中我们可以看到,key的值与idea中设置的值一致,但value却是"乱码",这是因为在RedisConfiguration类中我们使用语句

redisTemplate.setKeySerializer(new StringRedisSerializer());

设置了Redis key的序列化器,如果将该语句注释掉,系统会使用默认的序列化器,key的值也会变为乱码。

二、哈希操作命令

        哈希常用的操作命令有五个HSET、HGET key field、HDEL key field、HKEYS key、HVALS key。

    @Test
    public void testHashOperations() {
        // 获取哈希操作对象,用于执行哈希相关的Redis命令
        HashOperations<String, Object, Object> hashOperations = redisTemplate.opsForHash();

        // 将键值对存入哈希表,其中"user"是哈希表的键,"username"是字段,"jack"是值
        hashOperations.put("user", "username", "jack");
        // 将另一个键值对存入同一个哈希表,"age"是字段,"32"是值
        hashOperations.put("user", "age", "32");

        // 从哈希表中获取字段"username"的值
        String name = (String) hashOperations.get("user", "username");
        // 打印获取到的用户名
        System.out.println(name); // 应该输出 "jack"

        // 获取哈希表"user"中所有的字段
        Set<Object> keys = hashOperations.keys("user");
        // 打印所有字段
        System.out.println(keys); // 应该输出包含 "username" 和 "age" 的集合

        // 获取哈希表"user"中所有的值
        List<Object> values = hashOperations.values("user");
        // 打印所有值
        System.out.println(values); // 应该输出包含 "jack" 和 "32" 的列表

        // 从哈希表中删除字段"username"
        hashOperations.delete("user", "username");
        // 此时,哈希表"user"中应该只剩下字段"age"和它的值"32"
    }

三、列表操作命令

        其大致相同,不再赘述,直接看代码:

@Test
public void testList(){
    //之前学习的方法:lpush lrange rpop llen
    // 获取操作列表类型的对象
    ListOperations listOperations = redisTemplate.opsForList();
    
    // 将多个元素从左边插入到列表中
    listOperations.leftPushAll("mylist","a", "b", "c");
    // 再将一个元素从左边插入到列表中
    listOperations.leftPush("mylist", "d");
    
    // 获取列表的所有元素
    List myList = listOperations.range("mylist", 0, -1);
    System.out.println(myList);
    
    // 从右边弹出列表中的一个元素
    listOperations.rightPop("mylist");
    
    // 获取列表的大小
    Long size = listOperations.size("mylist");
    System.out.println(size);
}

四、集合操作命令 

@Test
public void testSet() {
    //sadd smembers scard sinter sunion srem

    // 创建一个用于集合操作的实例
    SetOperations<String, String> setOperations = redisTemplate.opsForSet();
    
    // 向集合set1添加元素 a, b, c, d
    setOperations.add("set1", "a", "b", "c", "d");
    
    // 向集合set2添加元素 a, b, x, y
    setOperations.add("set2", "a", "b", "x", "y");
    
    // 获取集合set1的所有成员
    Set<String> members = setOperations.members("set1");
    System.out.println(members);
    
    // 获取集合set1的大小
    Long size = setOperations.size("set1");
    System.out.println(size);
    
    // 计算集合set1和set2的交集
    Set<String> intersect = setOperations.intersect("set1", "set2");
    System.out.println(intersect);
    
    // 计算集合set1和set2的并集
    Set<String> union = setOperations.union("set1", "set2");
    System.out.println(union);
    
    // 从集合set1中移除元素 a 和 b
    setOperations.remove("set1", "a", "b");
}
//控制台输出
[d, c, b, a]
4
[b, a]
[x, d, a, c, b, y]

 

五、有序集合操作命令

    @Test
    public void testZset() {
        //zadd zrange zincrby zrem

        // 获取有序集合操作实例
        ZSetOperations<String, String> zSetOperations = redisTemplate.opsForZSet();

        // 向有序集合添加元素及其分数
        zSetOperations.add("zset1", "a", 10);
        zSetOperations.add("zset1", "b", 12);
        zSetOperations.add("zset1", "c", 9);

        // 获取有序集合中的所有元素
        Set<String> zset1 = zSetOperations.range("zset1", 0, -1);
        System.out.println(zset1);

        // 增加元素c的分数
        zSetOperations.incrementScore("zset1", "c", 10);

        // 从有序集合中移除元素a和b
        zSetOperations.remove("zset1", "a", "b");
    }

六、通用命令

        上述命令操作前,都需先获取对应的Operations对象然后再进行操作,但通用命令可直接通过RedisTemplate类的实例redisTemplate来操作。

    @Test
    public void testCommon() {
        //keys exists type del

        // 获取所有键
        Set keys = redisTemplate.keys("*");
        System.out.println(keys);

        // 检查特定键是否存在
        Boolean nameExists = redisTemplate.hasKey("name");
        Boolean set1Exists = redisTemplate.hasKey("set1");

        // 遍历所有键并打印其数据类型
        for (Object key : keys) {
            DataType dataType = redisTemplate.type(key);
            System.out.println(dataType.name());
        }

        // 删除指定键
        redisTemplate.delete("mylist");
    }
//控制台输出
[set2, mylist, set1, key3, user, zset1, key1]
SET
LIST
SET
STRING
HASH
ZSET
STRING

        此时各功能均已简单介绍,因此测试各功能是在测试类中进行的, 在苍穹外卖项目中并不需要该测试类及其内部的方法,为避免测试类拖慢项目启动速度,我们可以将测试类上方的@SpringBootTest注释掉。

店铺营业状态设置

        店铺左上角有一营业信息表示是否营业,点击右上角的营业状态设置可修改营业信息。
        当前餐厅处于营业状态时,当前餐厅处于打烊状态时,仅接受营业时间内的预定订单,可点击营业中手动恢复营业状态。

        接下来分析所需的接口,首先是左上角查询营业信息需要一个查询接口,同时不仅商家需要查询是否营业的接口,用户的小程序也需类似的接口,从技术层面来说两者可共用一个接口,但在该项目中为了规范请求路径(管理端发出的请求统一使用/admin作为前缀、用户端发出的请求统一使用/user作为前缀),我们选择将其设计为两个不同的接口。

        分析所需接口,首先上文提到的"管理端查询营业状态"、"用户端查询营业状态两接口",然后是设置营业状态所需的接口,我们依次来看。

设置营业状态

        首先是设置营业状态,营业状态的值可通过多种方式传到后端:url地址、请求体、路径参数,在本项目我们选择通过路径参数传递值。

        请求路径/admin/shop/{status},请求方法put,传递的值为1则表示营业,0为打烊。

        存储营业信息的数据表只需一个字段表示状态,且只需要一列数据用于存储0或1,为了存储这一数据来单独新开一个MySQL表不合理,因此我们选择将其存储到Redis数据库中,选择基于Redis的字符串来进行存储。

@RestController
@RequestMapping("/admin/shop")
@Api(tags = "店铺相关接口")
@Slf4j
public class ShopControlller {

    public static final String KEY = "SHOP_STATUS"; // 定义一个常量,用于Redis中存储店铺状态的键名
    @Autowired // 自动注入RedisTemplate实例,用于操作Redis
    private RedisTemplate redisTemplate;

    @PutMapping("/{status}")
    @ApiOperation("设置店铺的营业状态")
    public Result setStatus(@PathVariable Integer status) { // 接收路径变量status作为方法参数
        log.info("设置店铺的营业状态为:{}", status == 1 ? "营业中" : "打烊中");
        redisTemplate.opsForValue().set(KEY, status); // 将店铺状态存储到Redis中,使用定义的KEY作为键
        return Result.success();
    }
}

管理端查询营业状态

        请求路径/admin/shop/status,请求方法get。

    @GetMapping("/status")
    @ApiOperation("获取店铺营业状态") // 使用@ApiOperation注解描述该接口的功能,即获取店铺的营业状态
    public Result<Integer> getStatus() { // 定义一个返回类型为Result<Integer>的方法
        Integer shopStatus = (Integer) redisTemplate.opsForValue().get(KEY); // 从Redis中获取店铺状态
        log.info("获取到的店铺营业状态为:{}", shopStatus == 1 ? "营业中" : "打烊中"); // 记录日志,输出获取到的店铺状态
        return Result.success(shopStatus); // 返回包含店铺状态的Result对象
    }

用户端查询营业状态

        请求路径/user/shop/status,请求方法get。因为该功能为用户端的功能,为和管理端区分,我们需新建一个user包用于保存相关代码

        然后将admin包的ShopController类复制到该包下并修改相关信息,再删除修改营业状态的信息。由于两包中的类名称一致,导致其生成的bean名称也一致,同时放到IOC容器中会发生冲突,因此需手动为两类指定bean的名称,分别修改两类的注解为@RestController("userShopController")和@RestController("adminShopController")。

@RestController("userShopController")
@RequestMapping("/user/shop")
@Api(tags = "用户相关接口")
@Slf4j
public class ShopController {
    public static final String KEY="SHOP_STATUS";

    @Autowired // 自动注入RedisTemplate实例
    private RedisTemplate redisTemplate;

    @GetMapping("/status")
    @ApiOperation("获取店铺营业状态") // 使用@ApiOperation注解描述该接口的功能,即获取店铺的营业状态
    public Result<Integer> getStatus() { // 定义一个返回类型为Result<Integer>的方法
        Integer shopStatus = (Integer) redisTemplate.opsForValue().get(KEY); // 从Redis中获取店铺状态
        log.info("获取到的店铺营业状态为:{}", shopStatus == 1 ? "营业中" : "打烊中"); // 记录日志,输出获取到的店铺状态
        return Result.success(shopStatus); // 返回包含店铺状态的Result对象
    }
}

        代码已完成,开始测试,测试前先删除Redis数据库中的数据,点击对应图标并输入"yes"可快速删除所有数据:

 

 

        此时无论是管理端接口还是用户端接口都在同一个接口文档下,不便管理,我们可以修改用于生成接口文档的server模块config包WebMvcConfiguration类的docket(),修改接口文档需要扫描的包,使其只扫描管理端接口。
        再新建一个Docket类方法用于生成用户端接口的接口文档,并通过.groupName()方法,传入字符串来指定接口:

    @Bean
    public Docket adminDocket() {
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档title")
                .version("2.0")
                .description("苍穹外卖项目接口文档desc")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .groupName("管理端接口")
                .apiInfo(apiInfo)
                .select()
                //指定接口文档需要扫描的包
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller.admin"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

    /**
     * 用户端接口文档
     * @return
     */
    @Bean
    public Docket userDocket() {
        ApiInfo apiInfo = new ApiInfoBuilder()
                .title("苍穹外卖项目接口文档title")
                .version("2.0")
                .description("苍穹外卖项目接口文档desc")
                .build();
        Docket docket = new Docket(DocumentationType.SWAGGER_2)
                .groupName("用户端接口")
                .apiInfo(apiInfo)
                .select()
                //指定接口文档需要扫描的包
                .apis(RequestHandlerSelectors.basePackage("com.sky.controller.user"))
                .paths(PathSelectors.any())
                .build();
        return docket;
    }

        此时在接口文档页面就可以通过下拉列表区分不同的接口文档:


http://www.kler.cn/a/504127.html

相关文章:

  • 【make】makefile 函数全解
  • Vue Diff 算法完全解析
  • 73.矩阵置零 python
  • Java-数据结构-栈与队列(常考面试题与单调栈)
  • 2 XDMA IP中断
  • 非PHP开源内容管理系统(CMS)一览
  • px、em 和 rem 的区别:深入理解 CSS 中的单位
  • 【ArcGIS初学】产生随机点计算混淆矩阵
  • 【树莓派3B】香瓜树莓派3B之语音识别机器人
  • 2025年  生活公报计划
  • 见微知著:Tripo 开创 3D 生成新时代
  • 无人机反制设备十大应用场景详解
  • 什么是IDE,新手如何选择IDE?
  • 宝塔面板 php8.0 安装 fileinfo 拓展失败
  • 解决“无法定位程序输入点 av_buffer_create 于动态链接库 XXX\Obsidian.exe 上”问题
  • electron 打包后的 exe 文件,运行后是空白窗口
  • 开源工作管理解决方案tillywork
  • IO流相关概念
  • 使用 LLaMA-Factory 微调大模型
  • 【练习】力扣热题100 除自身以外数组的乘积
  • WinForm如何跨线程更新界面
  • 在vscode中使用R-1
  • “代驾”小程序查漏补缺
  • 【漫话机器学习系列】048.编码有序类别特征(Encoding Ordinal Categorical Features)
  • C#里使用libxl设置EXCEL里公式计算的例子
  • Golang——并发控制