day07-缓存商品、购物车

1. 缓存菜品

1.1 问题说明

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

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

1.2 实现思路

通过Redis来缓存菜品数据,减少数据库查询操作。
在这里插入图片描述

缓存逻辑分析:

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

在这里插入图片描述

1.3 代码开发

修改用户端接口 DishController 的 list 方法,加入缓存处理逻辑:
在这里插入图片描述

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

需要改造的方法:

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

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

2. 缓存套餐

2.1 Spring Cache

2.1.1 介绍

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.2 常用注解

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

注解说明
@EnableCaching开启缓存注解功能,通常加在启动类上
@Cacheable在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;如果没有缓存数据,调用方法并将方法返回值放到缓存中
@CachePut将方法的返回值放到缓存中
@CacheEvict将一条或多条数据从缓存中删除

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

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

2.1.3 入门案例

1). 环境准备

导入基础工程: 底层已使用 Redis 缓存实现
基础环境的代码,在我们今天的资料中已经准备好了, 大家只需要将这个工程导入进来就可以了。导入进来的工程结构如下:
在这里插入图片描述

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

引导类上加@EnableCaching:

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,用法如下:

    /**
     * CachePut:将方法返回值放入缓存
     * value:缓存的名称,每个缓存名称下面可以有多个key
     * key:缓存的key
     */
    @PostMapping
    @CachePut(value = "userCache", key = "#user.id")//key的生成:userCache::1
//    @CachePut(value = "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

	/**
	* Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,	  *调用方法并将方法返回值放到缓存中
	* value:缓存的名称,每个缓存名称下面可以有多个key
	* key:缓存的key
	*/
	@GetMapping
    @Cacheable(cacheNames = "userCache",key="#id")
    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

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

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

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

2.2 实现思路

实现步骤:

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

2.3 代码开发

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

<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

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

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

package com.sky;

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

