reggie优化01-缓存短信验证码和菜品数据

news2024/11/27 10:30:41

1、缓存短信验证码

1.1 Redis配置类RedisConfig

在config包下,创建Redis配置类RedisConfig:
纳入Git管理:
在这里插入图片描述

package com.itheima.reggie.config;

import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

@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.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
}

1.2 思路分析和代码改造

之前的短信验证码存放在session中,是存在一定的时间有效期,现在要将短信验证码存放到Redis中。
在这里插入图片描述
1、注入RedisTemplate对象:

    @Autowired
    private RedisTemplate redisTemplate;

2、在sendMsg方法中,将生成的验证码缓存到Redis中,并且设置有效期为5分钟:

       //将生成的验证码缓存到Redis中,并且设置有效期为5分钟
       redisTemplate.opsForValue().set(phone,code,5,TimeUnit.MINUTES);

其中:redisTemplate.opsForValue().set(key, value, 时间, 时间单位)

3、在login方法中,从Redis中获取缓存的验证码:

       //从Redis中获取缓存的验证码
       Object codeInSession = redisTemplate.opsForValue().get(phone);

4、在sendMsg方法中,登录成功,删除Redis中缓存的验证码:

       //如果用户登录成功,删除Redis中缓存的验证码
       redisTemplate.delete(phone);

1.3 总Code和运行:

package com.itheima.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.User;
import com.itheima.reggie.service.UserService;
import com.itheima.reggie.utils.SMSUtils;
import com.itheima.reggie.utils.ValidateCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@RestController
@RequestMapping("/user")
@Slf4j
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){
        //获取手机号
        String phone = user.getPhone();

        if(StringUtils.isNotEmpty(phone)){
            //生成随机的4位验证码
            String code = ValidateCodeUtils.generateValidateCode(4).toString();
            log.info("code={}",code);

            //调用阿里云提供的短信服务API完成发送短信
            //SMSUtils.sendMessage("瑞吉外卖","",phone,code);

            //需要将生成的验证码保存到Session
            //session.setAttribute(phone,code);

            //将生成的验证码缓存到Redis中,并且设置有效期为5分钟
            redisTemplate.opsForValue().set(phone,code,5,TimeUnit.MINUTES);

            return R.success("手机验证码短信发送成功");
        }

        return R.error("短信发送失败");
    }

    /**
     * 移动端用户登录
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session){
        log.info(map.toString());

        //获取手机号
        String phone = map.get("phone").toString();

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

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

        //从Redis中获取缓存的验证码
        Object codeInSession = redisTemplate.opsForValue().get(phone);

        //进行验证码的比对(页面提交的验证码和Session中保存的验证码比对)
        if(codeInSession != null && codeInSession.equals(code)){
            //如果能够比对成功,说明登录成功

            LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(User::getPhone,phone);

            User user = userService.getOne(queryWrapper);
            if(user == null){
                //判断当前手机号对应的用户是否为新用户,如果是新用户就自动完成注册
                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("登录失败");
    }

}

运行移动端,发送验证码请求后,redis数据库结果显示:
在这里插入图片描述

2、缓存菜品数据

2.1 思路分析和代码改造

在这里插入图片描述
1、注入RedisTemplate对象:

    @Autowired
    private RedisTemplate redisTemplate;

2、在list中,先从redis中获取缓存数据,不过先要找到key值,通过浏览器发送过来的请求可知道key由分类ID和状态组成。
在这里插入图片描述

      //动态构造key
      String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();//dish_1397844391040167938_1

      //先从redis中获取缓存数据
      dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);

3、

  • 如果存在,直接返回,无需查询数据库。
  • 如果不存在,需要查询数据库,将查询到的菜品数据缓存到Redis

4、修改和保存数据要清理缓存:

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

       //清理某个分类下面的菜品缓存数据
       String key = "dish_" + dishDto.getCategoryId() + "_1";
       redisTemplate.delete(key);

2.2 总Code和运行:

package com.itheima.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.reggie.common.R;
import com.itheima.reggie.dto.DishDto;
import com.itheima.reggie.entity.Category;
import com.itheima.reggie.entity.Dish;
import com.itheima.reggie.entity.DishFlavor;
import com.itheima.reggie.service.CategoryService;
import com.itheima.reggie.service.DishFlavorService;
import com.itheima.reggie.service.DishService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 菜品管理
 */
