首页 > 其他分享 >苍穹外卖学习笔记——第七天

苍穹外卖学习笔记——第七天

时间:2024-07-18 23:09:40浏览次数:7  
标签:list 接口 购物车 shoppingCart 外卖 dish 苍穹 id 第七天

缓存商品、购物车

缓存菜品

问题说明

  • 用户端小程序展示的菜品数据都是通过查询数据库获得,如果用户端访问量比较大,数据库访问压力随之增大,从而导致系统响应慢、用户体验差。

实现思路

  • 通过Redis来缓存菜品数据,减少数据库查询操作,具体流程如下:
  • 缓存逻辑分析:
    • 每个分类下的菜品保存一份缓存数据,其中缓存数据的key为“dish_分类id”,value为对应菜品数组序列化后的string。
    • 数据库中菜品数据有变更时清理缓存数据。

代码开发

  • 修改用户端接口 DishController 的 list 方法,加入缓存处理逻辑:
@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.isEmpty()) {
        //如果存在,直接返回,无需查询数据库
        return Result.success(list);
    }

    //如果不存在,查询数据库
    Dish dish = new Dish();
    dish.setCategoryId(categoryId);
    dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品

    list = dishService.listWithFlavor(dish);

    //将查询结果的数据放入redis中
    redisTemplate.opsForValue().set(key, list);

    return Result.success(list);
}
  • 修改管理端接口 DishController 的相关方法,加入清理缓存的逻辑,需要改造以下方法:新增菜品、修改菜品、批量删除菜品和起售、停售菜品。

    • 抽取清理缓存的方法:

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


* 调用清理缓存的方法,保证数据一致性:

