缓存商品、购物车(day07)

缓存菜品

问题说明

**问题说明:**用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。

结果: 系统响应慢、用户体验差

实现思路

通过Redis来缓存菜品数据,减少数据库查询操作。

缓存逻辑分析:

  • 每个分类下的菜品保存一份缓存数据
  • 数据库中菜品数据有变更时清理缓存数据

代码开发

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

为了保证数据库Redis 中的数据保持一致,修改管理端接口 DishController 的相关方法,加入清理缓存逻辑。
修改管理端接口 DishController 的相关方法,加入清理缓存的逻辑,需要改造的方法:

  • 新增菜品
  • 修改菜品
  • 批量删除菜品
  • 起售、停售菜品

抽取清理缓存的方法:

调用清理缓存的方法,保证数据一致性:

调用清理缓存的方法,保证数据一致性:

调用清理缓存的方法,保证数据一致性:

功能测试

可以通过如下方式进行测试:
• 查看控制台 sql
• 前后端联调
• 查看 Redis 中的缓存数据

缓存套餐

Spring Cache

介绍

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

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

  • EHCache
  • Caffeine
  • Redis(常用)
常用注解:

在 SpringCache 中提供了很多缓存操作的注解,常见的是以下的几个:

**在spring boot项目中,**使用缓存技术只需在项目中导入相关缓存技术的依赖包,并在启动类上使用@EnableCaching开启缓存支持即可。

例如,使用Redis作为缓存技术,只需要导入Spring data Redis的maven坐标即可。

入门案例

入门案例:导入资料中的初始工程,在此基础上加入Spring Cache注解即可

导入基础工程: 底层已使用 Redis 缓存实现

基础环境的代码,在我们今天的资料中已经准备好了, 大家只需要将这个工程导入进来就可以了。导入进来的工程结构如下:

数据库准备:

创建名为spring_cache_demo数据库,将springcachedemo.sql脚本直接导入数据库中。

1、引导类上加@EnableCaching:
java 复制代码
package com.itheima;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;

@Slf4j
@SpringBootApplication
@EnableCaching //开启缓存注解功能
public class CacheDemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(CacheDemoApplication.class,args);
        log.info("项目启动成功...");
    }
}
2). @CachePut注解

@CachePut 说明:

  • 作用: 将方法返回值,放入缓存
  • value: 缓存的名称, 每个缓存名称下面可以有很多key
  • key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法

在save方法上加注解@CachePut

当前 UserController 的 save 方法是用来保存用户信息的,我们希望在该用户信息保存到数据库的同时,也往缓存中缓存一份数据,我们可以在 save 方法上加上注解 @CachePut,用法如下:

java 复制代码
/**
     * CachePut:将方法返回值放入缓存
     * value:缓存的名称,每个缓存名称下面可以有多个key
     * key:缓存的key
     */
    @PostMapping
    @CachePut(cacheNames = "userCache",key = "#user.id") //如果使用Spring Cache缓存数据,key的生成:userCache::1
    //@CachePut(cacheNames = "userCache",key = "#result.id") //对象导航
    //@CachePut(value = "userCache", key = "#p0.id")//p0,第一个参数;p1,第二个参数
    //@CachePut(value = "userCache", key = "#a0.id")//a0,第一个参数;a1,第二个参数
    //@CachePut(value = "userCache", key = "#root.args[0].id")//root.args[0],第一个参数
    public User save(@RequestBody User user){
        userMapper.insert(user);
        return user;
    }

说明: key的写法如下

  1. #user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ;
  2. #result.id : #result代表方法返回值,该表达式 代表以返回对象的id属性作为key ;
  3. #p0.id:#p0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
  4. #a0.id:#a0指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
  5. #root.args[0].id:#root.args[0]指的是方法中的第一个参数,id指的是第一个参数的id属性,也就是使用第一个参数的id属性作为key ;
    启动服务,通过swagger接口文档测试,访问UserController的save()方法
3). @Cacheable注解

@Cacheable 说明:

  • 作用: 在方法执行前,spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
  • value: 缓存的名称,每个缓存名称下面可以有多个key
  • key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法

在getById上加注解@Cacheable

java 复制代码
/**
     * Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,	  *调用方法并将方法返回值放到缓存中
     * value:缓存的名称,每个缓存名称下面可以有多个key
     * key:缓存的key
     */
    @Cacheable(cacheNames = "userCache",key = "#id")
    @GetMapping
    public User getById(Long id){
        User user = userMapper.getById(id);
        return user;
    }

