苍穹外卖day07---Redis缓存优化与购物车功能实现

一.缓存菜品

1.问题1

当许多人同时访问我们的小程序,我们的程序可能在一个时间内进行非常多次数据库查询,这样会导致我们程序的数据库查询效率降低,因此我们通过Redis缓存功能进行解决该问题。

2.解决思路

当用户对菜品查询时,我们首先判断菜品是否缓存,如果缓存直接返回菜品即可,否则查询数据库,将查询到的菜品缓存,然后进行返回。

3.代码实现

复制代码
@RestController("userDishController")
@RequestMapping("/user/dish")
@Slf4j
@Api(tags = "C端-菜品浏览接口")
public class DishController {
    @Autowired
    private DishService dishService;
    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 根据分类id查询菜品
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<DishVO>> list(Long categoryId) {
        //根据分类id查询菜品是否缓存
        String key = "dish_" + categoryId;
        List<DishVO> list1 = (List<DishVO>) redisTemplate.opsForValue().get(key);
        if(list1 != null && !list1.isEmpty()){
            return Result.success(list1);
        }
        //如果没有缓存则去数据库中查询并缓存菜品
        Dish dish = new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);
        //查询起售中的菜品
        List<DishVO> list = dishService.listWithFlavor(dish);
        redisTemplate.opsForValue().set(key,list);
        return Result.success(list);
    }

4.问题2

当我们在管理端对菜品进行增删改操作以及起售停售时,我们应该将缓存删除掉,否则我们的增删改起售停售操作会起不到理想效果

5.解决思路

因为多个地方都需要删除缓存,所以我们将其抽象为一种方法,然后调用即可

6代码实现

复制代码
private void cleanCache(String pattern){
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }

因为修改操作设计的情况太过于复杂,可能涉及多个分类,所以我们直接将缓存全部删除即可。

二.缓存套餐

1.Spring Cache

Spring Cache 是 Spring 提供的一个缓存抽象框架,帮你把数据临时存起来,加快访问速度,减少重复查询。即可以实现我们上面的缓存菜品的功能。

常见注解:

2.代码实现思路

1.引入SpringCache以及redis依赖

2.启动类上加入@EnableCaching注解

3.list查询方法上加入@Cacheable注解

4.增删改起售停售等方法上加入@CacheEvict注解

代码非常简单,在此不过多赘述

三.添加购物车

1.需求分析

产品原型

接口设计

数据库设计

2.解决思路

添加购物车即点击加号时将菜品/套餐插入数据库。

应该注意:当购物车有这个商品时,应该是数量+1,我们将+1后的数量更新到数据库中,如果没有这个商品,直接将这个商品插入数据库。所以应该有一查询和插入和更新操作

3.代码实现

这里我们先写出代码的大体架构,即controller,mapper层,以及service层的大致逻辑

然后我们再去补充service层的逻辑实现

controller

复制代码
@PostMapping("/add")
    public Result shoppingCart(@RequestBody ShoppingCartDTO shoppingCartDTO){
        shoppingCartService.shoppingCart(shoppingCartDTO);
        return Result.success();
    }

service

复制代码
@Override
    public void shoppingCart(ShoppingCartDTO shoppingCartDTO) {
        ShoppingCart shoppingCart = new ShoppingCart();
        BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
        shoppingCart.setUserId(BaseContext.getCurrentId());
        //查询,如果没有直接插入,有则数量加1
        List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);
        if (list != null && list.size() > 0){
            //如果包含,则该商品数量加1,请你帮我实现
            ShoppingCart cart = list.get(0);
            cart.setNumber(cart.getNumber() + 1);
            shoppingCartMapper.update(cart);
        }//添加购物车,需要判断菜品是套餐还是菜品,因为接受参数不一样
        else {
            if(shoppingCartDTO.getDishId() != null){
                //本次添加到购物车的是菜品
                Dish dish = dishMapper.getById(shoppingCartDTO.getDishId());
                shoppingCart.setName(dish.getName());
                shoppingCart.setImage(dish.getImage());
                shoppingCart.setAmount(dish.getPrice());
            }
            else {
                //本次添加到购物车的是套餐
                Long setmealId = shoppingCartDTO.getSetmealId();
                Setmeal setmeal = setmealMapper.getById(setmealId);
                shoppingCart.setName(setmeal.getName());
                shoppingCart.setImage(setmeal.getImage());
                shoppingCart.setAmount(setmeal.getPrice());
            }
            shoppingCart.setNumber(1);
            shoppingCart.setCreateTime(LocalDateTime.now());
            shoppingCartMapper.insert(shoppingCart);
        }
    }

mapper

复制代码
@Mapper
public interface ShoppingCartMapper {
    //查询
    List<ShoppingCart> list(ShoppingCart shoppingCart);
    //插入
    @Insert("insert into shopping_cart (name, image, dish_id, setmeal_id, dish_flavor, number, amount, create_time, user_id) VALUES (#{name}, #{image}, #{dishId}, #{setmealId}, #{dishFlavor}, #{number}, #{amount}, #{createTime}, #{userId})")
    void insert(ShoppingCart shoppingCart);