@SpringBootApplication
@EnableTransactionManagement //开启注解方式的事务管理
@Slf4j
@EnableCaching
public class SkyApplication {
    public static void main(String[] args) {
        SpringApplication.run(SkyApplication.class, args);
        log.info("server started");
    }
}

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

	/**
     * 条件查询
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询套餐")
    @Cacheable(cacheNames = "setmealCache",key = "#categoryId") //key: setmealCache::100
    public Result<List<Setmeal>> list(Long categoryId) {
        Setmeal setmeal = new Setmeal();
        setmeal.setCategoryId(categoryId);
        setmeal.setStatus(StatusConstant.ENABLE);

        List<Setmeal> list = setmealService.list(setmeal);
        return Result.success(list);
    }

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

	/**
     * 新增套餐
     *
     * @param setmealDTO
     * @return
     */
    @PostMapping
    @ApiOperation("新增套餐")
    @CacheEvict(cacheNames = "setmealCache",key = "#setmealDTO.categoryId")//key: setmealCache::100
    public Result save(@RequestBody SetmealDTO setmealDTO) {
        setmealService.saveWithDish(setmealDTO);
        return Result.success();
    }
	/**
     * 批量删除套餐
     *
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("批量删除套餐")
    @CacheEvict(cacheNames = "setmealCache",allEntries = true)
    public Result delete(@RequestParam List<Long> ids) {
        setmealService.deleteBatch(ids);
        return Result.success();
    }
	/**
     * 修改套餐
     *
     * @param setmealDTO
     * @return
     */
    @PutMapping
    @ApiOperation("修改套餐")
    @CacheEvict(cacheNames = "setmealCache",allEntries = true)
    public Result update(@RequestBody SetmealDTO setmealDTO) {
        setmealService.update(setmealDTO);
        return Result.success();
    }

    /**
     * 套餐起售停售
     *
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("套餐起售停售")
    @CacheEvict(cacheNames = "setmealCache",allEntries = true)
    public Result startOrStop(@PathVariable Integer status, Long id) {
        setmealService.startOrStop(status, id);
        return Result.success();
    }

3. 添加购物车

3.1 需求分析和设计

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

字段名数据类型说明备注
idbigint主键自增
namevarchar(32)商品名称冗余字段
imagevarchar(255)商品图片路径冗余字段
user_idbigint用户id逻辑外键
dish_idbigint菜品id逻辑外键
setmeal_idbigint套餐id逻辑外键
dish_flavorvarchar(50)菜品口味
numberint商品数量
amountdecimal(10,2)商品单价冗余字段
create_timedatetime创建时间

说明:

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

3.2 代码开发

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

4. 查看购物车

4.1 需求分析和设计

当用户添加完菜品和套餐后,可进入到购物车中,查看购物中的菜品和套餐。

4.2 代码开发

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

5. 清空购物车

5.1 需求分析和设计

当点击清空按钮时,会把购物车中的数据全部清空。

5.2 代码开发

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/489682.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

分享全栈开发医疗小程序 -带源码课件(课件无解压密码),自行速度保存

课程介绍 分享全栈开发医疗小程序 -带源码课件&#xff08;课件无解压密码&#xff09;&#xff0c;自行速度保存&#xff01;看到好多坛友都在求SpringBoot2.X Vue UniAPP&#xff0c;全栈开发医疗小程序 - 带源码课件&#xff0c;我看了一下&#xff0c;要么链接过期&…

Docker 容器编排利器 Docker Compose

文章目录 一、Docker Compose 简介二、Docker Compose 安装2.1 Mac、Windows 平台默认支持2.2 Linux 安装(通过包管理)2.2.1 安装2.2.2 测试2.2.3 卸载 2.3 使用PIP 安装与卸载2.3.1 PIP安装2.3.2 PIP 卸载 三、基本使用3.1 术语3.2 部署Flask 应用 四、Compose 常用命令4.1 命…

【Java程序设计】【C00351】基于Springboot的疫情居家办公系统(有论文)

基于Springboot的疫情居家办公系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 项目获取 &#x1f345;文末点击卡片获取源码&#x1f345; 开发环境 运行环境&#xff1a;推荐jdk1.8&#xff1b; 开发工具&#xff1a;eclipse以及i…

windows环境安装,GOPATH设置,编写Go代码:

目录 windows环境安装 GOPATH设置&#xff1a; 开始编写Go代码&#xff1a; Go Hello World 实例 执行 Go 程序 注意 使用编译器&#xff1a;Sublime Text - 先进的代码编辑器 windows环境安装 windows环境下&#xff0c;go安装包安装成功后&#xff0c;会自动将go添加到…

cad不用插件怎么批量打印?分享2种轻松的方法!

在工程设计、建筑制图等领域&#xff0c;CAD软件是不可或缺的工具。然而&#xff0c;对于很多用户来说&#xff0c;批量打印CAD文件却是一个让人头疼的问题。难道每次都需要安装繁琐的插件才能实现吗&#xff1f;其实不然&#xff0c;今天我们就来介绍几种无需插件&#xff0c;…

Python爬虫学习完整版

一、什么是爬虫 网络爬虫&#xff0c;是一种按照一定规则&#xff0c;自动抓取互联网信息的程序或者脚本。由于互联网数据的多样性和资源的有限性&#xff0c;根据用户需求定向抓取相关网页并分析也成为如今主流的爬取策略。 1 爬虫可以做什么 你可以爬取网络上的的图片&#…

WPF —— Expander折叠栏 、菜单标签 menu

Expander 1 &#xff1a;Expander折叠栏 简介 Expander控件有一个箭头按钮。单击箭头时&#xff0c;Expander中的子元素将显示或隐藏。箭头“展开”控件&#xff0c;使其子控件可见。 2 &#xff1a;Expander常用的属性 IsEnabled 默认是打开或者折叠起来&#xff0c;true就…

记录‘No module named ‘notebook.notebookapp‘’导致jupyter打不开的解决方法

最初是因为无法重命名文件的问题&#xff0c;更新了notebook&#xff0c;但是更新之后打不开了 在终端输入 jupyter notebook 报错 File "/Users/maclin/Library/Python/3.8/bin/jupyter-notebook", line 5, in <module> from notebook.notebookapp import ma…

Python学习笔记(二)

一&#xff1a;异常&#xff1a; 1.1&#xff1a;异常处理&#xff1a; 1.2&#xff1a;异常捕获&#xff1a; 1.3&#xff1a;异常传递&#xff1a; 二&#xff1a;模块&#xff1a; 2.1&#xff1a;模块的定义&#xff1a; 2.2&#xff1a;模块的导入&#xff1a; 2.3&…

网络原理(7)——以太网数据帧和DNS协议(数据链路层和应用层)

目录 一、以太网数据帧&#xff08;数据链路层&#xff09; 二、DNS协议(域名解析系统&#xff0c;应用层协议) 一、以太网数据帧&#xff08;数据链路层&#xff09; 以太网横跨了数据链路层和物理层&#xff0c;这里只做简单介绍&#xff0c;因为普通程序员用不到这一块&am…

canvas画带透明度的直线和涂鸦

提示&#xff1a;canvas画线 文章目录 前言一、带透明度的直线和涂鸦总结 前言 一、带透明度的直线和涂鸦 test.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content…

#GIT|Git Flow#Gitflow工作流程

Gitflow是一种使用功能分支和多个主分支的Git分支模型&#xff0c;它适用于有预定发布周期的项目&#xff0c;也适用于DevOps最佳实践中的持续交付。这个工作流程不会添加任何新的概念或命令&#xff0c;而是为不同的分支分配了非常具体的角色&#xff0c;并定义了它们应该如何…

利用Python和IP技术实现智能旅游情报系统

文章目录 引言一、系统架构设计1. 数据采集模块2. 数据处理模块3. 用户界面模块 二、数据获取技术应用三、系统功能展示四、亮数据采集工具介绍五、总结六、号外 引言 随着旅游行业的不断发展&#xff0c;人们对旅游信息的需求也越来越大。为了帮助旅行者更好地规划行程&#…

PTA-练习8

目录 实验5-3 使用函数求Fibonacci数 实验5-4 输出每个月的天数 实验5-9 使用函数求余弦函数的近似值 实验5-11 空心的数字金字塔 实验6-6 使用函数验证哥德巴赫猜想 实验6-7 使用函数输出一个整数的逆序数 实验6-8 使用函数输出指定范围内的完数 实验8-1-7 数组循环右…

javascript三要素核验身份证号、姓名和人像是否匹配的身份证实名认证接口

在开发的过程中&#xff0c;总会用到各种各样的API接口来实现各种各样的功能。互联网信息时代&#xff0c;为确保注册用户身份信息的正确性&#xff0c;无论是手机端还是电脑端应用都需要进行实名认证来防止虚假身份的使用&#xff0c;维护公共利益和个人权益的安全&#xff0c…

云原生安全

云安全 https://wiki.teamssix.com 云服务安全 云服务&#xff0c;顾名思义就是云上的服务&#xff0c;简单的来说就是在云厂商&#xff08;例如 AWS、阿里云&#xff09;那里买的服务 云服务 S3 对象存储Simple Storage Service&#xff0c;简单的说就是一个类似网盘的东…

消息预知在线客服系统php网站源码

安装教程 服务器环境&#xff1a; 宝塔面板 &#xff0c;Nginx1.16-1.18&#xff0c;7.2.23<php<7.3&#xff08;因为升级了客服系统&#xff09;&#xff0c;Mysql5.6- Mysql5.7 网站运行目录为./public/ 访问网址http://你的域名/install.php进入安装程序即可 源码免…

制作小程序需要多少钱?成本分析与效益预测

在当今数字化时代&#xff0c;微信小程序已成为企业和个人拓展业务的重要工具。然而&#xff0c;许多人在考虑进入这一领域时&#xff0c;都会面临一个关键问题&#xff1a;制作一个小程序需要多少钱&#xff1f;下面和你一起探讨小程序开发的成本因素&#xff0c;帮助你更好地…

LGBM算法 原理

简介 GBDT (Gradient Boosting Decision Tree) 是机器学习中一个长盛不衰的模型&#xff0c;其主要思想是利用弱分类器&#xff08;决策树&#xff09;迭代训练以得到最优模型&#xff0c;该模型具有训练效果好、不易过拟合等优点。GBDT不仅在工业界应用广泛&#xff0c;通常被…

机器学习模型及其使用方法——《机器学习图解》

本书教你两件事——机器学习模型及其使用方法 机器学习模型有不同的类型&#xff0c;有些返回确定性的答案&#xff0c;例如是或否&#xff0c;而另一些返回概率性的答案。有些以问题的形式呈现&#xff1b;其他则使用假设性表达。这些类型的一个共同点是它们都返回一个答案或…