@RestController
@RequestMapping("/dish")
@Slf4j
public class DishController {
    @Autowired
    private DishService dishService;

    @Autowired
    private DishFlavorService dishFlavorService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 新增菜品
     * @param dishDto
     * @return
     */
    @PostMapping
    public R<String> save(@RequestBody DishDto dishDto){
        log.info(dishDto.toString());

        dishService.saveWithFlavor(dishDto);

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

        //清理某个分类下面的菜品缓存数据
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);

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

    /**
     * 菜品信息分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page,int pageSize,String name){

        //构造分页构造器对象
        Page<Dish> pageInfo = new Page<>(page,pageSize);
        Page<DishDto> dishDtoPage = new Page<>();

        //条件构造器
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        //添加过滤条件
        queryWrapper.like(name != null,Dish::getName,name);
        //添加排序条件
        queryWrapper.orderByDesc(Dish::getUpdateTime);

        //执行分页查询
        dishService.page(pageInfo,queryWrapper);

        //对象拷贝
        BeanUtils.copyProperties(pageInfo,dishDtoPage,"records");

        List<Dish> records = pageInfo.getRecords();

        List<DishDto> list = records.stream().map((item) -> {
            DishDto dishDto = new DishDto();

            BeanUtils.copyProperties(item,dishDto);

            Long categoryId = item.getCategoryId();//分类id
            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);

            if(category != null){
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }
            return dishDto;
        }).collect(Collectors.toList());

        dishDtoPage.setRecords(list);

        return R.success(dishDtoPage);
    }

    /**
     * 根据id查询菜品信息和对应的口味信息
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public R<DishDto> get(@PathVariable Long id){

        DishDto dishDto = dishService.getByIdWithFlavor(id);

        return R.success(dishDto);
    }

    /**
     * 修改菜品
     * @param dishDto
     * @return
     */
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
        log.info(dishDto.toString());

        dishService.updateWithFlavor(dishDto);

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

        //清理某个分类下面的菜品缓存数据
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);

        return R.success("修改菜品成功");
    }

    /**
     * 根据条件查询对应的菜品数据
     * @param dish
     * @return
     */
    /*@GetMapping("/list")
    public R<List<Dish>> list(Dish dish){
        //构造查询条件
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId());
        //添加条件,查询状态为1(起售状态)的菜品
        queryWrapper.eq(Dish::getStatus,1);

        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);

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

        return R.success(list);
    }*/

    @GetMapping("/list")
    public R<List<DishDto>> list(Dish dish){
        List<DishDto> dishDtoList = null;

        //动态构造key
        String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();//dish_1397844391040167938_1

        //先从redis中获取缓存数据
        dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key);

        if(dishDtoList != null){
            //如果存在,直接返回,无需查询数据库
            return R.success(dishDtoList);
        }

        //构造查询条件
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId());
        //添加条件,查询状态为1(起售状态)的菜品
        queryWrapper.eq(Dish::getStatus,1);

        //添加排序条件
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(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
            //根据id查询分类对象
            Category category = categoryService.getById(categoryId);

            if(category != null){
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }

            //当前菜品的id
            Long dishId = item.getId();
            LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>();
            lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId);
            //SQL:select * from dish_flavor where dish_id = ?
            List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);
            dishDto.setFlavors(dishFlavorList);
            return dishDto;
        }).collect(Collectors.toList());

        //如果不存在,需要查询数据库,将查询到的菜品数据缓存到Redis
        redisTemplate.opsForValue().set(key,dishDtoList,60, TimeUnit.MINUTES);

        return R.success(dishDtoList);
    }

}

在这里插入图片描述

3、Git合并分支

在这里插入图片描述

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

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

相关文章

接口自动化测试框架unittest和pytest差异比较

