瑞吉外卖优化

news2025/1/18 9:57:41

1.缓存问题

  • 用户数量多,系统访问量大频繁访问数据库,系统性能下降,用户体验差

2.导入依赖 和配置

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
spring:  
  redis:
    host: 自己的地址
    password: 自己的密码
    database: 0
    port: 6379

3.key序列化配置类

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory connectionFactory){
        RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();
        //默认的key序列化器为:JdkSerializationRedisSerializer
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

4.缓存短信验证码

4.1实现思路

1.引入RedisTemplate

2.设置验证码缓存到redis

3.登陆成功删除redis中的验证码

4.2代码 

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @Autowired
    private UserService userService;


    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 发送手机短信验证码
     *
     * @param user
     * @return
     */
    @PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user, HttpSession session) {
        //1.获取手机号
        String phone = user.getPhone();
        if (StringUtils.isNotEmpty(phone)) {

            //2.生成四位的验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();

            //查看验证码
            log.info("code={}", code);

            //3.调用阿里云短信服务完成发送
            //若要真的发送,执行下面
//            SMSUtils.sendMessage("签名","",phone,code);


            //4.生成的验证码保存到session
//            session.setAttribute(phone, code);

            //优化,将生成的验证码缓存到redis中,有效期5分钟
            redisTemplate.opsForValue().set(phone, code, 5, TimeUnit.MINUTES);

            return R.success("发送验证码发送成功");

        }
        return R.success("发送失败");
    }


    /**
     * 移动端登录
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session) {
        //1.获取手机号
        String phone = map.get("phone").toString();

        //2.获取验证码
        String code = map.get("code").toString();

        //3.从Session中获取保存的验证码进行比对
//        Object codeInSession = session.getAttribute(phone);

        //优化:从redis中获取缓存验证码
        Object codeInSession = redisTemplate.opsForValue().get(phone);

        //4.如果比对成功,判断手机号是否在用户表中
        if (codeInSession != null && codeInSession.equals(code)) {//登陆成功
            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone, phone);
            User user = userService.getOne(queryWrapper);
            if (user == null) {//新用户
                //5.如果不在用户表,则自动完成注册
                user = new User();
                user.setPhone(phone);
                user.setStatus(1);
                userService.save(user);
            }
            session.setAttribute("user", user.getId());

            //优化:如果用户登陆成功,删除redis缓存的验证码
            redisTemplate.delete(phone);

            return R.success(user);
        }
        return R.error("登陆失败");
    }
}

4.3测试

已经存到redis中

5.缓存菜品数据

5.1实现思路

1、改造DishController的list方法,先从Redis中获取菜品数据,如果有则直接返回,无需查询数据库;如果没有则查询数据库,并将查询到的菜品数据放入Redis。

2、改造DishController的save和update方法,加入清理缓存的逻辑、

注意:在使用缓存过程中,要注意保证数据库中的数据和缓存中的数据一致,如果数据库中的数据发生变化,需要及时清理缓存数据。

5.2代码风暴

   @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish) {
        List<DishDto> dishDtoList = null;
        //动态构造key
        String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();

        //1.先从redis中获取缓存数据

        dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);
        if (dishDtoList != null) {
            //2.如果存在,直接返回,无需查询数据库
            return R.success(dishDtoList);

        }

        //3.如果不存在,查询数据库,再缓存到redis
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
        queryWrapper.eq(Dish::getStatus, 1);
        queryWrapper.orderByDesc(Dish::getSort).orderByAsc(Dish::getUpdateTime);

        List<Dish> list = dishService.list(queryWrapper);

        dishDtoList = list.stream().map((item) -> {
            DishDto dishDto = new DishDto();
            //拷贝
            BeanUtils.copyProperties(item, dishDto);

            Long categoryId = item.getCategoryId();//分类id
            Category category = categoryService.getById(categoryId);
            if (category != null) {
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }
            Long dishId = item.getId();
            LambdaQueryWrapper<DishFlavor> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(DishFlavor::getDishId, dishId);
            List<DishFlavor> dishFlavors = dishFlavorService.list(queryWrapper1);
            dishDto.setFlavors(dishFlavors);
            return dishDto;
        }).collect(Collectors.toList());

        //查询完数据库,在将数据缓存到redis
        redisTemplate.opsForValue().set(key,dishDtoList,60, TimeUnit.MINUTES);

        return R.success(dishDtoList);
    }

 5.3测试

再次查询时就是从redis缓存中获取了

5.3更新菜品时删除对应的redis缓存 

@PutMapping()
    public R<String> put(@RequestBody DishDto dishDto) {
        dishService.updateWithFlavor(dishDto);

        //清理所有菜品的缓存数据
//        Set keys = redisTemplate.keys("dish_*");
//        redisTemplate.delete(keys);

        //精确清理,清理某个分类下面的缓存
        String key="dish_"+dishDto.getCategoryId()+"_1";
        redisTemplate.delete(key);
        return R.success("修改成功");
    }

5.4添加菜品时删除对应的redis缓存

 @PostMapping()
    public R<String> save(@RequestBody DishDto dishDto) {
        dishService.saveWithFlavor(dishDto);
        //清理所有菜品的缓存数据
//        Set keys = redisTemplate.keys("dish_*");
//        redisTemplate.delete(keys);

        //精确清理,清理某个分类下面的缓存
        String key="dish_"+dishDto.getCategoryId()+"_1";
        redisTemplate.delete(key);

        return R.success("新增菜品成功");
    }

6.缓存套餐数据【注解】

  • 1、导入Spring Cache和Redis相关maven坐标
  • 2、在application.yml中配置缓存数据的过期时间
  • 3、在启动类上加入@EnableCaching注解,开启缓存注解功能
  • 4、在SetmealController的list方法上加入@Cacheable注解
  • 5、在SetmealController的save和delete方法上加入CacheEvict注解

6.1引入依赖 

        <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>

6.2开启注解缓存

@Slf4j
@SpringBootApplication
@ServletComponentScan
@EnableTransactionManagement
@EnableCaching //开启注解缓存
public class ProductRuijiApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProductRuijiApplication.class, args);
        log.info("程序启动成功");
    }
}

6.3查询套餐时加入缓存

    @Cacheable(value = "setmealCache",key = "#setmeal.categoryId+'_'+#setmeal.status")
    @GetMapping("/list")
    public R<List<Setmeal>> list( Setmeal setmeal) {
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());
        queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);
        List<Setmeal> list = setmealService.list(queryWrapper);
        return R.success(list);
    }

6.4删除套餐时删除缓存

   @CacheEvict(value = "setmealCache",allEntries = true)
    @DeleteMapping
    public R<String> delete(@RequestParam List<Long> ids) {
        setmealService.removeWithDish(ids);
        return R.success("删除套餐成功");
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言好好题(一维数组)

两天没有更新了&#xff0c;贴纸们&#xff0c;有没有想我呀。&#x1f604;&#x1f604;&#x1f604; 好了&#xff0c;就寒暄到这里吧&#xff0c;下面请看题&#xff1a; 有序序列判断 输入一个整数序列&#xff0c;判断是否是有序序列&#xff0c;有序&#xff0c;指序列…

Java基础(程序控制结构篇)

Java的程序控制结构与C语言一致&#xff0c;分为顺序结构、选择结构&#xff08;分支结构&#xff09;和循环结构三种。 一、顺序结构 如果程序不包含选择结构或是循环结构&#xff0c;那么程序中的语句就是顺序的逐条执行&#xff0c;这就是顺序结构。 import java.util.Sc…

iperf3 网络测试

iperf3 测试网络的上下行带宽 下载地址 https://iperf.fr/iperf-download.php 开启服务器 开启客户端 常用命令 -c 代表客户端-s 代表服务端-u 代表 udp-r 代表数据方向是否反向 https://baijiahao.baidu.com/s?id1731514357681464971&wfrspider&forpc

c语言-操作符详解(含优先级与结合性)

文章目录 了解什么是操作数、操作符操作数&#xff1a;操作符 操作符详解&#xff1a;1.算术操作符&#xff1a; 、- 、* 、/ 、%2.移位操作符: << >>3.位操作符: & | ^4. 赋值操作符: 、 、 - 、 * 、 / 、% 、<< 、>> 、& 、| 、^5. 单⽬操…

移动机器人,开启智能柔性制造新篇章

智能制造是当今工业发展的必然趋势&#xff0c;而柔性制造则是智能制造的重要组成部分。在这个快速变革的时代&#xff0c;如何提高生产效率、降低成本、增强灵活性成为了制造业的关键挑战。富唯智能移动机器人应运而生&#xff0c;为柔性制造注入了新的活力。 基于富唯智能AI-…

xss-labs靶场6-10关

文章目录 前言一、靶场6-10关1、关卡62、关卡73、关卡84、关卡95、关卡10 总结 前言 此文章只用于学习和反思巩固xss攻击知识&#xff0c;禁止用于做非法攻击。注意靶场是可以练习的平台&#xff0c;不能随意去尚未授权的网站做渗透测试&#xff01;&#xff01;&#xff01; …

xilinx zynq平台 elf文件到bin文件格式转化

在嵌入式实际开发过程中&#xff0c;因为系统资源有限&#xff0c;需要尽可能的节省资源&#xff0c;尤其是flash资源。在某些场景下&#xff0c;需要直接执行占用内存较小的bin文件&#xff0c;而非elf文件。但xilinx SDK编译的输出文件一般为elf文件&#xff0c;所以需要进行…

国际版Amazon Lightsail的功能解析

Amazon Lightsail是一项易于使用的云服务,可为您提供部署应用程序或网站所需的一切,从而实现经济高效且易于理解的月度计划。它是部署简单的工作负载、网站或开始使用亚马逊云科技的理想选择。 作为 AWS 免费套餐的一部分&#xff0c;可以免费开始使用 Amazon Lightsail。注册…

【Delphi】使用TWebBrowser执行JavaScript命令传入JSON参数执行出错解决方案

目录 一、问题背景&#xff1a; 二、实际示例&#xff1a; 三、解决方案&#xff1a; 1. Delphi 代码&#xff1a; 2. javaScript代码&#xff1a; 一、问题背景&#xff1a; 在用Delphi开发程序&#xff0c;无论是移动端还是PC端&#xff0c;都可以很方便的使用TWebBrows…

LongAccumulator

原子操作之LongAccumulator 和LongAdder的区别在于&#xff0c;LongAdder是在Cell里面只能做加减操作&#xff0c;不能乘除&#xff0c;而LongAccumulator就可以定义乘除操作。原理和LongAdder都是一样的&#xff0c;一个Base和一个Cells数组。 原文跳转地址

Java游戏之飞翔的小鸟

前言 飞翔的小鸟 小游戏 可以作为 java入门阶段的收尾作品 &#xff1b; 需要掌握 面向对象的使用以及了解 多线程&#xff0c;IO流&#xff0c;异常处理&#xff0c;一些java基础等相关知识。一 、游戏分析 1. 分析游戏逻辑 &#xff08;1&#xff09;先让窗口显示出来&#x…

51单片机按键控制LED灯亮灭的N个玩法

51单片机按键控制LED灯亮灭的N个玩法 1.概述 这篇文章介绍按键的使用&#xff0c;以及通过控制LED灯的小实验&#xff0c;发现按键中存在的问题&#xff0c;然后思考并解决这些问题。达到熟练使用按键控制元器件。 2.搭建硬件环境 1.硬件准备 名称型号数量单片机STC12C205…

【办公常识】写好的代码如何上传?使用svn commit

首先找到对应的目录 找到文件之后点击SVN Commit

如何做好项目管理?年薪百万项目大佬一直在用这11张图

大家好&#xff0c;我是老原。 日常工作中&#xff0c;我们会遇到各种大大小小的工作项目&#xff0c;如何能让项目保质保量的完成&#xff0c;是我们项目经理的目标。 项目管理的流程可以说是由一系列的子过程组成的&#xff0c;它是一个循序渐进的过程&#xff0c;所以不能…

排序算法-----快速排序(非递归实现)

目录 前言 快速排序 基本思路 非递归代码实现 前言 很久没跟新数据结构与算法这一栏了&#xff0c;因为数据结构与算法基本上都发布完了&#xff0c;哈哈&#xff0c;那今天我就把前面排序算法那一块的快速排序完善一下&#xff0c;前面只发布了快速排序递归算法&#xff0c;…

智能合约安全漏洞与解决方案

// SPDX-License-Identifier: MIT pragma solidity ^0.7.0;import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v3.3/contracts/math/SafeMath.sol";/*智能合约安全在智能合约中安全问题是一个头等大事&#xff0c;因为智能合约不像其他语…

LeetCode 2304. 网格中的最小路径代价:DP

【LetMeFly】2304.网格中的最小路径代价&#xff1a;DP 力扣题目链接&#xff1a;https://leetcode.cn/problems/minimum-path-cost-in-a-grid/ 给你一个下标从 0 开始的整数矩阵 grid &#xff0c;矩阵大小为 m x n &#xff0c;由从 0 到 m * n - 1 的不同整数组成。你可以…

网工内推 | 合资公司网工,CCNP/HCIP认证优先,朝九晚六

01 中企网络通信技术有限公司 招聘岗位&#xff1a;网络工程师 职责描述&#xff1a; 1、按照工作流程和指引监控网络运行情况和客户连接状况&#xff1b; 2、确保各监控系统能正常运作&#xff1b; 3、快速响应各个网络告警事件&#xff1b; 4、判断出网络故障&#xff0c;按…

【LeetCode刷题】--39.组合总和

39.组合总和 本题详解&#xff1a;回溯算法剪枝 class Solution {public List<List<Integer>> combinationSum(int[] candidates, int target) {int len candidates.length;List<List<Integer>> res new ArrayList<>();if (len 0) {return r…

栈和队列【详解】

目录 一、栈 1.栈的定义 2.栈的初始化 3.入栈 4.出栈 5.获取栈顶元素 6.获取栈元素的个数 7.判断栈是否为空 8.销毁栈 二、队列 1.队列的定义 2.入队 3.出队 4.获取队头元素 5.获取队尾元素 6.判断队列是否为空 7.获取队列的元素个数 8.销毁队列 前言&#xf…