【苍穹外卖】项目实战Day05

柔光的暖阳◎ 2024-05-06 09:56 137阅读 0赞

? 本文由 程序喵正在路上 原创,CSDN首发!
? 系列专栏:苍穹外卖项目实战
? 首发时间:2024年5月5日
? 欢迎关注?点赞?收藏?留言?

目录

  • Redis入门
    • Redis简介
    • Redis下载与安装
    • Redis服务启动与停止
  • Redis数据类型
    • 5种常用数据类型介绍
    • 各种数据类型的特点
  • Redis常用命令
    • 字符串操作命令
    • 哈希操作命令
    • 列表操作命令
    • 集合操作命令
    • 有序集合操作命令
    • 通用命令
  • 在Java中操作Redis
    • Redis的Java客户端
    • Spring Data Redis使用方式
      • 操作 String 类型的数据
      • 操作 Hash 类型的数据
      • 操作 List 类型的数据
      • 操作 Set 类型的数据
      • 操作 ZSet 类型的数据
      • 通用命令操作
  • 店铺营业状态设置
    • 需求分析和设计
    • 代码开发
    • 功能测试

Redis入门

Redis简介

Redis 是一个基于内存的 key-value 结构数据库。

  • 基于内存存储,读写性能高
  • 适合存储热点数据(热点商品、资讯、新闻)
  • 企业应用广泛

在这里插入图片描述

  • 官网:https://redis.io
  • 中文网:https://www.redis.net.cn/

Redis下载与安装

Redis 安装包分为 Windows 版和 Linux 版:

  • Windows 版下载地址:https://github.com/microsoftarchive/redis/releases
  • Linux 版下载地址: https://download.redis.io/releases/

在资料中已经准备好了 Windows 版本的:

在这里插入图片描述

RedisWindows 版属于绿色软件,直接解压即可使用,解压后目录结构如下:

在这里插入图片描述

Redis服务启动与停止

  • 服务启动命令:redis-server.exe redis.windows.conf

    redis 解压目录的地址栏,输入 cmd 后回车,输入启动命令:

    在这里插入图片描述

  • Redis 服务默认端口号为 6379 ,通过快捷键 Ctrl + c 可以停止 Redis 服务
  • 客户端连接命令:redis-cli.exe

    在服务端启动的前提下,再打开一个命令行窗口,输入客户端连接命令,如下图表示成功:

    在这里插入图片描述

  • 客户端退出命令:exit
  • 通过 redis-cli.exe 命令默认连接的是本地的 redis 服务,并且使用默认 6379 端口。我们也可以通过指定如下参数连接:

    • -h:ip地址
    • -p:端口号
    • -a:密码(如果需要)
  • 通过修改 redis.windows.conf,我们可以设置 redis 的服务密码,redis 的客户登录并不需要用户名,但是需要密码

    打开 redis.windows.conf,Ctrl + F 找到图中内容,然后设置一下你的 redis 服务密码:

    在这里插入图片描述

  • 注意:

    • 修改密码后需要重启 Redis 服务才能生效
    • Redis 配置文件中的 # 表示注释

用命令来操作多少还是有点麻烦,下面我们介绍一个 Redis 客户端图形工具:

在这里插入图片描述
安装后,打开:

在这里插入图片描述

连接后,我们可以看到服务端的信息:

在这里插入图片描述

Redis数据类型

5种常用数据类型介绍

Redis 存储的是 key-value 结构的数据,其中 key 是字符串类型,value5 种常用的数据类型:

  • 字符串 string
  • 哈希 hash
  • 列表 list
  • 集合 set
  • 有序集合 sorted set / zset

各种数据类型的特点

在这里插入图片描述

  • 字符串 (string):普通字符串,Redis 中最简单的数据类型
  • 哈希 (hash):也叫散列,类似于 Java 中的 HashMap 结构,适合存储对象
  • 列表 (list):按照插入顺序排序,可以有重复元素,类似于 Java 中的 LinkedList
  • 集合 (set):无序集合,没有重复元素,类似于 Java 中的 HashSet
  • 有序集合 (sorted set / zset):集合中每个元素关联一个分数(score),根据分数升序排序,没有重复元素

Redis常用命令

字符串操作命令

