苍穹外卖day7 缓存商品(redis/Spring Cache)、用户端购物车功能

ops/2024/10/19 9:43:08/

文章目录

  • 前言
  • 一、缓存菜品
    • 1. 问题说明
    • 2. 解决办法
    • 3. 代码开发
  • 二、缓存套餐
    • 1. Spring Cache
    • 2. 实现思路
  • 三、购物车管理
    • 1. 添加购物车
      • 1.1 产品原型
      • 1.2 接口设计
      • 1.3 数据库设计
      • 1.4 代码开发
    • 2. 查看购物车
      • 2.1 接口设计
      • 2.2 代码开发
    • 3. 清空购物车
      • 3.1 接口设计
      • 3.2 代码开发
    • 4. 删除购物车中一个商品
      • 4.1 接口设计
      • 4.2 代码开发


前言

在用户端中,每次点击左侧分类都会展示一遍菜品数据,而每次都是通过查询数据库获取的,效率低下,所以通过redis缓存数据。
Spring Cache实现了基于注解的缓存功能,通过在方法上添加相应的注解,就能够实现相关缓存操作。
添加购物车时,涉及到多个表的操作,可以单独添加菜品,也可以添加套餐,添加菜品的时候有些也需要添加菜品口味信息。


一、缓存菜品

1. 问题说明

用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大,系统响应慢、用户体验差。

2. 解决办法

通过Redis来缓存菜品数据,减少数据库查询操作。
在这里插入图片描述
缓存逻辑分析
每个分类下的菜品保存一份缓存数据
数据库中菜品数据有变更时清理缓存数据
在这里插入图片描述

3. 代码开发

1、修改用户端接口 DishController 的 list 方法,加入缓存处理逻辑

@GetMapping("/list")
@ApiOperation("根据分类id查询菜品")
public Result<List<DishVO>> list(Long categoryId){//构造redis中的key,规则:dish_分类idString key = "dish_"+categoryId;//查询redis中是否存在菜品数据List<DishVO> list = (List<DishVO>) redisTemplate.opsForValue().get(key);//如果存在,直接返回,无需查询数据库if(list != null && list.size()>0){return Result.success(list);}Dish dish = new Dish();dish.setCategoryId(categoryId);dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品//如果不存在,查询数据库list = dishService.listWithFlavor(dish);//将查询到的数据放入redisredisTemplate.opsForValue().set(key,list);return Result.success(list);
}

2、修改管理端接口 DishController 的相关方法,加入清理缓存的逻辑,当数据发生变更要及时清理redis中的缓存数据,不然会造成数据不一致

private void cleanCache(String pattern){Set keys = redisTemplate.keys(pattern);redisTemplate.delete(keys);
}
  • 新增菜品
public Result save(@RequestBody DishDTO dishDTO){log.info("新增菜品{}",dishDTO);dishService.saveWithFlavor(dishDTO);//清理缓存数据  新增菜品所属分类会受影响String key = "dish_"+dishDTO.getCategoryId();cleanCache(key);return Result.success();
}
  • 修改菜品
public Result update(@RequestBody DishDTO dishDTO){log.info("修改菜品 {}",dishDTO);dishService.updateWithFlavor(dishDTO);//如果是修改菜品所属分类,就会影响两个分类  统一清理所有缓存数据cleanCache("dish_*");return Result.success();
}
  • 批量删除菜品
public Result delete(@RequestParam List<Long> ids){log.info("菜品批量删除:{}",ids);dishService.deleteBatch(ids);//批量删除菜品,不同的菜品可能属于不同分类 直接将所有的菜品缓存数据,所有以dish_开头的keycleanCache("dish_*");return Result.success();
}
  • 起售、停售菜品
 public Result startOrStop(@PathVariable Integer status,Long id){log.info("菜品起售停售:{},{}",status,id);dishService.startOrStop(status,id);//统一清除所有缓存数据cleanCache("dish_*");return Result.success();
}

二、缓存套餐

1. Spring Cache

Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。

Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如:
EHCache
Caffeine
Redis

导入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><version>2.7.3</version>
</dependency>

常用注解
在这里插入图片描述

2. 实现思路

  1. 导入Spring Cache和Redis相关maven坐标
  2. 在启动类上加入@EnableCaching注解,开启缓存注解功能
  3. 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
@Cacheable(cacheNames = "setmealCache",key = "#categoryId")  //key:setmealCache::categoryId
public Result<List<Setmeal>> list(Long categoryId){...}
  1. 在管理端接口SetmealController的 saveSetmealwithDish、delete、update、startOrStop等方法上加入CacheEvict注解
@CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId") //key:setmealCache::categoryId 清除指定key
public Result saveSetmealwithDish(@RequestBody SetmealDTO setmealDTO){...}@CacheEvict(cacheNames = "setmealCache",allEntries = true) //allEntries = true清除value对应缓存中所有元素
public Result delete(@RequestParam List<Long> ids){...}@CacheEvict(cacheNames = "setmealCache",allEntries = true)
public Result update(@RequestBody SetmealDTO setmealDTO){...}@CacheEvict(cacheNames = "setmealCache",allEntries = true)
public Result startOrStop(@PathVariable Integer status,Long id ){...}

