苍穹外卖开发日志Day06——套餐管理


2025.07.23

一、Redis入门

1.1 Redis简介

  • Redis是一个基于内存的key-value结构数据库
  • Redis特点:
    • 基于内存存储,读写性能高
    • 适合存储热点数据(热点商品、资讯、新闻)
    • 企业应用广泛
  • 官网:https://redis.io/
  • 中文网:https://www.redis.net.cn/

1.2 Redis下载与安装

1.3 Redis配置与启动

  • Redis配置文件:redis.windows.conf
    • 可以修改配置文件中的选项来调整Redis的行为
    • 常用配置选项包括:
      • bind:绑定IP地址,默认绑定到本地IP
      • port:Redis服务端口,默认6379
      • requirepass:设置访问密码
  • 运行:
    • 在安装目录下启动cmd,并输入redis-server.exe redis.windows.conf即可
      Redis启动
    • ctrl+C可以停止Redis服务
  • Redis默认没有密码,可以在redis.windows.conf中设置密码
    • 修改配置文件中的requirepass选项,取消注释并设置密码
      Redis设置密码
    • 重启Redis服务后,使用redis-cli连接时需要输入密码,格式为-a 密码
      Redis输入密码
  • 连接到Redis:
    • 方式一:在安装目录下启动cmd,并输入redis-cli.exe即可
      Redis连接
    • 方式二:使用图形化界面Another Redis Desktop Manager链接
      Redis图形化界面

二、Redis数据类型

2.1 Redis数据类型概述

  • Redis支存储的是key-value结构的数据,其中key是字符串类型,value可以是多种数据类型:
    • 字符串(string)
    • 哈希(hash)
    • 列表(list)
    • 集合(set)
    • 有序集合(sorted set/zset)

2.2 Redis数据类型特点

Redis数据类型

  • 字符串(string):普通字符串,Redis中最简单的数据类型
  • 哈希(hash):也叫散列,类似于Java中的HashMap结构,可以理解为(key-(key-vaue))对的集合
  • 列表(list):按照插入顺序排序,可以有重复元素,类似于Java中的LinkedList
  • 集合(set):无序且唯一的元素集合,类似于Java中的HashSet
  • 有序集合(sorted set/zset):有序且唯一的元素集合,每个元素都有一个分数(score)来决定顺序,类似于Java中的TreeSet

三、Redis常用命令

3.1 Redis字符串命令

  • SET key value:设置key的值为value
  • GET key:获取key的值
  • SETEX key seconds value:设置key的值为value,并设置过期时间为seconds秒
  • SETNX key value:如果key不存在,则设置key的值为value

示例:
操作命令:
Redis字符串命令
效果:
SET name jack
SETEX code 60 1597
SETNX user li

3.2 Redis哈希命令

Redis hash是一个string类型的field和value的映射表,适合存储对象数据,常用命令:

  • HSET key field value:设置哈希表key中的field的值为value
  • HGET key field:获取哈希表key中的field的值
  • HDEL key field:删除哈希表key中的field
  • HKEYS key:获取哈希表key中的所有field
  • HVALS key:获取哈希表key中的所有value

示例:
操作命令:
Redis哈希命令
效果:
HSET 100

3.3 Redis列表命令

Redis列表是简单的字符串列表,按照插入顺序排序,常用命令:

  • LPUSH key value1 [value2]:将一个或多个值插入到列表key的头部
  • LRANGE key start stop:获取列表key中指定范围的元素
  • RPOP key:移除并返回列表key的最后一个元素
  • LLEN key:获取列表key的长度

示例:
操作命令:
Redis列表命令
效果:
LPUSH mylist a b c
RPOP mylist

3.4 Redis集合命令

