Day07 缓存商品 购物车

发布于:2025-08-18 ⋅ 阅读:(17) ⋅ 点赞:(0)

缓存菜品

问题说明

用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大。

结果:系统响应慢,用户体验差

实现思路

通过 Redis 来缓存菜品数据,减少数据库查询操作。

缓存逻辑分析:

        每个分类下的菜品保存一份缓存数据

        数据库中菜品数据有变更时清理缓存数据

代码开发

首先是菜品缓存

package com.sky.controller.user;

import com.sky.constant.StatusConstant;
import com.sky.entity.Dish;
import com.sky.result.Result;
import com.sky.service.DishService;
import com.sky.vo.DishVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@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) {

        //构造 redis 中的 key
        String key = "dish_" + categoryId;

        //查询 redis 中是否存在这个 key 的 value
        List<DishVO> list = (List<DishVO>)redisTemplate.opsForValue().get(key);

        if(list != null && list.size() > 0){
            //如果这个 key 在 redis 中存在,就不去查 mysql,直接返回
            return Result.success(list);
        }

        Dish dish = new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品

        //redis 中没有的话,就去 mysql 里面查,查到之后就存入 redis
         list = dishService.listWithFlavor(dish);
        redisTemplate.opsForValue().set(key, list);

        return Result.success(list);
    }

}

为了保证 mysql 和 redis 中的数据库的数据一致,我们需要清理缓存,所以当我们进行修改,删除,起/停售,新增菜品 操作时需要清空缓存,为了代码简洁我们直接写一个方法,直接调用这个方法即可

    /**
     * 清空缓存
     */
    private void DeleteRedis(String pattern){
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }

功能测试

当我们调用该方法时,可以发现 Redis 里面的 key 消失了

缓存套餐

Spring Cache

实现思路

代码开发

    @Cacheable(cacheNames = "setmealCache", key = "#categoryId") // key: setmealCache::categoryId
    @GetMapping("/list")
    @ApiOperation("根据分类id查询套餐")
    public Result<List<Setmeal>> list(Long categoryId) {
        Setmeal setmeal = new Setmeal();
        setmeal.setCategoryId(categoryId);
        setmeal.setStatus(StatusConstant.ENABLE);

        List<Setmeal> list = setmealService.list(setmeal);
        return Result.success(list);
    }
    @PostMapping
    @ApiOperation("新增套餐")
    @CacheEvict(cacheNames = "setmealCache", key = "setmealDTO.categoryId")
    public Result save(@RequestBody SetmealDTO setmealDTO) {
        setmealService.saveWithDish(setmealDTO);
        return Result.success();
    }
    @DeleteMapping
    @ApiOperation("批量删除套餐")
    @CacheEvict(cacheNames = "setmealCache", allEntries = true)
    public Result delete(@RequestParam List<Long> ids){
        setmealService.deleteBatch(ids);
        return Result.success();
    }
    @PutMapping
    @ApiOperation("修改套餐")
    @CacheEvict(cacheNames = "setmealCache", allEntries = true)
    public Result update(@RequestBody SetmealDTO setmealDTO) {
        setmealService.update(setmealDTO);
        return Result.success();
    }
    @PostMapping("/status/{status}")
    @ApiOperation("套餐起售停售")
    @CacheEvict(cacheNames = "setmealCache", allEntries = true)
    public Result startOrStop(@PathVariable Integer status, Long id) {
        setmealService.startOrStop(status, id);
        return Result.success();
    }

功能测试

和之前缓存菜品一样,只需要看一下 Redis 里面是否缓存成功即可

添加购物车

需求分析和设计

代码开发

具体业务逻辑见代码

package com.sky.controller.user;

import com.sky.result.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController("userShopController")
@RequestMapping("/user/shop")
@Slf4j
@Api(tags = "用户端店铺营业状态相关接口")
public class ShopController {

    @Autowired
    RedisTemplate redisTemplate;

    public static final String  KEY = "SHOP_STATUS";

    @GetMapping("/status")
    @ApiOperation("营业状态查询")
    public Result<Integer> result(){
        Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
        log.info("当前店铺的营业状态为:{}", status == 1 ? "营业中": "打样中");
        return Result.success(status);
    }


}
package com.sky.service.impl;

import com.sky.context.BaseContext;
import com.sky.dto.ShoppingCartDTO;
import com.sky.entity.Dish;
import com.sky.entity.Setmeal;
import com.sky.entity.ShoppingCart;
import com.sky.mapper.DishMapper;
import com.sky.mapper.SetmealMapper;
import com.sky.mapper.ShopCartMapper;
import com.sky.service.ShopCardService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Service
public class ShopCardServiceImpl implements ShopCardService {

    @Autowired
    ShopCartMapper shopCartMapper;
    @Autowired
    DishMapper dishMapper;
    @Autowired
    SetmealMapper setmealMapper;

