苍穹外卖day7总结

文章讲述了在用户端小程序中通过SpringCache和Redis进行菜品数据缓存,以减少数据库访问压力。介绍了缓存菜品、清理缓存策略以及购物车功能的实现,包括添加、删除、查看和清空购物车的操作及其背后的缓存控制技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.缓存菜品

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

/**
     * 根据分类id查询菜品
     *
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<DishVO>> list(Long categoryId) {
        //构造redis缓存key,规则为:dish_分类id
        String key="dish_"+categoryId;
        //查找redis中是否存在缓存
        List<DishVO> list = (List<DishVO>) redisTemplate.opsForValue().get(key);
        //如果存在,直接返回
        if(list !=null && list.size()>0){
            return Result.success(list);
        }
        //如果不存在,查询数据库
        Dish dish = new Dish();
        dish.setCategoryId(categoryId);
        dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品

        list = dishService.listWithFlavor(dish);

        //将查询到的数据载入缓存
        redisTemplate.opsForValue().set(key,list);

        return Result.success(list);
    }

2.清理缓存

清理缓存的逻辑,需要改造的方法(修改管理端接口 DishController 的相关方法):

  • 新增菜品(针对性删redis,String key="dish_"+dishDTO.getCategoryId()
  • 修改菜品(直接全删redis,传入"dish_*")
  • 批量删除菜品(直接全删redis,传入"dish_*")
  • 起售、停售菜品(直接全删redis,传入"dish_*")

抽取清理缓存的方法:

3.Spring Cache

导入maven坐标

常用注解:

注解

说明

@EnableCaching

开启缓存注解功能,通常加在启动类上

@Cacheable

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

@CachePut

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

@CacheEvict

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

@CachePut注解:

//如果使用Spring Cache缓存数据,key的生成:userCache::key

//1.#加形参的属性之类的,或者本身,要与形参对应

//2.或者result,取返回值算key

//3.p0,p1第几个参数

//4.a0,a1第几个参数

//5.root.args[id].id, 第几个参数
@CachePut(cacheNames = "setmealCache",key = "#categoryId"

在用户端接口SetmealController list 方法上加入@Cacheable注解:

这里key不能是result

@CacheEvict(cacheNames="",key="")

删除所有缓存@CacheEvict(cacheNames="",allEntries=true)

4.缓存套餐

具体的实现思路如下:

导入Spring CacheRedis相关maven坐标

在启动类上加入@EnableCaching注解,开启缓存注解功能

在用户端接口SetmealController list 方法上加入@Cacheable注解

管理端接口SetmealControllersavedeleteupdatestartOrStop等方法上加入CacheEvict注解

在用户端接口SetmealController list 方法上加入@Cacheable注解:

管理端接口SetmealControllersavedeleteupdatestartOrStop等方法上加入CacheEvict注解:

5.添加购物车

根据添加购物车接口创建ShoppingCartController

@RestController
@RequestMapping("/user/shoppingCart")
@Slf4j
@Api(tags = "C端购物车相关接口")
public class ShoppingCartController {
    @Autowired
    private ShoppingCartService shoppingCartService;

    /**
     * 添加购物车
     * @param shoppingCartDTO
     * @return
     */
    @PostMapping("/add")
    @ApiOperation("添加购物车")
    public Result add(@RequestBody ShoppingCartDTO shoppingCartDTO){
        log.info("添加购物车,商品信息为:{}",shoppingCartDTO);
        shoppingCartService.addShoppingCart(shoppingCartDTO);
        return Result.success();
    }
}

创建ShoppingCartServiceImpl实现类,并实现add方法:

@Service
@Slf4j
public class ShoppingCartServiceImpl implements ShoppingCartService {
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private SetmealMapper setmealMapper;

    /**
     * 添加购物车
     * @param shoppingCartDTO
     */
    public void addShoppingCart(ShoppingCartDTO shoppingCartDTO) {
        //判断当前加入购物车的商品是否已经存在了
        ShoppingCart shoppingCart=new ShoppingCart();
        BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
        Long userId = BaseContext.getCurrentId();
        shoppingCart.setUserId(userId);

        List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);
        //只有两种结果:1.查到了只有一条数据2.查不到,无数据
        //如果已经存在,只需要数量加1
        if (list !=null && list.size() >0){
            ShoppingCart cart=list.get(0);
            cart.setNumber(cart.getNumber()+1);//update shopping_cart set number=? where id =?
            shoppingCartMapper.updateNumberById(cart);
        }else{
        //如果不存在,需要插入一条购物车数据
            Long dishId = shoppingCart.getDishId();
            //判断本次添加的是菜品还是套餐
            if (dishId != null){
                //本次添加到购物车的是菜品
                Dish dish = dishMapper.getById(dishId);
                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);
        }
    }
}

创建ShoppingCartMapper接口:

@Mapper
public interface ShoppingCartMapper {

    /**
     * 动态条件查询
     * @param shoppingCart
     * @return
     */
    List<ShoppingCart> list(ShoppingCart shoppingCart);

    /**
     * 根据id修改商品数量
     * @param shoppingCart
     */
    @Update("update shopping_cart set number = #{number} where id = #{id}")
    void updateNumberById(ShoppingCart shoppingCart);

