瑞吉外卖(终章)项目优化

2022-09-22 15:28:55 浏览数 (1)

01、缓存优化

1、环境搭建

01.依赖

代码语言:javascript复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

02.配置文件

代码语言:javascript复制
spring: 
    redis:
        host: 192.168.136.200
        port: 6379
        password: 131400
        database: 0

03.配置类

代码语言:javascript复制
package cn.mu00.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()); // key序列化
        //redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // value序列化

        redisTemplate.setConnectionFactory(connectionFactory);
        return redisTemplate;
    }
}

2、缓存短信验证码

位置:UserController

代码语言:javascript复制
@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("小沐沐吖","SMS_248910220",phone,code);

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

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

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

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

/**
 * 移动端用户登录
 * @param user
 * @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中获取保存的验证码
    // String codeInSession = (String) session.getAttribute(phone);

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

    // 进行验证码校验
    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);
            userService.save(user);
        }
        session.setAttribute("user", user.getId());

        // 如果用户登录成功,删除Redis中缓存得验证码
        redisTemplate.delete(phone);
        return R.success(user);
    }
    return R.error("登录成功");
}

3、缓存菜品数据

位置:DishController 方法:list

代码语言:javascript复制
/**
 * 根据条件查询菜品数据
 * @param dish
 * @return
 */
@GetMapping("/list")
public R<List<DishDto>> list(Dish dish){

    List<DishDto> dishDtoList = null;

    String key = "dish"   dish.getCategoryId()   "-"   dish.getStatus();

    // 先从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);

        // 分类id
        Long categoryId = item.getCategoryId();
        // 根据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);

        List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper);

        dishDto.setFlavors(dishFlavorList);

        return dishDto;
    }).collect(Collectors.toList());

    // 缓存数据
    redisTemplate.opsForValue().set(key, dishDtoList, 60, TimeUnit.MINUTES);

    return R.success(dishDtoList);
}

位置:DishController 方法:save,update 清除缓存

代码语言:javascript复制
// 清理指定分类下菜品得缓存
String key = "dish_"   dishDto.getCategoryId()   "_1";
redisTemplate.delete(key);

位置:DishController 方法:delete,status 清除缓存

代码语言:javascript复制
// 清理所有菜品得缓存
Set keys = redisTemplate.keys("dish_*");
redisTemplate.delete(keys);

4、Spring Cache

1、介绍

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

Spring Cache提供了一层抽象,底层可以切换不同的Cache实现。具体就是通过CacheManager接口来统一不同的缓存技术

Spring Cache是SPring提供的各种缓存技术抽象接口

针对不同的缓存技术需要实现不同的CacheManager

CacheManager

描述

EhCacheCacheManager

使用EhCache作为缓存技术

GuavaCacheManager

使用谷歌的GuavaCache作为缓存技术

RedisCacheManager

使用Redis作为缓存技术

2、常用注解

注解

说明

@EnableCaching

开启缓存注解功能

@Cacheable

在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将返回值放到缓存中

@CachePut

将方法的返回值放到缓存中

@CacheEvict

将一条或多条数据从缓存中删除

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

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

5、缓存套餐数据

1、添加依赖

代码语言:javascript复制
<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、代码实现

01.在配置文件中添加

代码语言:javascript复制
spring: 
    cache:
        redis:
            time-to-live: 1800000

02.在启动类添加注解

代码语言:javascript复制
@EnableCaching

03.R实现序列号接口

代码语言:javascript复制
public class R<T> implements Serializable{...}

04.位置:SetmealController 方法list

代码语言:javascript复制
@Cacheable(value = "setmealCache", key = "#setmeal.categoryId   '_'   #setmeal.status")

05.位置:SetmealController 方法:delete、status、save、update 清除所有缓存

代码语言:javascript复制
@CacheEvict(value = "setmealCache", allEntries = true)

0 人点赞