Redis set是string类型的无序集合,集合成员是唯一的,集合中不能出现重复的数据,常用命令:

  • SADD key member1 [member2]:向集合key添加一个或多个成员
  • SMEMBERS key:获取集合key中的所有成员
  • SCARD key:获取集合key的成员数量
  • SINTER key1 [key2]:返回给定所有集合的交集
  • SUNION key1 [key2]:返回给定所有集合的并集
  • SREM key member1 [member2]:移除集合key中的一个或多个成员

示例:
操作命令:
Redis集合命令
效果:
SADD set1
SADD set2
SREM set1 c

3.5 Redis有序集合命令

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

  • ZADD key score1 member1 [score2 member2]:向有序集合key添加一个或多个成员,分数为score1[score2]
  • ZRANGE key start stop [WITHSCORES]:返回有序集合key中指定范围的成员,WITHSCORES选项可以返回成员的分数
  • ZINCRBY key increment member:为有序集合key中的成员member的分数增加increment
  • ZREM key member1 [member2]:移除有序集合key中的一个或多个成员

示例:
操作命令:
Redis有序集合命令
效果:
ZADD set 0.1 a 0.3 b 0.2 c
ZINCRBY set 0.5 a
ZREM set c

3.6 Redis通用命令

Redis的通用命令是不分数据类型的,常用命令:

  • KEYS pattern:查找所有符合给定模式(pattern)的key
  • EXISTS key:检查key是否存在
  • TYPE key:返回key所储存的值的类型
  • DEL key:删除key

示例:
操作命令:
Redis通用命令

四、在Java中操作Redis

4.1 Redis的Java客户端

Redis有多种Java客户端可供选择,常用的有:

  • Jedis:最常用的Redis Java客户端,简单易用
  • Lettuce:基于Netty的异步Redis客户端,支持响应式编程
  • Spring Data Redis:Spring框架的Redis集成,提供了更高层次的抽象

4.2 Spring Data Redis使用方式

  • 操作步骤

    1. 在pom.xml中导入Spring Data Redis的maven坐标
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    ```

    2. 在application.yml中配置Redis数据源
    ```yml
    spring:
    redis:
    host: localhost
    port: 6379
    password: 123456
    database: 0
    1. 编写配置类,创建RedisTemplate对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    @Configuration
    @Slf4j
    public class RedisConfiguration {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {

    log.info("开始创建Redis模板对象...");
    RedisTemplate redisTemplate = new RedisTemplate();
    // 设置连接工厂对象
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    // 设置key的序列化器
    redisTemplate.setKeySerializer(new StringRedisSerializer());

    return redisTemplate;
    }
    }
    1. 通过RedisTemplate对象操作Redis

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package com.sky.test;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;