    /**
     * 插入购物车shopping_cart数据
     * @param shoppingCart
     */
    @Insert("insert into shopping_cart(name, image, user_id, dish_id, setmeal_id, dish_flavor, amount, create_time) "+
    "values (#{name},#{image},#{userId},#{dishId},#{setmealId},#{dishFlavor},#{amount},#{createTime})")
    void insert(ShoppingCart shoppingCart);
}

创建ShoppingCartMapper.xml

一开始and写成了add,一直报错。。。

<mapper namespace="com.sky.mapper.ShoppingCartMapper">

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

6.查看购物车

ShoppingCartController中创建查看购物车的方法:

 /**
     * 查看购物车
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("查看购物车")
    public Result<List<ShoppingCart>> list(){
        List<ShoppingCart> list= shoppingCartService.showShoppingCart();
        return Result.success(list);
    }

ShoppingCartServiceImpl中实现查看购物车的方法:

    public List<ShoppingCart> showShoppingCart() {
        //获取到当前微信用户id
        Long userId = BaseContext.getCurrentId();
        ShoppingCart shoppingCart = ShoppingCart.builder()
                .userId(userId)
                .build();
        List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);
        return list;
    }

7.清空购物车

ShoppingCartController中创建清空购物车的方法:

    /**
     * 清空购物车
     * @return
     */
    @DeleteMapping("/clean")
    @ApiOperation("清空购物车")
    public Result clean(){
        shoppingCartService.cleanShoppingCart();
        return Result.success();
    }

ShoppingCartServiceImpl中实现清空购物车的方法:

    public void cleanShoppingCart() {
        Long userId = BaseContext.getCurrentId();
        shoppingCartMapper.deleteByUserId(userId);

    }

ShoppingCartMapper接口中创建删除购物车数据的方法:

    /**
     * 根据用户id删除购物车数据
     * @param userId
     */
    @Delete("delete from shopping_cart where user_id=#{userId}")
    void deleteByUserId(Long userId);

8.删除购物车中的一个商品

ShoppingCartController

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

ShoppingCartServiceImpl

注意:

//查询当前购物车数据
ShoppingCart shoppingCart=new ShoppingCart();
BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
Long userId = BaseContext.getCurrentId();
shoppingCart.setId(userId);
//实际获取的只是点击的那个购物车数据
List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);

这段中实际是点减时请求的查询当前这条购物车数据,所以list只有一条数据

 /**
     * 删除购物车中一个商品
     * @param shoppingCartDTO
     */
    public void subShoppingCart(ShoppingCartDTO shoppingCartDTO) {
        //查询当前购物车数据
        ShoppingCart shoppingCart=new ShoppingCart();
        BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
        Long userId = BaseContext.getCurrentId();
        shoppingCart.setId(userId);
        //实际获取的只是点击的那个购物车数据
        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(number-1);
                shoppingCartMapper.updateNumberById(shoppingCart);
            }
        }

    }

ShoppingCartMapper

    /**
     * 根据id删除购物车数据
     * @param id
     */
    @Delete("delete from shopping_cart where id=#{id}")
    void deleteById(Long id);

### 苍穹外卖 Day 功能配置与时间处理 在苍穹外卖项目的学习过程中,关于日期或时间设置的功能配置是一个常见的关注点。以下是对此主题的详细解析: #### 1. **时间戳的应用** 在软件开发中,时间戳通常用于记录事件发生的具体时刻。对于苍穹外卖这样的应用来说,订单创建时间、配送预计完成时间等功能都需要依赖于精确的时间管理[^1]。 ```python import time # 获取当前时间戳 current_timestamp = int(time.time()) print(f"Current Timestamp: {current_timestamp}") ``` 通过上述代码可以获取到当前的时间戳,并将其存储至数据库以便后续使用。这种做法能够有效减少因时区差异带来的误差问题[^2]。 #### 2. **定时任务调度** 为了实现某些特定时间段内的操作自动化执行(比如每日凌晨清理过期数据),可以通过 `APScheduler` 库来设定周期性的后台作业计划表[^3]。 ```python from apscheduler.schedulers.background import BackgroundScheduler def clean_expired_data(): print("Cleaning expired data...") scheduler = BackgroundScheduler() scheduler.add_job(clean_expired_data, 'cron', hour=0, minute=0) # 设置每天零点运行一次 scheduler.start() try: while True: time.sleep(2) except (KeyboardInterrupt, SystemExit): scheduler.shutdown() ``` 此段脚本展示了如何利用 APScheduler 来安排每晚午夜自动清除旧资料的任务实例。 #### 3. **前端显示本地化时间** 当涉及到跨区域用户的交互界面设计时,则需考虑不同地区的用户看到的是他们所在位置对应的标准时间而非统一服务器端时间。因此,在返回给客户端的数据包里附带原始 UTC 时间的同时也要提供转换方法让浏览器自行调整成适合访问者的当地时间格式。 ```javascript function convertToLocalTime(utcDate){ const localDate = new Date(utcDate); return `${localDate.toLocaleDateString()} ${localDate.toLocaleTimeString()}`; } console.log(convertToLocalTime('2024-01-01T00:00:00Z')); ``` 以上 JavaScript 函数接受一个 ISO 字符串形式表示的世界协调世界时作为输入参数并输出经过变换后的当地实际可见版本字符串结果。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值