前言 说到 Python 的单元测试框架&#xff0c;想必接触过 Python 的朋友脑袋里第一个想到的就是unittest。 的确&#xff0c;作为 Python 的标准库&#xff0c;它很优秀&#xff0c;并被广泛用于各个项目。但你知道吗&#xff1f;其实在 Python 众多项目中&#xff0c;主流的单…

【ROS机械臂入门教程】

首先声明一下&#xff0c;此项目是参考B站哈萨克斯坦UP的【ROS机械臂入门教程】&#xff0c;前期以复现【机械臂视觉抓取从理论到实战】 此内容为他研究生生涯的阶段性成果展示和技术分享&#xff0c;所有数据和代码均开源。所以鹏鹏我又特此来复现一下&#xff0c;我采用的硬件…

Redis源码篇 - Reactor设计模式 和 Redis Reactor设计模式

Reactor &#xff1a;反应器模式或者应答者模式&#xff0c;它是一种基于事件驱动的设计模式。拥有一个或者多个输入源&#xff0c;通过反应器分发给多个worker线程处理&#xff0c;实现并发场景下事件处理。 此图网上找的&#xff0c;画的很好&#xff1a;

中国新一代载人运载火箭“长征十号”发布,衍生型号积极研发中

我国新一代载人运载火箭“长征十号”已发布&#xff0c;主要用于将月面着陆器和登月飞船送入地月转移轨道。此外&#xff0c;“长征十号”还有一个衍生型号正在积极研发中。根据中国运载火箭技术研究院官方消息&#xff0c;近期&#xff0c;火箭院北京强度环境研究所圆满完成了…

SQlite3数据库相关相关命令

1&#xff09;系统命令 以 ‘.’ 开头 .help 帮助手册 .exit 退出 .table 查看当前数据库的有的表格名 .databases .schema 查看表的结构属性2&#xff09;sql语句 以 ;结尾 1. 创建表格 create table <table-name> (id integer, age integer, name char, score f…

夜深人静学32系列18——DMA+ADC单/多通道采集

夜深人静学32系列18——DMAADC单/多通道采集 DMA & ADC (理论篇)DMADMA框图DMA通道与外设对应表 ADC重要知识不同模式组合的作用 为什么要是用DMA ADC&#xff1f;DMA & ADC (实战篇)任务要求原理图CubeMX配置代码实现实验现象 很久没更新了&#xff0c;这次我们浅浅的…

MVSNet、PatchMatchNet环境配置、运行演示

文章目录 1 环境配置要求2 配置流程2.1 创建新环境mvs环境2.2 配置 PatchMatchNet环境3 程序运行演示1 环境配置要求 Ubuntu 18.04 python 3.7 , CUDA 10.1。 requirements.txt torch==1.4.0 torchvision==0.5.0 opencv-python numpy plyfile pillow tensorboard以上环境MV…

Docker 快速搞定 selenium grid 分布式测试

目录 前言&#xff1a; NO.1 搭环境 NO.2 写代码 NO.3 并发 感想 前言&#xff1a; Docker是一个流行的容器化平台&#xff0c;它可以帮助开发人员快速构建、部署和运行应用程序。Selenium Grid是一个用于分布式测试的工具&#xff0c;它可以并行执行多个测试用例&#xf…

做接口测试需要哪些技能、怎么做?

目录 1、什么是接口测试&#xff1f; 2、接口测试需要会什么&#xff1f; 3、如何学这些技能&#xff1f; 4、如何获取接口相关信息&#xff1f; 5、如何进行进行接口测试&#xff1f; 6、自动化接口测试 7、其他 1、什么是接口测试&#xff1f; 定义&#xff1a;测试系…

【ARM Coresight 系列文章 10 - ARM Coresight STM 介绍及使用】

文章目录 ARM System Trace MacrocellSTM FeaturesSTM 与 ETM/PTM的差异STM Master ARM System Trace Macrocell ARM 对STM 的解释是其支持高带宽的"仪器化输出"&#xff0c;仪器化输出其实也就是像 Cortex-M 系列中的 ITM 一样&#xff0c;通过将数据写入 STM 的 s…