```java
@PostMapping
@ApiOperation("新增菜品")
public Result save(@RequestBody DishDTO dishDTO) {
    log.info("新增菜品:{}", dishDTO);
    dishService.saveWithFlavor(dishDTO);

    //清理缓存数据
    String key = "dish_" + dishDTO.getCategoryId();
    cleanCache(key);
    return Result.success();
}

//其他方法内添加以下代码
//将所有的菜品缓存数据清理掉,即所有以dish_开头的key
cleanCache("dish_*");

功能测试

  • 可以通过如下方式进行测试:查看控制台sql、前后端联调、查看Redis中的缓存数据。

缓存套餐

Spring Cache

  • Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。

  • Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如:EHCache、Caffeine和Redis。

  • maven坐标为

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

常用注解

常用注解 说明
@EnableCaching 开启缓存注解功能,通常加在启动类上
@Cacheable 在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据;如果没有缓存数据,调用方法并将方法返回值放到缓存中
@CachePut 将方法的返回值放到缓存中
@CacheEvict 将一条或多条数据从缓存中删除

用法:

  • CachePut(cacheNames = "cachename", key = "#variable.property"),使用Spring Cache缓存数据时,key的生成规则为:cachename::{variable.property的值},其中key按照spEL(spring Expression Language)的规则来写,其中一种写法是目标变量.目标属性,这个"."叫做对象导航。
  • CacheEvict(cacheNames = "cachename", allEntries = true),使用allEntries = true即可删除cachename下的所有键值对。

实现思路

  • 导入Spring Cache和Redis相关maven坐标。
  • 在启动类上加入@EnableCaching注解,开启缓存注解功能。
  • 在用户端接口SetmealController的 list 方法上加入@Cacheable注解。
  • 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解。

代码开发

  • 在用户端接口SetmealController的 list 方法上加入@Cacheable注解:
@GetMapping("/list")
@ApiOperation("根据分类id查询套餐")
@Cacheable(cacheNames = "setmealCache", key = "#categoryId")
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);
}
  • 在管理端接口SetmealController的 save、delete、update、startOrStop等方法上加入CacheEvict注解:
@CacheEvict(cacheNames = "setmealCache", key = "#setmealDTO.categoryId") //save上

@CacheEvict(cacheNames = "setmealCache", allEntries = true) //其他方法上

功能测试

  • 通过前后端联调方式来进行测试,同时观察redis中缓存的套餐数据。

添加购物车

需求分析和设计

产品原型

接口设计

数据库设计

shopping_cart购物车表
字段名 数据类型 说明 备注
id bigint 主键 自增
name varchar(32) 商品名称 冗余字段
image varchar(255) 商品图片路径 冗余字段
user_id bigint 用户id 逻辑外键
dish_id bigint 菜品id 逻辑外键
setmeal_id bigint 套餐id 逻辑外键
dish_flavor varchar(50) 菜品口味
number int 商品数量
amount decimal(10,2) 商品单价 冗余字段
create_time datetime 创建时间

代码开发

  • 根据添加购物车接口的参数设计DTO:
@Data
public class ShoppingCartDTO implements Serializable {

    private Long dishId;
    private Long setmealId;
    private String dishFlavor;

}
  • 根据添加购物车接口创建ShoppingCartController:
@RestController("userShopController")
@RequestMapping("/user/shop")
@Api(tags = "C端-店铺相关接口")
@Slf4j
public class ShopController {

    public static final String KEY = "SHOP_STATUS";

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询店铺营业状态
     *
     * @return
     */
    @GetMapping("/status")
    @ApiOperation("查询店铺营业状态")
    public Result<Integer> getStatus() {
        Integer status = (Integer) redisTemplate.opsForValue().get(KEY);
        log.info("查询店铺营业状态为:{}", status == 1 ? "营业中" : "打烊中");
        return Result.success(status);
    }
}
  • 创建ShoppingCartService接口:
public interface ShoppingCartService {

    /**
     * 添加购物车
     *
     * @param shoppingCartDTO
     */
    void addShoppingCart(ShoppingCartDTO shoppingCartDTO);
}
  • 创建ShoppingCartServiceImpl实现类,并实现add方法:
@Service
@Slf4j
public class ShoppingCartServiceImpl implements ShoppingCartService {

    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private DishMapper dishMapper;
    @Autowired
    private SetmealMapper setmealMapper;

    /**
     * 添加购物车
     *
     * @param shoppingCartDTO
     */
    @Override
    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);

        //如果已经存在了,只需要将数量加一
        if (list != null && !list.isEmpty()) {
            ShoppingCart cart = list.get(0);
            cart.setNumber(cart.getNumber() + 1);
            shoppingCartMapper.updateNumberById(cart);
        } else {
            //如果不存在,需要插入一条购物车数据

            //判断本次添加到购物车的是菜品还是套餐
            Long dishId = shoppingCartDTO.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);

    /**
     * 插入购物车数据
     *
     * @param shoppingCart
     */
    @Insert("insert into 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);
}
  • 创建ShoppingCartMapper.xml:
<?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.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>

功能测试

  • 可以通过如下方式进行测试:查看控制台sql、Swagger接口文档测试、前后端联调。

查看购物车

需求分析和设计

产品原型

接口设计

代码开发

  • 在ShoppingCartController中创建查看购物车的方法:
@GetMapping("/list")
@ApiOperation("查看购物车")
public Result<List<ShoppingCart>> list() {
    List<ShoppingCart> list = shoppingCartService.showShoppingCart();
    return Result.success(list);
}
  • 在ShoppingCartService接口中声明查看购物车的方法:
List<ShoppingCart> showShoppingCart();
  • 在ShoppingCartServiceImpl中实现查看购物车的方法:
@Override
public List<ShoppingCart> showShoppingCart() {
    ShoppingCart shoppingCart = new ShoppingCart().builder()
            .userId(BaseContext.getCurrentId())
            .build();
    List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);
    return list;
}

功能测试

可以通过接口文档进行测试,最后完成前后端联调测试即可。

清空购物车

需求分析和设计

产品原型

接口设计

代码开发

  • 在ShoppingCartController中创建清空购物车的方法:
@DeleteMapping("/clean")
@ApiOperation("清空购物车")
public Result clean() {
    shoppingCartService.cleanShoppingCart();
    return Result.success();
}
  • 在ShoppingCartService接口中声明清空购物车的方法:
void cleanShoppingCart();
  • 在ShoppingCartServiceImpl中实现清空购物车的方法:
@Override
public void cleanShoppingCart() {
    Long userId = BaseContext.getCurrentId();
    shoppingCartMapper.deleteByUserId(userId);
}
  • 在ShoppingCartMapper接口中创建根据用户id清空购物车的方法:
@Delete("delete from shopping_cart where user_id = #{userId}")
void deleteByUserId(Long userId);

功能测试

通过Swagger接口文档进行测试,通过后再前后端联调测试即可。

删除购物车中一个商品

需求分析和设计

产品原型

接口设计

接口设计

代码开发

  • 在ShoppingCartController中创建删除购物车中一个商品的方法:
@PostMapping("/sub")
@ApiOperation("删除购物车中一个商品")
public Result sub(@RequestBody ShoppingCartDTO shoppingCartDTO) {
    log.info("删除购物车中一个商品:{}", shoppingCartDTO);
    shoppingCartService.subShoppingCart(shoppingCartDTO);
    return Result.success();
}
  • 在ShoppingCartService接口中声明删除购物车中一个商品的方法:
void subShoppingCart(ShoppingCartDTO shoppingCartDTO);
  • 在ShoppingCartServiceImpl中实现删除购物车中一个商品的方法:
@Override
public void subShoppingCart(ShoppingCartDTO shoppingCartDTO) {
    ShoppingCart shoppingCart = new ShoppingCart();
    BeanUtils.copyProperties(shoppingCartDTO, shoppingCart);
    //设置查询条件,查询当前登录用户的这一条购物车数据
    Long userId = BaseContext.getCurrentId();
    shoppingCart.setUserId(userId);

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

    if (list != null && !list.isEmpty()) {
        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删除购物车中一个商品的方法:
@Delete("delete from shopping_cart where id = #{id}")
void deleteById(Long id);

功能测试

通过Swagger接口文档进行测试,通过后再前后端联调测试即可。

标签:list,接口,购物车,shoppingCart,外卖,dish,苍穹,id,第七天
From: https://www.cnblogs.com/zgg1h/p/18310560

相关文章

  • 苍穹外卖学习笔记——第八天
    用户下单、订单支付导入地址簿功能代码需求分析和设计产品原型业务功能查询地址列表新增地址修改地址删除地址设置默认地址查询默认地址接口设计新增地址查询当前登录用户的所有地址信息查询默认地址根据id修改地址根据id删除地址根据id查询......
  • 大数据实训第七天笔记
    打包Mapreduce代码以及自定义类型打包wordCount类使用自定义的类型进行mapreduce计算打包wordCount类使用maven的assembly:assumbly插件会生成如下的target打包文件,选择下方的mapreduce_test-1.0-SNAPSHOT-jar-with-dependencies.jar,这是包含依赖文件的jar包,将其......
  • 第七天学习笔记(经验测试,白盒测试)
    经验测试法错误推测法基于经验的测试技术之错误推测法错误推测法也叫错误猜测法,就是根据经验猜想,已有的缺陷,测试经验和失败数据等可能有什么问题并依此设计测试用例.异常分析法基于经验的测试技术之异常分析法系统异常分析法就是针对系统有可能存在的异常操作、软硬件缺陷......
  • <c++>斗破苍穹游戏(转载·博客园)喜欢的一键三连~
    #include<stdio.h>#include<ctime>#include<time.h>//suiji#include<windows.h>//SLEEP函数structPlayer//玩家结构体,并初始化player{charname[21];intattack;intdefense;inthealth;longintmax_health;intlevel;intexp;intrange_exp;......
  • 用微客云搭建一套外卖霸王餐系统赚CPS佣金
    在当下数字化快速发展的时代,外卖行业作为餐饮业的重要分支,正在经历着前所未有的变革。为了满足市场需求,提高用户体验和增加商户收入,越来越多的外卖平台开始寻求创新,其中,搭建一套高效、稳定且功能丰富的外卖霸王餐系统成为了不少企业的首选。本文将详细介绍如何使用微客云搭建一套......
  • 坐牢第七天 20040710
    1.作业:完成学生管理系统1>使用菜单完成2>有学生的信息录入功能:输入学生个数,并将学生的姓名、分数录入3>查看学生信息:输出所有学生姓名以及对应的分数4>求出学习最好的学生信息:求最大值5>按姓名将所有学生进行升序排序6>按成绩将所有学生进行升序排序要求每个功能......
  • 苍穹外卖 - day1
    1.项目介绍业务功能技术选型环境搭建前端前端部分非重点,直接由平台提供,部署在nginx服务器上。nginx概念反向代理与负载均衡动态监听80端口,将请求转发到目标服务器,若有多个目标服务器,则采取负载均衡策略进行请求的分发(如轮询)后端接口文档1.YApi通过上传jso......
  • 海狐外卖O2O商城系统:技术架构与运营模式的深度解析
    摘要:本文深入探讨了海狐外卖O2O商城系统的技术架构、功能特性以及运营模式。海狐外卖作为一款专注于细分市场领域的外卖餐饮解决方案,不仅拥有先进的技术栈支持,还通过丰富的系统插件和灵活的运营模式,为商户和用户提供高效、便捷的服务。本文将从技术角度对其架构进行详细解析,并......
  • 做外卖霸王餐前景咋样,好不好做
    微客云霸王餐系统当今互联网经济蓬勃发展,外卖行业已成为日常生活不可或缺的一部分,其市场规模和用户基础逐年攀升。随着消费者对便捷性和优惠力度需求的增加,外卖霸王餐作为一种新兴的营销模式,正逐渐成为商家和第三方平台眼中的香饽饽。本文将深入探讨外卖霸王餐的前景,分析其市场潜......
  • 外卖霸王餐怎么做才能盈利赚钱的呢?
    在当前的餐饮市场中,外卖行业已成为不可忽视的一部分,而“外卖霸王餐”作为一种促销策略,更是在外卖市场中引起了广泛的关注。那么,如何通过外卖霸王餐实现盈利赚钱呢?以下将从多个方面进行深入探讨。一、明确外卖霸王餐的定位与目标外卖霸王餐作为一种促销手段,其定位应明确为吸引新客......