三、购物车管理

1. 添加购物车

1.1 产品原型

在这里插入图片描述

1.2 接口设计

在这里插入图片描述

1.3 数据库设计

暂时存放所选商品的地方
选的什么商品
每个商品都买了几个
不同用户的购物车需要区分开
在这里插入图片描述

1.4 代码开发

1、在ShoppingCartController中编写add方法添加购物车

@PostMapping("/add")
@ApiOperation("添加购物车")
private Result add(@RequestBody ShoppingCartDTO shoppingCartDTO){log.info("添加购物车,商品信息为:{}",shoppingCartDTO);shoppingCartService.addShoppingCart(shoppingCartDTO);return Result.success();
}

2、在ShoppingCartService中定义addShoppingCart方法,在ShoppingCarterviceImpl中实现

 public void addShoppingCart(ShoppingCartDTO shoppingCartDTO) {//判断当前加入购物车中的商品已存在ShoppingCart shoppingCart = new ShoppingCart();BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);//获取用户idLong userId = BaseContext.getCurrentId();shoppingCart.setUserId(userId);//通过list方法查询购物车中的商品List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);//如果已存在,只需要将数量加1if(list != null && list.size()>0){ShoppingCart cart = list.get(0);cart.setNumber(cart.getNumber()+1);//update shopping_cart set number =? where id = ?shoppingCartMapper.updateNumberById(cart);}else{//如果不存在,需要插入一条购物车数据//判断本次添加到购物车中商品的是菜品还是套餐Long dishId = shoppingCartDTO.getDishId();if(dishId != null){//本次添加到购物车的是菜品//查询菜品信息Dish dish = dishMapper.getById(dishId);shoppingCart.setName(dish.getName());shoppingCart.setImage(dish.getImage());shoppingCart.setAmount(dish.getPrice());}else{Long setmealId = shoppingCart.getSetmealId();//本次添加到购物车的是套餐Setmeal setmeal = setmealMapper.getById(setmealId);shoppingCart.setName(setmeal.getName());shoppingCart.setImage(setmeal.getImage());shoppingCart.setAmount(setmeal.getPrice());}shoppingCart.setNumber(1);shoppingCart.setCreateTime(LocalDateTime.now());shoppingCartMapper.insert(shoppingCart);}
}

3、在ShoppingCartMapper中定义list、updateNumberById、insert方法,在ShoppingCartMapper.xml文件中编写sql语句,完成相应的业务逻辑

//动态条件查询
List<ShoppingCart> list(ShoppingCart shoppingCart);
//根据id修改商品数量
@Update("update sky_take_out.shopping_cart set number=#{number} where id=#{id}")
void updateNumberById(ShoppingCart shoppingCart);
//插入购物车数据
@Insert("insert into sky_take_out.shopping_cart(name, image, user_id, dish_id, setmeal_id, "+"dish_flavor, amount, create_time)  values " +"(#{name}, #{image}, #{userId}, #{dishId}, #{setmealId}, #{dishFlavor}, #{amount}, #{createTime})")
void insert(ShoppingCart shoppingCart);
<select id="list" resultType="com.sky.entity.ShoppingCart">select * from sky_take_out.shopping_cart<where><if test="userId != null">and user_id = #{userId}</if><if test="setmealId != null">and setmeal_id = #{setmealId}</if><if test="dishId != null">and dish_id = #{dishId}</if><if test="dishFlavor != null">and dish_flavor = #{dishFlavor}</if></where>
</select>

2. 查看购物车

2.1 接口设计

在这里插入图片描述

2.2 代码开发

1、在ShoppingCartController中创建查看购物车的方法

 @GetMapping("/list")@ApiOperation("查看购物车")public Result<List<ShoppingCart>> list(){List<ShoppingCart> list = shoppingCartService.showShoppingCart();return Result.success(list);}

2、在ShoppingCartService接口中声明查看购物车的方法,在ShoppingCartServiceImpl中实现方法