重启服务,通过swagger接口文档测试,访问UserController的getById()方法

第一次访问,会请求我们controller的方法,查询数据库。后面再查询相同的id,就直接从Redis中查询数据,不用再查询数据库了,就说明缓存生效了。

4). @CacheEvict注解

@CacheEvict 说明:

  • 作用: 清理指定缓存
  • value: 缓存的名称,每个缓存名称下面可以有多个key
  • key: 缓存的key ----------> 支持Spring的表达式语言SPEL语法

在 delete 方法上加注解@CacheEvict

java 复制代码
@CacheEvict(cacheNames = "userCache",key = "#id")//删除某个key对应的缓存数据
    @DeleteMapping
    public void deleteById(Long id){
        userMapper.deleteById(id);
    }

    @CacheEvict(cacheNames = "userCache",allEntries = true)//删除userCache下所有的缓存数据
	@DeleteMapping("/delAll")
    public void deleteAll(){
        userMapper.deleteAll();
    }

重启服务,通过swagger接口文档测试,访问UserController的deleteAll()方法

实现思路

实现步骤:

  1. 导入Spring Cache和Redis相关maven坐标
  2. 在启动类上加入@EnableCaching注解,开启缓存注解功能
  3. 在用户端接口SetmealController的 list 方法上加入@Cacheable注解
  4. 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解

代码开发

1). 导入Spring Cache和Redis相关maven坐标(已实现)

2). 在启动类上加入@EnableCaching注解,开启缓存注解功能

3). 在用户端接口SetmealController的 list 方法上加入@Cacheable注解

4).在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解:

功能测试

添加购物车

需求分析和设计

产品原型:

接口设计:
请求方式:POST
请求路径:/user/shoppingCart/add
• 请求参数:套餐 id 、菜品 id 、口味
• 返回结果: code 、 data 、 msg

数据库设计:
• 作用:暂时存放所选商品的地方
• 选的什么商品
• 每个商品都买了几个
• 不同用户的购物车需要区分开

用户的购物车数据,也是需要保存在数据库中的,购物车对应的数据表为 shopping_cart 表,具体表结构如下:

说明:

  • 购物车数据是关联用户的,在表结构中,我们需要记录,每一个用户的购物车数据是哪些
  • 菜品列表展示出来的既有套餐,又有菜品,如果用户选择的是套餐,就保存套餐ID(setmeal_id),如果用户选择的是菜品,就保存菜品ID(dish_id)
  • 对同一个菜品/套餐,如果选择多份不需要添加多条记录,增加数量number即可

代码开发

根据添加购物车接口的参数设计DTO:

根据添加购物车接口创建ShoppingCartController:

创建ShoppingCartService接口:

创建ShoppingCartServiceImpl实现类,并实现add方法:

创建ShoppingCartServiceImpl实现类,并实现add方法:

创建ShoppingCartMapper接口:

创建ShoppingCartMapper.xml:

功能测试

查看购物车

需求分析和设计

产品原型:

接口设计:

代码开发

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

在ShoppingCartService接口中声明查看购物车的方法:

在ShoppingCartServiceImpl中实现查看购物车的方法:

功能测试

清空购物车

需求分析和设计

产品原型:

接口设计:

代码开发

在ShoppingCartController中创建清空购物车的方法:

在ShoppingCartService接口中声明清空购物车的方法:

在ShoppingCartServiceImpl中实现清空购物车的方法:

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

功能测试

上一节:

商品浏览(day06)下-CSDN博客

下一节:

地址簿功能代码(day08上)-CSDN博客

相关推荐
前行的小黑炭43 分钟前
设计模式:为什么使用模板设计模式(不相同的步骤进行抽取,使用不同的子类实现)减少重复代码,让代码更好维护。
android·java·kotlin
Java技术小馆1 小时前
如何设计一个本地缓存
java·面试·架构
XuanXu2 小时前
Java AQS原理以及应用
java
风象南4 小时前
SpringBoot中6种自定义starter开发方法
java·spring boot·后端
mghio13 小时前
Dubbo 中的集群容错
java·微服务·dubbo
咖啡教室18 小时前
java日常开发笔记和开发问题记录
java
咖啡教室18 小时前
java练习项目记录笔记
java
鱼樱前端19 小时前
maven的基础安装和使用--mac/window版本
java·后端
RainbowSea19 小时前
6. RabbitMQ 死信队列的详细操作编写
java·消息队列·rabbitmq