目录

1、问题说明

2、环境搭建

2.1、导入依赖

2.2、配置文件

2.3、配置类

3、缓存短信验证码

3.1、实现思路

3.2、代码

3.2.1、发送验证码时将验证码缓存到Redis

3.2.1、登录

4、缓存菜品数据

4.1、实现思路

4.2、代码

4.2.1、list 方法

4.2.2、update 方法

4.2.3、save 方法

5、Spring Cache

5.1、Spring Cache 介绍

5.2、常用注解

5.3、基本使用

5.3.1、依赖

5.3.2、@CachePut

5.3.3、@CacheEvict

5.3.4、Cacheable

5.4、以 Redis 作为缓存

5.4.1、依赖

5.4.2、application.yml 配置

6、缓存套餐数据

6.1、实现思路

6.2、代码

6.2.1、导入依赖

6.2.2、设置缓存数据过期时间

6.2.3、开启缓存,加上 @EnableCaching  注解

6.2.4、R 类序列化

6.2.5、list 方法

6.2.6、delete 和 save 方法 


1、问题说明

方法:通过缓存进行优化

2、环境搭建

2.1、导入依赖

在 pom.xml 中导入依赖

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

2.2、配置文件

在 application.yml 中添加配置

注意,这里由于使用 host、port、password 报错 ERR wrong number of arguments for ‘auth‘ command,所以改为使用 url 进行配置

详情查看:ERR wrong number of arguments for ‘auth‘ command_lisen_123a的博客-CSDN博客

spring:
  redis:
#    host: 192.168.44.128
#    port: 6379
    username: root
#    password: ***
    url: redis://<password>@<url>:<port>

2.3、配置类

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;

/**
 * Redis配置类
 * @Author zhang
 * @Date 2022/9/12 - 15:02
 * @Version 1.0
 */
@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.setHashKeySerializer(new StringRedisSerializer());

        redisTemplate.setConnectionFactory(connectionFactory);

        return redisTemplate;
    }

}

3、缓存短信验证码

3.1、实现思路

3.2、代码

3.2.1、发送验证码时将验证码缓存到Redis

    /**
     * 发送手机验证码
     * @param user
     * @return
     */
    @PostMapping("/sendMsg")
    public R<String> sendMsg(@RequestBody User user, HttpSession session) throws ExecutionException, InterruptedException {
        // 获取手机号
        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("短信发送失败");
    }

3.2.1、登录

    /**
     * 移动端用户登录
     * @param map
     * @param session
     * @return
     */
    @PostMapping("/login")
    public R<User> login(@RequestBody Map map, HttpSession session){
        // 获取手机号、验证码
        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);

        // 验证码比对
        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)l;

            return R.success(user);
        }
        return R.error("验证码错误,请重新输入");
    }

4、缓存菜品数据

4.1、实现思路

这里删除的方法也要请缓存

4.2、代码

4.2.1、list 方法

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

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

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

        // 若不存在,查询数据库,将查询到的菜品缓存到redis
        LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
        queryWrapper.eq(Dish::getStatus, 1);
        queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
        List<Dish> list = dishSerivce.list(queryWrapper);

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

            // 获取分类名称
            Long categoryId = item.getCategoryId();
            Category category = categoryService.getById(categoryId);
            if(category != null){
                String categoryName = category.getName();
                dishDto.setCategoryName(categoryName);
            }

            // 获取口味信息
            Long dishId = item.getId();
            LambdaQueryWrapper<DishFlavor> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DishFlavor::getDishId, dishId);
            List<DishFlavor> dishFlavorList = dishFlavorService.list(wrapper);
            dishDto.setFlavors(dishFlavorList);

            return dishDto;
        }).collect(Collectors.toList());
        redisTemplate.opsForValue().set(key, dishDtoList, 60, TimeUnit.MINUTES);

        return R.success(dishDtoList);
    }