Redis 字符串类型常用命令:

  • SET key value :设置指定 key 的值
  • GET key :获取指定 key 的值
  • SETEX key seconds value :设置指定 key 的值,并将 key 的过期时间设为 seconds 秒,经典应用场景为短信验证码
  • SETNX key value :只有当 key 不存在时才设置 key 的值

ps:命令不区分大小写

打开图形界面:

在这里插入图片描述

SETEX key seconds value : 时间到,key 会自动销毁

在这里插入图片描述

在这里插入图片描述

哈希操作命令

在这里插入图片描述

Redis hash 是一个 string 类型的 fieldvalue 的映射表,hash 特别适合用于存储对象,常用命令:

  • HSET key field value :将哈希表 key 中的字段 field 的值设为 value
  • HGET key field :获取存储在哈希表中指定字段的值
  • HDEL key field :删除存储在哈希表中的指定字段
  • HKEYS key :获取哈希表中所有字段
  • HVALS key :获取哈希表中所有值

在这里插入图片描述

在这里插入图片描述

列表操作命令

在这里插入图片描述

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

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

在这里插入图片描述

在这里插入图片描述

集合操作命令

在这里插入图片描述

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

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

在这里插入图片描述

在这里插入图片描述

有序集合操作命令

在这里插入图片描述

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

  • ZADD key score1 member1 [score2 member2] :向有序集合添加一个或多个成员
  • ZRANGE key start stop [WITHSCORES] :通过索引区间返回有序集合中指定区间内的成员
  • ZINCRBY key increment member :有序集合中对指定成员的分数加上增量 increment
  • ZREM key member [member ...] :移除有序集合中的一个或多个成员

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

通用命令

Redis 的通用命令是不分数据类型的,都可以使用的命令,因为都是在操作 key

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

在这里插入图片描述

在Java中操作Redis

Redis的Java客户端

RedisJava 客户端很多,常用的几种:

  • Jedis
  • Lettuce
  • Spring Data Redis

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

Spring Data Redis使用方式

操作步骤:

  • 导入 Spring Data Redismaven 坐标
  • 配置 Redis 数据源
  • 编写配置类,创建 RedisTemplate 对象
  • 通过 RedisTemplate 对象操作 Redis
  1. 导入 Spring Data Redismaven 坐标(项目中已导入)

    在这里插入图片描述

  2. 配置 Redis 数据源

    在配置文件中配置 redis 数据源,不要将数据写死,这样方便我们项目环境的切换。Redis 默认会给我们创建 16 个数据库,每个数据库之间的数据是隔离开的,默认使用 0 号数据库,我们也可以自己设置。

    在这里插入图片描述

    在这里插入图片描述

  3. 编写配置类,创建 RedisTemplate 对象

    新建配置类 RedisConfiguration

    1. import lombok.extern.slf4j.Slf4j;
    2. import org.springframework.context.annotation.Bean;
    3. import org.springframework.context.annotation.Configuration;
    4. import org.springframework.data.redis.connection.RedisConnectionFactory;
    5. import org.springframework.data.redis.core.RedisTemplate;
    6. import org.springframework.data.redis.serializer.StringRedisSerializer;
    7. @Configuration
    8. @Slf4j
    9. public class RedisConfiguration {
  1. @Bean
  2. public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
  3. log.info("开始创建redis模板对象...");
  4. RedisTemplate redisTemplate = new RedisTemplate();
  5. //设置redis的连接工厂对象
  6. redisTemplate.setConnectionFactory(redisConnectionFactory);
  7. //设置redis key的序列化器
  8. redisTemplate.setKeySerializer(new StringRedisSerializer());
  9. return redisTemplate;
  10. }
  11. }
  1. 通过 RedisTemplate 对象操作 Redis

    在测试包下新建测试类 SpringDataRedisTest

    在这里插入图片描述

    注入 RedisTemplate 对象,测试对象是否创建成功:

    在这里插入图片描述

RedisTemplate 针对大量 api 进行了归类封装,将同一数据类型的操作封装为对应的 Operation 接口,具体分类如下:

  • ValueOperationsstring 数据操作
  • HashOperationshash 类型的数据操作
  • ListOperationslist 类型的数据操作
  • SetOperationsset 类型数据操作
  • ZSetOperationszset 类型数据操作