    @Update("update shopping_cart set number = #{number} where id = #{id}")
    void update(ShoppingCart cart);
    @Delete("delete from shopping_cart where user_id = #{currentId}")
    void clean(Long currentId);
    @Delete("delete from shopping_cart where id = #{id}")
    void deleteById(Long id);
}

我们在mapper模块的查询操作中,返回值是List集合,这里返回单个对象即可,我们这是多此一举吗?其实并不是。在实际开发中,这样的做法是我们的代码更具有韧性,可以重复利用。

我们上面实现了购物车的添加功能,但是购物车既然可以添加,那么就可以将某些菜品从购物车中去除,下面实现去除功能

controller

复制代码
/**
     * 删除购物车中一个商品
     * @param shoppingCartDTO
     * @return
     */
    @PostMapping("/sub")
    @ApiOperation("删除购物车中一个商品")
    public Result sub(@RequestBody ShoppingCartDTO shoppingCartDTO){
        log.info("删除购物车中一个商品,商品:{}", shoppingCartDTO);
        shoppingCartService.subShoppingCart(shoppingCartDTO);
        return Result.success();
    }

service

复制代码
 @Override
    public void subShoppingCart(ShoppingCartDTO shoppingCartDTO) {
        ShoppingCart shoppingCart = new ShoppingCart();
        BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
        //设置查询条件,查询当前登录用户的购物车数据
        shoppingCart.setUserId(BaseContext.getCurrentId());

        List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);

        if(list != null && list.size() > 0){
            shoppingCart = list.get(0);

            Integer number = shoppingCart.getNumber();
            if(number == 1){
                //当前商品在购物车中的份数为1,直接删除当前记录
                shoppingCartMapper.deleteById(shoppingCart.getId());
            }else {
                //当前商品在购物车中的份数不为1,修改份数即可
                shoppingCart.setNumber(shoppingCart.getNumber() - 1);
                shoppingCartMapper.update(shoppingCart);
            }
        }
    }

mapper

复制代码
@Mapper
public interface ShoppingCartMapper {
    //查询
    List<ShoppingCart> list(ShoppingCart shoppingCart);
    //插入
    @Insert("insert into shopping_cart (name, image, dish_id, setmeal_id, dish_flavor, number, amount, create_time, user_id) VALUES (#{name}, #{image}, #{dishId}, #{setmealId}, #{dishFlavor}, #{number}, #{amount}, #{createTime}, #{userId})")
    void insert(ShoppingCart shoppingCart);

    @Update("update shopping_cart set number = #{number} where id = #{id}")
    void update(ShoppingCart cart);
    @Delete("delete from shopping_cart where user_id = #{currentId}")
    void clean(Long currentId);
    @Delete("delete from shopping_cart where id = #{id}")
    void deleteById(Long id);
}

四.查看购物车

1.需求分析

产品原型

接口涉及

代码非常简单,普通的查询操作

2.代码实现

controller

复制代码
@GetMapping("/list")
    public Result list(){
        List<ShoppingCart> list = shoppingCartService.list();
        return Result.success(list);
    }

service

复制代码
@Override
    public List<ShoppingCart> list() {
        ShoppingCart shoppingCart = new ShoppingCart();
        shoppingCart.setUserId(BaseContext.getCurrentId());
        return shoppingCartMapper.list(shoppingCart);
    }

五.清空购物车

思路非常简单,简单删除操作

代码实现

controller

复制代码
@DeleteMapping("/clean")
    public Result clean(){
        shoppingCartService.clean();
        return Result.success();
    }

service

复制代码
@Override
    public void clean() {
        shoppingCartMapper.clean(BaseContext.getCurrentId());
    }

mapper

复制代码
@Delete("delete from shopping_cart where id = #{id}")
    void deleteById(Long id);
相关推荐
毕设源码-钟学长2 小时前
【开题答辩全过程】以 国产汽车的在线销售系统为例,包含答辩的问题和答案
java
切糕师学AI2 小时前
MongoDB 是什么?
数据库·mongodb
学历真的很重要2 小时前
【系统架构师】第三章 数据库系统知识 - 数据库基础到关系代数(详细版)
数据库·学习·职场和发展·系统架构·系统架构师
亓才孓2 小时前
【MyBatis Plus】Wrapper接口
java·开发语言·数据库·spring boot·mybatis
nudt_qxx2 小时前
Ubuntu 26.04 LTS“坚毅浣熊”(Resolute Raccoon) 新特性前瞻
linux·数据库·ubuntu
tianzhiyi1989sq2 小时前
C++工具库之PugiXML使用指南
java·数据库·c++
毕设源码-钟学长2 小时前
【开题答辩全过程】以 哈尔滨市小酒窝APP为例,包含答辩的问题和答案
java
人道领域2 小时前
MyBatisPlus高效开发实战指南
java·开发语言·数据库
AALoveTouch3 小时前
逆向利器:Frida Hook
java·python