    @Override
    public void add(ShoppingCartDTO shoppingCartDTO) {

        ShoppingCart shoppingCart = new ShoppingCart();
        BeanUtils.copyProperties(shoppingCartDTO, shoppingCart);
        shoppingCart.setUserId(BaseContext.getCurrentId());

        // 首先判断要添加的是菜品还是套餐
        Long dishId = shoppingCartDTO.getDishId();
        Long setmealId = shoppingCartDTO.getSetmealId();

        if(dishId != null){
            // 传入的是菜品,判断购物车里是否有该菜品
            List<ShoppingCart> list = shopCartMapper.list(shoppingCart);
            // 菜品不为空,说明菜品已经存在,我们只需要让它的数量 + 1
            if(list != null && list.size() > 0){
                //注意注意,因为这张表里每个菜品只能存一次,所以我的这个集合要么没有元素,要么只有一个元素
                // 所以第一个元素也就是我们需要修改的那个
                ShoppingCart shoppingCart1 = list.get(0);
                shoppingCart.setNumber(shoppingCart1.getNumber() + 1);
                shoppingCart.setId(shoppingCart1.getId());
            //    log.info("当前菜品的数量为:{}", shoppingCart.getNumber());
            //    log.info("当前菜品的 id 为:{}",shoppingCart.getId());
                shopCartMapper.update(shoppingCart);
                return;
            }else{
                // 菜品为空,我们就需要查找对应的菜品数据,然后赋值给 shoppingCart
                Dish dish = dishMapper.getById(dishId);
                shoppingCart.setNumber(1);
                shoppingCart.setAmount(dish.getPrice());
                shoppingCart.setCreateTime(LocalDateTime.now());
                shoppingCart.setName(dish.getName());
                shoppingCart.setImage(dish.getImage());
                shopCartMapper.insert(shoppingCart);
                return;
            }
        }else{
            // 传入的是套餐,判断购物车中是否有该套餐,逻辑和上面一样
            List<ShoppingCart> list = shopCartMapper.list(shoppingCart);
            if(list != null && list.size() > 0){
                ShoppingCart shoppingCart1 = list.get(0);
                shoppingCart.setNumber(shoppingCart1.getNumber() + 1);
                shoppingCart.setId(shoppingCart1.getId());
                shopCartMapper.update(shoppingCart);
                return;
            }else{
                // 套餐为空
                Setmeal setmeal = setmealMapper.getById(setmealId);
                shoppingCart.setNumber(1);
                shoppingCart.setAmount(setmeal.getPrice());
                shoppingCart.setCreateTime(LocalDateTime.now());
                shoppingCart.setName(setmeal.getName());
                shoppingCart.setImage(setmeal.getImage());
                shopCartMapper.insert(shoppingCart);
                return;
            }
        }
    }
}
package com.sky.mapper;

import com.sky.entity.ShoppingCart;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;

import java.util.List;

@Mapper
public interface ShopCartMapper {
    List<ShoppingCart> list(ShoppingCart shoppingCart);

    @Update("update sky_take_out.shopping_cart set number = #{number} where id = #{id}")
    void update(ShoppingCart shoppingCart);

    @Insert("insert into sky_take_out.shopping_cart(name, image, user_id, dish_id, setmeal_id, dish_flavor, number, amount, create_time)" +
            "values (#{name}, #{image}, #{userId},#{dishId},#{setmealId},#{dishFlavor},#{number},#{amount},#{createTime})")
    void insert(ShoppingCart shoppingCart);
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.ShopCartMapper">

    <select id="list" resultType="com.sky.entity.ShoppingCart">
        select * from sky_take_out.shopping_cart
        <where>
            <if test="userId != null">
                and user_id = #{userId}
            </if>
            <if test="dishId != null">
                and dish_id = #{dishId}
            </if>
            <if test="setmealId != null">
                and setmeal_id = #{setmealId}
            </if>
            <if test="dishFlavor != null">
                and dish_flavor = #{dishFlavor}
            </if>
        </where>
    </select>

</mapper>

功能测试

查看购物车

 需求分析和设计

代码开发

    @GetMapping("/list")
    @ApiOperation("查看购物车信息")
    public Result<List<ShoppingCart>> showShoppingCart(){
        List<ShoppingCart> shoppingCart = shopCardService.list();
        return Result.success(shoppingCart);
    }
    @Override
    public List<ShoppingCart> list() {
        ShoppingCart shoppingCart = ShoppingCart.builder()
                .userId(BaseContext.getCurrentId())
                .build();
        List<ShoppingCart> shoppingCarts = shopCartMapper.list(shoppingCart);
        return shoppingCarts;
    }
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.sky.mapper.ShopCartMapper">

    <select id="list" resultType="com.sky.entity.ShoppingCart">
        select * from sky_take_out.shopping_cart
        <where>
            <if test="userId != null">
                and user_id = #{userId}
            </if>
            <if test="dishId != null">
                and dish_id = #{dishId}
            </if>
            <if test="setmealId != null">
                and setmeal_id = #{setmealId}
            </if>
            <if test="dishFlavor != null">
                and dish_flavor = #{dishFlavor}
            </if>
        </where>
    </select>

</mapper>

功能测试

清空购物车

需求分析和设计

代码开发

    @DeleteMapping("/clean")
    @ApiOperation("清空购物车")
    public Result clearShoppingCart(){
        log.info("清空购物车");
        shopCardService.clean();
        return Result.success();
    }
    @Override
    public void clean() {
        shopCartMapper.clean(BaseContext.getCurrentId());
    }
    @Delete("delete from sky_take_out.shopping_cart where user_id = #{currentId}")
    void clean(Long currentId);

功能测试

直接可以看到数据库中的数据被删除了


网站公告

今日签到

点亮在社区的每一天
去签到