[!IMPORTANT]
- 缓存菜品的目的是什么?如何通过Redis实现缓存菜品数据?
- 在Controller层中,如何构造Redis的key并查询Redis中是否存在菜品数据?
- 当数据库中菜品数据发生变更时,如何保证Redis缓存中的数据与数据库保持一致?
- Spring Cache的作用是什么?常用的注解有哪些?
- 如何在Spring Boot项目中使用Spring Cache?
- 添加购物车的逻辑是什么?
- 如何查看购物车中的菜品和套餐?
- 如何清空购物车中的数据? 删除购物车的一个商品呢?
-
缓存菜品的目的是什么?如何通过Redis实现缓存菜品数据?
- 目的:通过缓存菜品数据,减少数据库查询操作,提升系统性能。
- 实现:将每个分类下的菜品数据保存到Redis中,使用
dish_分类id
作为key。当查询菜品时,先从Redis中获取数据,如果不存在再从数据库中查询,并将查询结果存入Redis。
-
在Controller层中,如何构造Redis的key并查询Redis中是否存在菜品数据?
- 构造key:
String key = "dish_" + categoryId;
- 查询Redis:使用
redisTemplate.opsForValue().get(key)
方法查询Redis中是否存在菜品数据。如果存在,直接返回;如果不存在,则查询数据库并将结果存入Redis。
- 构造key:
-
当数据库中菜品数据发生变更时,如何保证Redis缓存中的数据与数据库保持一致?
- 清理缓存:在新增、修改、删除菜品等操作后,调用自定义的
cleanCache
方法清理对应的缓存数据。cleanCache
方法通过redisTemplate.delete(keys)
删除Redis中与菜品相关的缓存。
- 清理缓存:在新增、修改、删除菜品等操作后,调用自定义的
-
Spring Cache的作用是什么?常用的注解有哪些?
- 作用:Spring Cache提供了一层缓存抽象,简化了缓存操作,支持多种缓存实现(如Redis、EHCache等)。
- 常用注解:
@EnableCaching
:开启缓存功能。@Cacheable
:在方法执行前查询缓存,如果缓存存在则直接返回,否则执行方法并将结果存入缓存。@CachePut
:将方法的返回值存入缓存。@CacheEvict
:从缓存中删除数据。
-
如何在Spring Boot项目中使用Spring Cache?
- 导入Spring Cache和Redis的依赖。
- 在启动类上添加
@EnableCaching
注解。 - 在需要缓存的方法上使用
@Cacheable
、@CachePut
或@CacheEvict
注解。
-
添加购物车的逻辑是什么?
- 购物车数据是关联用户的,在表结构中,我们需要记录,每一个用户的购物车数据是哪些
- 菜品列表展示出来的既有套餐,又有菜品,如果用户选择的是套餐,就保存套餐ID(setmeal_id),如果用户选择的是菜品,就保存菜品ID(dish_id)
- 对同一个菜品/套餐,如果选择多份不需要添加多条记录,增加数量number即可
Controller 层逻辑
-
请求接收
接口路径:
POST /user/shoppingCart/add
参数接收:通过
@RequestBody
解析请求体中的ShoppingCartDTO
对象 -
日志记录
记录入参日志:
log.info("添加购物车,商品信息为:{}", shoppingCartDTO)
-
服务调用
调用 Service 方法:
shoppingCartService.addShoppingCart(shoppingCartDTO)
-
响应返回
统一返回结构:
Result.success()
Service 层逻辑
- 用户验证
- 获取当前用户 ID:
BaseContext.getCurrentId()
- 验证失败处理:用户未登录时抛出
RuntimeException("用户未登录")
- 获取当前用户 ID:
- 数据转换
- DTO 转实体:
BeanUtils.copyProperties(shoppingCartDTO, shoppingCart)
- 补充用户 ID:
shoppingCart.setUserId(userId)
- DTO 转实体:
- 购物车查询
- 执行查询:
shoppingCartMapper.list(shoppingCart)
- 查询条件:用户 ID + 菜品/套餐 ID + 口味(若存在)
- 执行查询:
- 分支处理逻辑
-
场景 1:商品已存在
- 获取已存在条目:
shoppingCartList.get(0)
- 更新数量:
setNumber(原有数量 + 1)
- 执行更新:
shoppingCartMapper.updateNumberById()
- 获取已存在条目:
-
场景 2:商品不存在
- 类型判断:
- 菜品:
dishMapper.getById(dishId)
补全名称/价格/图片 - 套餐:
setmealMapper.getById(setmealId)
补全信息
- 菜品:
- 数据初始化:
- 设置默认数量:
number = 1
- 记录创建时间:
createTime = LocalDateTime.now()
- 设置默认数量:
- 数据插入:
- 执行插入:
shoppingCartMapper.insert()
- 执行插入:
- 类型判断:
-
-
如何查看购物车中的菜品和套餐?
-
Controller 层处理
- 接收请求:
ShoppingCartController
中的list()
方法处理该请求。 - 调用 Service:通过
shoppingCartService.showShoppingCart()
调用服务层逻辑。 - 返回响应:将结果包装为统一响应结构
Result.success(data)
。
- 接收请求:
-
Service 层逻辑
-
用户身份验证:
- 隐式通过
BaseContext.getCurrentId()
获取当前用户 ID(若未登录,请求会在拦截器阶段被拦截)。
- 隐式通过
-
构建查询条件:
-
使用建造者模式动态构造查询对象:
ShoppingCart.builder() .userId(BaseContext.getCurrentId()) .build();
-
-
执行查询:
- 调用
shoppingCartMapper.list()
方法,传入包含userId
的查询对象。
- 调用
-
返回数据:
- 直接返回从数据库查询到的
List<ShoppingCart>
原始数据。
- 直接返回从数据库查询到的
-
-
-
如何清空购物车中的数据? 删除购物车的一个商品呢
清空购物车功能逻辑步骤
- Controller 层处理
- 调用
shoppingCartService.cleanShoppingCart()
方法。
- 调用
- Service 层处理
- 获取当前用户 ID:
BaseContext.getCurrentId()
。 - 调用
shoppingCartMapper.deleteByUserId(userId)
删除用户所有购物车数据。
- 获取当前用户 ID:
- 返回结果
- 返回
Result.success()
表示操作成功。
- 返回
删除单个商品功能逻辑步骤
-
Controller 层处理
- 记录日志:
log.info("删除购物车中的一个商品{}", shoppingCartDTO)
。 - 调用
shoppingCartService.subShoppingCart(shoppingCartDTO)
。
- 记录日志:
-
Service 层处理
- 数据转换:将
ShoppingCartDTO
转换为ShoppingCart
对象,并设置用户 ID。 - 查询商品:调用
shoppingCartMapper.list(shoppingCart)
查询购物车中是否存在该商品。 - 分支处理:
- 商品存在且数量 > 1:
- 更新数量:
shoppingCart.setNumber(shoppingCart.getNumber() - 1)
。 - 调用
shoppingCartMapper.updateNumberById(shoppingCart)
更新数据库。
- 更新数量:
- 商品存在且数量 = 1:
- 调用
shoppingCartMapper.deleteById(shoppingCart.getId())
删除记录。
- 调用
- 商品存在且数量 > 1:
- 商品不存在:
- 当前逻辑未处理,可能导致异常。
- 数据转换:将
-
返回结果
- 返回
Result.success()
表示操作成功。
- 返回