import javax.xml.crypto.Data;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@SpringBootTest
public class SpringDataRedisTest {

@Autowired
private RedisTemplate redisTemplate;

@Test
public void testRedisTemplate() {
System.out.println(redisTemplate);
ValueOperations valueOperations = redisTemplate.opsForValue();
HashOperations hashOperations = redisTemplate.opsForHash();
ListOperations listOperations = redisTemplate.opsForList();
SetOperations setOperations = redisTemplate.opsForSet();
ZSetOperations zSetOperations = redisTemplate.opsForZSet();
}

/**
* 字符串命令测试
*/
@Test
public void testString() {
// set get setex setnx
redisTemplate.opsForValue().set("city", "北京");
String city = (String) redisTemplate.opsForValue().get("city");
System.out.println(city);

redisTemplate.opsForValue().set("code", "1234", 3, TimeUnit.MINUTES);
redisTemplate.opsForValue().setIfAbsent("age", "18");
}

/**
* 哈希命令测试
*/
@Test
public void testHash() {
// hset hget hdel hkeys hvals
HashOperations hashOperations = redisTemplate.opsForHash();

hashOperations.put("100", "name", "Tom");
hashOperations.put("100", "age", "18");

String name = (String) hashOperations.get("100", "name");
System.out.println(name);

Set keys = hashOperations.keys("100");
System.out.println(keys);

List values = hashOperations.values("100");
System.out.println(values);

hashOperations.delete("100", "age");
}

/**
* 列表命令测试
*/
@Test
public void testList() {
// lput 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 setOperations = redisTemplate.opsForSet();

setOperations.add("set1", "a", "b", "c");
setOperations.add("set2", "c", "d", "e");

Set members = setOperations.members("set1");
System.out.println(members);

Long size = setOperations.size("set1");
System.out.println(size);

Set interset = setOperations.intersect("set1", "set2");
System.out.println(interset);

Set union = setOperations.union("set1", "set2");
System.out.println(union);

setOperations.remove("set1", "a", "b");
}

/**
* 有序集合命令测试
*/
@Test
public void testZSet() {
// zadd zrange zincrby zrem
ZSetOperations zSetOperations = redisTemplate.opsForZSet();

zSetOperations.add("zset1", "a", 10);
zSetOperations.add("zset1", "b", 12);
zSetOperations.add("zset1", "c", 9);

Set zset1 = zSetOperations.range("zset1", 0, -1);
System.out.println(zset1);

zSetOperations.incrementScore("zset1", "c", 10);

zSetOperations.remove(zset1, "a", "b");
}

/**
* 通用命令测试
*/
@Test
public void testCommon() {
// keys exists type del
Set keys = redisTemplate.keys("*");
System.out.println(keys);

Boolean name = redisTemplate.hasKey("name");
Boolean set1 = redisTemplate.hasKey("set1");

for (Object key : keys) {
DataType type = redisTemplate.type(key);
System.out.println(type.name());
}

redisTemplate.delete("mylist");
}
}

五、店铺营业状态设置

5.1 业务需求

产品原型:

接口设计:

  • 设置营业状态
  • 管理端查询营业状态
  • 用户端查询营业状态

设置营业状态接口设计
管理端查询营业状态接口设计
用户端查询营业状态接口设计

本项目约定:

  • 管理端发出的请求,统一使用/admin前缀
  • 用户端发出的请求,统一使用/user前缀
  • 营业状态数据存储方式:基于Redis的字符串来进行存储
  • 约定:1表示营业,0表示打烊

5.2 代码实现

5.2.1 adminShopController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@RestController("adminShopController")
@RequestMapping("/admin/shop")
@Api(tags = "店铺相关接口")
@Slf4j
public class ShopController {

public static final String KEY = "SHOP_STATUS";

@Autowired
private RedisTemplate redisTemplate;

/**
* 设置店铺营业状态
* @param status
* @return
*/
@PutMapping("/{status}")
@ApiOperation("设置店铺营业状态")
public Result setStatus(@PathVariable Integer status) {
log.info("设置店铺营业状态为:{}", status == 1 ? "营业中":"打烊中");
redisTemplate.opsForValue().set(KEY, status);
return Result.success();
}

/**
* 获取店铺营业状态
* @return
*/
@GetMapping("/status")
@ApiOperation("获取店铺营业状态")
public Result<Integer> getStatus() {
Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
log.info("店铺营业状态为:{}", status == 1 ? "营业中":"打烊中");
return Result.success(status);
}
}

5.2.2 userShopController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RestController("userShopController")
@RequestMapping("/user/shop")
@Api(tags = "店铺相关接口")
@Slf4j
public class ShopController {

public static final String KEY = "SHOP_STATUS";

@Autowired
private RedisTemplate redisTemplate;

/**
* 获取店铺营业状态
* @return
*/
@GetMapping("/status")
@ApiOperation("获取店铺营业状态")
public Result<Integer> getStatus() {
Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
log.info("店铺营业状态为:{}", status == 1 ? "营业中":"打烊中");
return Result.success(status);
}
}

5.3 功能测试

设置店铺营业状态
管理端查询营业状态
用户端查询营业状态

前后端联调测试:
前后端联调测试