操作 String 类型的数据

  1. /**
  2. * 操作String类型数据
  3. */
  4. @Test
  5. public void testString() {
  6. ValueOperations valueOperations = redisTemplate.opsForValue();
  7. valueOperations.set("city", "北京"); //set
  8. String city = (String) valueOperations.get("city"); //get
  9. System.out.println(city);
  10. valueOperations.set("code", "123", 3, TimeUnit.MINUTES); //setex
  11. valueOperations.setIfAbsent("lock", "1"); //setnx
  12. valueOperations.setIfAbsent("lock", "2");
  13. }

执行这个测试方法,然后查看 1 号数据库(前面我们设置使用的是 1 号数据库):

在这里插入图片描述

可以看到 value 部分好像是乱码的,而 key 是正常的,这时因为在配置类中我们给 key 设置了序列化器:

在这里插入图片描述

操作 Hash 类型的数据

  1. /**
  2. * 操作Hash类型的数据
  3. */
  4. @Test
  5. public void testHash() {
  6. HashOperations hashOperations = redisTemplate.opsForHash();
  7. hashOperations.put("user", "name", "Tom"); //hset
  8. hashOperations.put("user", "age", "20");
  9. String name = (String) hashOperations.get("user", "name"); //hget
  10. System.out.println(name);
  11. Set keys = hashOperations.keys("user"); //hkeys
  12. System.out.println(keys);
  13. List values = hashOperations.values("user"); //hvals
  14. System.out.println(values);
  15. hashOperations.delete("user", "age"); //hdel
  16. }

在这里插入图片描述

在这里插入图片描述

操作 List 类型的数据

  1. /**
  2. * 操作List类型的数据
  3. */
  4. @Test
  5. public void testList() {
  6. ListOperations listOperations = redisTemplate.opsForList();
  7. listOperations.leftPushAll("myList", "a", "b", "c"); //lpush
  8. listOperations.leftPush("myList", "d"); //lpush
  9. List myList = listOperations.range("myList", 0, -1); //lrange
  10. System.out.println(myList);
  11. listOperations.rightPop("myList"); //rpop
  12. Long size = listOperations.size("myList"); //llen
  13. System.out.println(size);
  14. }

在这里插入图片描述

操作 Set 类型的数据

  1. /**
  2. * 操作Set类型的数据
  3. */
  4. @Test
  5. public void testSet() {
  6. SetOperations setOperations = redisTemplate.opsForSet();
  7. setOperations.add("set1", "a", "b", "c", "d"); //sadd
  8. setOperations.add("set2", "b", "c", "d", "e");
  9. Set members = setOperations.members("set1"); //smembers
  10. System.out.println(members);
  11. Long size = setOperations.size("set1"); //scard
  12. System.out.println(size);
  13. Set intersect = setOperations.intersect("set1", "set2"); //sinter
  14. System.out.println(intersect);
  15. Set union = setOperations.union("set1", "set2"); //sunion
  16. System.out.println(union);
  17. setOperations.remove("set1", "a", "b"); //srem
  18. }

在这里插入图片描述

操作 ZSet 类型的数据

  1. /**
  2. * 操作ZSet类型的数据
  3. */
  4. @Test
  5. public void testZSet() {
  6. ZSetOperations zSetOperations = redisTemplate.opsForZSet();
  7. zSetOperations.add("zset1", "a", 1); //zadd
  8. zSetOperations.add("zset1", "b", 2);
  9. zSetOperations.add("zset1", "c", 3);
  10. Set zset1 = zSetOperations.range("zset1", 0, -1); //zrange
  11. System.out.println(zset1);
  12. zSetOperations.incrementScore("zset1", "c", 10); //zincrby
  13. zSetOperations.remove("zset1", "a"); //zrem
  14. }

在这里插入图片描述

通用命令操作

  1. /**
  2. * 通用命令操作
  3. */
  4. @Test
  5. public void testCommon() {
  6. Set keys = redisTemplate.keys("*"); //keys
  7. System.out.println(keys);
  8. Boolean name = redisTemplate.hasKey("name"); //exists
  9. System.out.println("name:" + name);
  10. Boolean set1 = redisTemplate.hasKey("set1");
  11. System.out.println("set1:" + set1);
  12. for (Object key : keys) {
  13. DataType type = redisTemplate.type(key); //type
  14. System.out.println(key + ": " + type.name());
  15. }
  16. redisTemplate.delete("myList"); //del
  17. }