(中等)LeetCode 328. 奇偶链表 Java

对于链表中有零个、一个、两个节点的情况&#xff0c;直接返回即可 对于链表的节点数大于两个的情况&#xff0c;需要讨论&#xff0c;看当前节点是第奇数个节点还是第偶数个节点 class Solution {public ListNode oddEvenList(ListNode head) {if (head null || head.next …

Android Glide onlyRetrieveFromCache downloadOnly submit ,kotlin

Android Glide onlyRetrieveFromCache downloadOnly submit ,kotlin Glide预加载&#xff0c;加载到磁盘或者内存缓存&#xff0c;然后加载的图片只从缓存&#xff08;磁盘缓存或者内存缓存&#xff09;中取。 private val imageFile File("/storage/emulated/0/DCIM/Ca…

百科创建必看攻略!人物百度百科怎么创建?5分钟教会你创建人物百度百科词条

百度人物百科是一个广受欢迎的在线百科平台&#xff0c;它为用户提供了一个便捷的方式来了解各种各样的人物信息。如果你有一个人物的详细资料&#xff0c;你可以通过创建一个百度人物百科页面来分享这些信息。 下面是分媒互动分享的创建百度人物百科页面的步骤以及需要注意的几…

ConfigMap 补充 和 Secret

对于上一篇文章我们分享了为什么要使用 ConfigMap &#xff0c;我们创建 ConfigMap 的时候可以传入单个或者多个键值对&#xff0c;也可以传入文件&#xff0c;还分享了如何简单的传入 ConfigMap 里面的数据作为环境变量 我们补充一下使用 ConfigMap 一次性传递多个条目吧 一…

直击现场|Sui Builder House巴黎站倒计时0天

Sui Builder House下一站即将在法国巴黎举行&#xff0c;为世界各地的开发人员提供在这座被誉为“City of Light”的城市学习和交流的机会。 Sui Builder House将于7月18–19日在巴黎举行&#xff0c;这是展示Sui突破性技术的绝佳机会。在丹佛Builder House活动之后&#xff0c…

PCIe总线的链路训练

目录 概述 链路训练的目的 几个关键概念 Lane reveral &#xff1a; Polarity inversion&#xff1a; De-skew&#xff1a; link number&#xff1a; Lane number&#xff1a; Bit lock&#xff1a; Symbol lock&#xff1a; 几个特殊序列&#xff1a; TS1和TS2&am…

深度学习系列8——分类模型评估指标

1. 概述 1.1 分类 分类&#xff1a;标签为离散值。 回归&#xff1a;标签为连续值。 2. 混淆矩阵 二分类的混淆矩阵&#xff1a; TP 和 TN 为网络预测正确的部分&#xff0c;FP 和 FN 为网络预测错误的部分。 3. 二级指标 准确率&#xff1a; 针对模型的整体评估&#xf…

Java基础之复习笔记(上)

目录 一、Java是什么&#xff1f; &#x1f496;Java概念 &#x1f496;Java运行机制 二、Java的语言基础 &#x1f496;关键字 &#x1f496;基本数据类型 &#x1f496;运算符 三、Java逻辑控制 &#x1f496;分支结构 &#x1f496;循环结构 四、Java的方法 &#…

嵌入式基础知识-系统调度

系统调度是操作系统重要功能&#xff0c;在嵌入式开发&#xff0c;也要了解系统调度的基本原理。对于嵌入式Linux开发&#xff0c;一般使用多线程和多进程开发&#xff0c;对于运行RTOS的嵌入式系统&#xff0c;一般使用多任务开发。这些线程、进程、任务的调度&#xff0c;有许…

RS232转Profinet网关怎么设置

大家好&#xff0c;今天我要给大家带来一个很有意思的案例分享。你们猜猜&#xff0c;这回我们要用远创智控的一款神奇的网关YC-RSPN-002做什么呢&#xff1f;没错&#xff0c;我们要把一台扫码枪设备通过这个RS232转PROFINET网关&#xff0c;接入到一台西门子S7-1200PLC的Prof…