4.2.2、update 方法

    /**
     * 修改菜品
     * @return
     */
    @PutMapping
    public R<String> update(@RequestBody DishDto dishDto){
        dishSerivce.updateWithFlavor(dishDto);

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

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

4.2.3、save 方法

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

        // 清理修改的菜品的缓存数据
        String key = "dish_" + dishDto.getCategoryId() + "_1";
        redisTemplate.delete(key);
        
        return R.success("新增菜品成功");
    }

5、Spring Cache

5.1、Spring Cache 介绍

5.2、常用注解

5.3、基本使用

5.3.1、依赖

Spring Cache 的依赖在 spring-boot-starter-web 中

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <scope>compile</scope>
        </dependency>

5.3.2、@CachePut

    /**
     * CachePut:将方法返回值放入缓存
     *      value:缓存的名称,每个缓存下可以有多个key
     *      key:缓存的key
     * @param user
     * @return
     */
    @CachePut(value = "userCache", key = "#user.id")
    @PostMapping
    public User save(User user){
        userService.save(user);
        return user;
    }

5.3.3、@CacheEvict

    /**
     * CacheEvict:清理指定缓存,key有多种写法
     * @param id
     */
    @CacheEvict(value = "userCache", key = "#id")
    //@CacheEvict(value = "userCache", key = "#root.args[0]")
    //@CacheEvict(value = "userCache", key = "#p0")
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id){
        userService.removeById(id);
    }

    @CacheEvict(value = "userCache", key = "#p0.id")
    //@CacheEvict(value = "userCache", key = "#root.args[0].id")
    //@CacheEvict(value = "userCache", key = "#user.id")
    //@CacheEvict(value = "userCache", key = "#result.id")
    @PutMapping
    public User update(User user){
        userService.updateById(user);
        return user;
    }

5.3.4、Cacheable

    /**
     * Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
     *           若数据库没有找到数据,以null为key
     *      condition:缓存条件,满足条件才缓存
     * @param id
     * @return
     */
    @Cacheable(value = "userCache", key = "#id", unless = "#result == null")
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id){
        User user = userService.getById(id);
        return user;
    }

5.4、以 Redis 作为缓存

5.4.1、依赖

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

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

主要使用

5.4.2、application.yml 配置

spring:
  redis:
    host: 192.168.44.128
    port: 6379
    password: root
    database: 0
  cache:
    redis:
      time-to-live: 1800000 # 设置缓存有效时间,以毫秒为单位

6、缓存套餐数据

6.1、实现思路

6.2、代码

6.2.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.2、设置缓存数据过期时间

spring:
  cache:
    redis:
      time-to-live: 1800000 # 设置缓存有效时间,以毫秒为单位

6.2.3、开启缓存,加上 @EnableCaching  注解

@EnableCaching  // 开启Spring Cache缓存

6.2.4、R 类序列化

public class R<T> implements Serializable

6.2.5、list 方法

    /**
     * 根据条件获取套餐数据
     * @param setmeal
     * @return
     */
    @GetMapping("/list")
    @Cacheable(value = "setmealCache", key = "#setmeal.categoryId + '_' + #setmeal.status")
    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.2.6、delete 和 save 方法 

    /**
     * 批量删除套餐
     * allEntries:清理value分类下所有缓存数据
     * @param ids
     * @return
     */
    @DeleteMapping
    @CacheEvict(value = "setmealCache", allEntries = true)
    public R<String> delete(@RequestParam List<Long> ids){
        setmealService.removeWithDish(ids);
        return R.success("套餐数据删除成功");
    }

    /**
     * 新增套餐
     * allEntries:清理value分类下所有缓存数据
     * @param setmealDto
     * @return
     */
    @PostMapping
    @CacheEvict(value = "setmealCache", allEntries = true)
    public R<String> save(@RequestBody SetmealDto setmealDto){
        setmealService.saveWithDish(setmealDto);
        return R.success("新增套餐成功");
    }

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