在这里插入图片描述

店铺营业状态设置

需求分析和设计

产品原型:

在这里插入图片描述
由于本项目约定:

  • 管理端发出的请求,统一使用 /admin 作为前缀
  • 用户端发出的请求,统一使用 /user 作为前缀

所以查询营业状态这个操作我们需要设计成两个接口。当然,这样设计也是有好处的,我们可以很容易地判断这个请求是来自用户端还是管理端。

接口设计:

  • 设置营业状态

    在这里插入图片描述

  • 管理端查询营业状态

    在这里插入图片描述

  • 用户端查询营业状态

    在这里插入图片描述

营业状态数据存储方式:基于 Redis 的字符串来进行存储。

在这里插入图片描述

约定:1 表示营业;0 表示打烊。

代码开发

先把前面写的这个测试类注释掉,不然会影响我们项目的启动速度:

在这里插入图片描述

管理端两个接口的开发

新建控制类 ShopController,专门用来存放店铺相关接口,然后开发设置店铺营业状态管理端查询营业状态两个接口:

  1. import com.sky.result.Result;
  2. import io.swagger.annotations.Api;
  3. import io.swagger.annotations.ApiOperation;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.data.redis.core.RedisTemplate;
  7. import org.springframework.web.bind.annotation.*;
  8. @RestController("adminShopController") //与用户端的ShopController区分开
  9. @RequestMapping("/admin/shop")
  10. @Slf4j
  11. @Api("店铺操作相关接口")
  12. public class ShopController {
  13. public static final String KEY = "SHOP_STATUS";
  14. @Autowired
  15. private RedisTemplate redisTemplate;
  16. /**
  17. * 设置店铺的营业状态
  18. *
  19. * @param status
  20. * @return
  21. */
  22. @PutMapping("/{status}")
  23. @ApiOperation("设置店铺的营业状态")
  24. public Result setStatus(@PathVariable Integer status) {
  25. log.info("设置店铺的营业状态为:{}", status == 1 ? "营业中" : "打烊");
  26. redisTemplate.opsForValue().set(KEY, status);
  27. return Result.success();
  28. }
  29. /**
  30. * 获取店铺的营业状态
  31. *
  32. * @return
  33. */
  34. @GetMapping("/status")
  35. @ApiOperation("获取店铺的营业状态")
  36. public Result<Integer> getStatus() {
  37. Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
  38. log.info("获取到店铺的营业状态为:{}", status == 1 ? "营业中" : "打烊");
  39. return Result.success(status);
  40. }
  41. }

用户端查询营业状态接口开发

其实,用户端查询营业状态这个接口的逻辑和管理端的一模一样,所以我们可以先在 controller 包下新建 user 包用来存放用户端的控制类,然后将管理端的 ShopController 复制一份到 user 包下,再稍加修改即可:

在这里插入图片描述

功能测试

可以进行接口测试,也可以进行前后端联调测试。

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

在进行接口测试的时候,我们发现,两个查询营业状态的接口被放在同一个菜单下,如果我们想把它们区分开发,也就是分为放在不同的目录下,应该如何操作呢?

(ps:两个菜单名为英文的不知道什么原因,代码没有错误)

在这里插入图片描述

之所以它们会在同一目录下,是因为我们在配置类中生成接口文档部分的代码只指定了扫描 controller 这个包中的内容,所以将它们都扫描进去了。

在这里插入图片描述

我们可以再写一个方法单独扫描 user 包,然后原先的 docket 方法扫描 admin 包:

在这里插入图片描述

重启服务,再查看接口文档,发现只剩下一个接口,因为我们现在是在用户端:

在这里插入图片描述

我们可以点击切换到管理端:

在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,137人围观)

还没有评论,来说两句吧...

相关阅读

    相关 苍穹——项目搭建

    本项目(苍穹外卖)是专门为餐饮企业(餐厅、饭店)定制的一款软件产品,包括 系统管理后台 和 小程序端应用 两部分。其中系统管理后台主要提供给餐饮企业内部员工使用,可以对餐...