public List<ShoppingCart> showShoppingCart() {//获取当前用户idLong userId = BaseContext.getCurrentId();ShoppingCart shoppingCart = ShoppingCart.builder().userId(userId).build();//list方法在添加购物车时已实现List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);return list;}

3. 清空购物车

3.1 接口设计

在这里插入图片描述

3.2 代码开发

1、在ShoppingCartController中创建清空购物车的方法,直接获取当前用户id,将当前用户的购物车数据全部删除

 public void cleanShoppingCart() {//获取当前用户idLong userId = BaseContext.getCurrentId();shoppingCartMapper.deleteByUserId(userId);
}

2、在ShoppingCartService接口中声明清空购物车的方法,在ShoppingCartServiceImpl中实现方法

public void cleanShoppingCart() {shoppingCartMapper.deleteByUserId(BaseContext.getCurrentId());
}

3、在ShoppingCartMapper接口中创建删除购物车数据的方法

 @Delete("delete from sky_take_out.shopping_cart where user_id=#{userId}")void deleteByUserId(Long userId);

4. 删除购物车中一个商品

4.1 接口设计

在这里插入图片描述

4.2 代码开发

1、在ShoppingCartController中创建删除购物车中一个商品的方法

@PostMapping("/sub")
@ApiOperation("删除购物车中一个商品")
public Result sub(@RequestBody ShoppingCartDTO shoppingCartDTO){log.info("删除购物车中一个商品,商品:{}", shoppingCartDTO);shoppingCartService.subShoppingCart(shoppingCartDTO);return Result.success();
}

2、在ShoppingCartService接口中声明方法,在ShoppingCartServiceImpl中实现,这里需要判断此商品数量为1还是大于1,该商品数量为1的时候直接删除,不为1则修改份数

public void subShoppingCart(ShoppingCartDTO shoppingCartDTO) {ShoppingCart shoppingCart = new ShoppingCart();BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);//设置查询条件,查询当前登录用户的购物车数据shoppingCart.setUserId(BaseContext.getCurrentId());List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);if(list != null && list.size() > 0){shoppingCart = list.get(0);Integer number = shoppingCart.getNumber();if(number == 1){//当前商品在购物车中的份数为1,直接删除当前记录shoppingCartMapper.deleteById(shoppingCart.getId());}else {//当前商品在购物车中的份数不为1,修改份数即可shoppingCart.setNumber(shoppingCart.getNumber() - 1);shoppingCartMapper.updateNumberById(shoppingCart);//在添加购物车的时候已实现}}
}

3、在ShoppingCartMapper中定义deleteById方法

@Delete("delete from shopping_cart where id = #{id}")
void deleteById(Long id);

http://www.ppmy.cn/ops/10417.html

相关文章

网站推广爬虫

网站推广爬虫是一种用于帮助网站推广的工具。它可以自动地收集和分析网站相关的数据&#xff0c;以便进行市场调研、竞争分析和优化策略等工作。以下是网站推广爬的一些常见功能和特点&#xff1a; .数据收集&#xff1a;网站推广爬虫可以通过抓取网页内容、提取关键信息和分析…

【css】select实现placeholder效果

场景&#xff1a;使用select下拉选择框的时候&#xff0c;需要像其他控件一样提示默认信息。 问题&#xff1a;表单控件select没有placeholder属性。 解决方案&#xff1a;通过css实现&#xff0c;不需要js <style>select > option[disabled]{ color:#999;cursor: n…

【前端】4. CSS综合案例

1. 模拟新闻界面 <!-- 1.模拟实现新闻界面 --><!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>…

分享4张亚马逊云科技AWS免费云开发和AI证书(有答案)

今天给大家带来特别福利&#xff0c;一口气带来亚马逊云科技AWS4张免费云开发/AI证书(有Credly徽章&#xff0c;有答案)&#xff0c;这四门都是云开发相关的硬核知识&#xff0c;含金量极高。 主要考察如何用AWS AI服务进行开发、以及当下热门的云原生改造&#xff0c;16道题80…

Edge的使用心得与深度探索:优化浏览体验的技巧与建议

随着互联网的快速发展&#xff0c;浏览器已经成为我们日常生活中不可或缺的工具之一。在众多浏览器中&#xff0c;微软Edge凭借其稳定性、安全性和功能丰富性备受用户青睐。本文将深入探讨Edge浏览器的各种功能与技巧&#xff0c;帮助用户优化其浏览体验。 文章目录 Edge翻译插…

Java中的BIO、NIO与AIO

1.概述 I/O 模型简单的理解&#xff1a;就是用什么样的通道进行数据的发送和接收&#xff0c;很大程度上决定了程序通信的性能。Java 共支持 3 种网络编程模型 I/O 模式&#xff1a;BIO、NIO、AIO。 2.Java BIO Java BIO(Blocking I/O)&#xff1a;是传统的java io 编程&#…

计算机网络学习day02|HTTP协议

目录 一、HTTP报文格式长什么样&#xff1f;是如何分割的&#xff1f; 请求行 状态行 头部字段 常用头字段 小结 二、HTTP提供了哪些方法&#xff1f;GET和POST的区别是什么&#xff1f; 1.HTTP有哪些方法 2.GET/HEAD 3.PSOT/PUT 小结 三、URI和URL URI 的格式 U…

面试宝典(1)——数据库篇(MySQL)

面试宝典&#xff08;1&#xff09;——数据库篇&#xff08;MySQL&#xff09; 1.什么是索引&#xff1f; 索引是一种用于加快数据库查询速度的数据结构。 索引可以帮助数据库快速定位到数据库表中特定列的记录&#xff0c;从而加快数据检索和查询的速度。 通过在表的列上…