瑞吉外卖优化

1.缓存问题

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

瑞吉外卖优化_第1张图片

2.导入依赖 和配置

        
            org.springframework.boot
            spring-boot-starter-data-redis
        
spring:  
  redis:
    host: 自己的地址
    password: 自己的密码
    database: 0
    port: 6379

3.key序列化配置类

@Configuration
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory connectionFactory){
        RedisTemplate 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 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 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 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中

瑞吉外卖优化_第2张图片

5.缓存菜品数据

5.1实现思路

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

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

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

5.2代码风暴

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

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

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

        }

        //3.如果不存在,查询数据库,再缓存到redis
        LambdaQueryWrapper 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 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 queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(DishFlavor::getDishId, dishId);
            List 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测试

瑞吉外卖优化_第3张图片

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

瑞吉外卖优化_第4张图片

瑞吉外卖优化_第5张图片

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

@PutMapping()
    public R 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 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引入依赖 

        
            org.springframework.boot
            spring-boot-starter-data-redis
        

        
            org.springframework.boot
            spring-boot-starter-cache
        

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 setmeal) {
        LambdaQueryWrapper 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 list = setmealService.list(queryWrapper);
        return R.success(list);
    }

6.4删除套餐时删除缓存

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

瑞吉外卖优化_第6张图片

你可能感兴趣的:(瑞吉外卖,spring,java,后端)