苍穹外卖--开发记录day07

文章

苍穹外卖day07

一:导入商品浏览接口

跟着视频在资料包里导入就行了。和之前一样都是crud

二:缓存菜品

问题说明,我们将数据存放在数据库,当有大量的用户访问数据库时,数据库的性能会下降,压力提高;我们可以使用缓存,减少数据库访问的压力

实现思路,用户查询菜品,我们先看缓存中有没有菜品,如果没有就查询数据库,然后再存入缓存

将菜品保存在缓存中,我们在controller中找到查询所有菜品的方法,然后做判断,先通过key来获取缓存的value,如果缓存中存在这个key就获取,然后直接返回,如果不存在就调用方法查询数据库,获得的菜品再存入缓存:

java 复制代码
@GetMapping("/list")
@ApiOperation("根据分类id查询菜品")
public Result<List<DishVO>> list(Long categoryId) {
    String key ="dish_"+categoryId;
    ValueOperations valueOperations = redisTemplate.opsForValue();
    if (redisTemplate.hasKey(key)){
        List<DishVO> res = (List<DishVO>) valueOperations.get(key);
        return Result.success(res);
    }
    Dish dish = new Dish();
    dish.setCategoryId(categoryId);
    dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品
    List<DishVO> list = dishService.listWithFlavor(dish);
    valueOperations.set(key,list);
    return Result.success(list);
}

我们统一将redis中存储分类菜品数据的key变成"dish_"+categoryId,然后需要注意的是,我们从redis中获取到时候key必须的字符穿类型的,value可以是任意类型的,我们取得时候就按存入时的类型去强制类型转换就行;

然后我们要进行菜品信息修改的话,小程序还是会从缓存中取数据而我们数据库的信息已经修改了,这个时候就要进行清理缓存的操作了,我们要思考一下,进行添加菜品需要清理吗,需要;因为我们菜品分类下多了一个菜品,修改菜品也需要,而且如果是修改分类的话,那么就会影响到两个缓存数据,为了方便呢,我们直接清理全部缓存即可,然后批量删除菜品也是,可能同时影响多个分类,所以我们也要清理全部缓存;

我们再admin下的菜品管理接口下进行清理即可:

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

定义一个方法,代表按照pattern的格式去清理缓存;

修改,删除操作:

java 复制代码
clearCache("dish_*");

清楚所有;

添加其实没必要进行清理,因为我们默认添加的菜品是禁售的;

三:springcache

1:enablecaching:开启缓存注解功能

2:cacheable:放在方法上看缓存中有没有数据,有直接返回,没有将方法的返回值放入缓存

3:cacheput:将方法的返回值放到缓存中;

4:cacheevict:清理缓存

具体使用:

java 复制代码
@Cacheable(cacheNames = "userCache",key = "#id" )

1:cacheable:这里放在方法上:通过userCache和key来拼接redis中的key,然后他会直接取redis中取查有没有存在我们拼接的这个key,如果有就直接返回,不调用方法,如果没有就通过反射来调用方法,然后将方法的返回值直接添加到我们拼接的key中;

java 复制代码
@CachePut(cacheNames = "userCache" ,key = "#user.id")

2:CachePut是直接将方法的返回值插入到redis中,然后前缀都是一样的,后面的key想要不一样就要动态设置,#后可以调用我们的参数,#result可以调用我们方法的返回值,然后#p可以知道是我们第几个参数,而且这个插入是当方法执行完毕后才会插入的;

java 复制代码
@CacheEvict(cacheNames = "userCache",key = "#id")
java 复制代码
@CacheEvict(cacheNames = "userCache",allEntries = true)

3:cacheEvict:这个就是清理缓存数据,我们可以一次清理一个和上面的命名方法一样,也可以使用allEntries将userCache下的全部数据清除;

四:缓存套餐

其实很简单只要再用户端查询套餐的接口上加上cacheable注解,这样,当我们的redis中没有时我们会执行方法,然后将返回值插入到redis,插入的时result对象,当然我们取出的也是result,前端需要的也是result,当我们redis中有key时就直接返回

java 复制代码
@Cacheable(cacheNames = "setmeal",key = "#categoryId")

清理缓存:当套餐增加了,对应的分类就要清除缓存,不然查询不到我们增加的套餐,当套餐修改了,如果修改的是套餐种类,那么可能会影响两个套餐种类,所有要清楚所有缓存,如果套餐批量删除,也可能会影响多个分类,所以,也要清楚全部缓存

java 复制代码
@CacheEvict(cacheNames = "setmeal",key = "#setmealDTO.categoryId")
java 复制代码
@CacheEvict(cacheNames = "setmeal",allEntries = true)

五:添加购物车

添加到购物车的service要麻烦一些:

controller:

java 复制代码
@PostMapping("/add")
public Result addCart(@RequestBody ShoppingCartDTO shoppingCartDTO){
    log.info("添加购物车{}",shoppingCartDTO);
    shopCartService.addCart(shoppingCartDTO);
    return Result.success();
}

我们接收的是一个dto对象,dto中有套餐id和菜品id,但是只会有一个,要么是套餐,要么是菜品;

service:

java 复制代码
@Override
public void addCart(ShoppingCartDTO shoppingCartDTO) {
    ShoppingCart shoppingCart = new ShoppingCart();
    BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
    shoppingCart.setUserId(BaseContext.getCurrentId());
    List<ShoppingCart> shoppingCarts= shopCartMapper.list(shoppingCart);
    //判断购物车是否已经存在菜品或者套餐
    if (shoppingCarts.size()>0&&shoppingCarts!=null){
        shopCartMapper.update(shoppingCart);
        return;
    }
    //将购物车中的信息插入到表中
    if (shoppingCartDTO.getDishId()!=null){//如果是菜品
        DishVO dishVO = dishMapper.selectById(shoppingCartDTO.getDishId());
        shoppingCart.setImage(dishVO.getImage());
        shoppingCart.setAmount(dishVO.getPrice());
        shoppingCart.setName(dishVO.getName());
        shoppingCart.setDishId(shoppingCartDTO.getDishId());
    }else if (shoppingCartDTO.getSetmealId()!=null) {//如果是套餐
        Setmeal setmeal = setmealMapper.selectById(shoppingCartDTO.getSetmealId());
        shoppingCart.setImage(setmeal.getImage());
        shoppingCart.setAmount(setmeal.getPrice());
        shoppingCart.setName(setmeal.getName());
        shoppingCart.setSetmealId(shoppingCartDTO.getSetmealId());
    }
    shoppingCart.setCreateTime(LocalDateTime.now());
    shopCartMapper.addCart(shoppingCart);
}

这边的业务逻辑比较复杂,我们要先看购物车里有没有当前传入的商品,如果有我们就只需要number+1就行了,然后我们先进行查询,看有没有我们当前传入的商品,我们根据dto中的菜品id或者套餐id,前边说过只会有一个所以sql这么写:

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

这里面的useid是我们通过treadlocal获取的;返回的虽然是一个集合,但是里面要么只有一个元素,要么就是没有元素,因为一个用户的一个菜品只会有一条数据,然后我们判断是否为空,如果不为空说明购物车中有该物品,我们只需要将number加一就行了,所以这边是update语句:

java 复制代码
<update id="update">
    update sky_take_out.shopping_cart set
    number= number+1
    where
    <if test="dishId!=null">
        dish_id=#{dishId}
    </if>
    <if test="setmealId!=null">
        setmeal_id=#{setmealId}
    </if>
    and user_id=#{userId}
</update>

可以看到我们通过用户id和商品id唯一的确定了一条数据,然后直接返回就行;

那么如果为空我们就要插入,这里可能是菜品,也可能是套餐,为方便后面调用相关的方法,我们分两种情况进行赋值,要赋值的有:商品名称,商品价格,商品的图片,商品的创建时间;

最后执行插入操作语句:

java 复制代码
@Insert("insert into sky_take_out.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 addCart(ShoppingCart shoppingCart);

就完成了!

mapper:见上;

六:查看购物车

controller:

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

service:

java 复制代码
public List<ShoppingCart> select() {
    ShoppingCart shoppingCart = new ShoppingCart();
    shoppingCart.setUserId(BaseContext.getCurrentId());
    List<ShoppingCart> list = shopCartMapper.list(shoppingCart);
    return list;
}

直接调用我们之前已经定义的list方法就行;

mapper:

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

七:清空购物车

controller:

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

service:

java 复制代码
@Override
public void clean() {

    shopCartMapper.clean(BaseContext.getCurrentId());

}

mapper:

java 复制代码
@Delete("delete from sky_take_out.shopping_cart where user_id=#{currentId}")
    void clean(Long currentId);

八:删除一个商品

这里其实是商品的数量-1,并且还有一个逻辑就是,当商品的数量为0时就删除这个商品

controller:

复制代码
@PostMapping ("/sub")
public Result deleteOne(@RequestBody ShoppingCartDTO shoppingCartDTO){
    shopCartService.updateOne(shoppingCartDTO);
    return Result.success();
}

service:

java 复制代码
@Override
public void updateOne(ShoppingCartDTO shoppingCartDTO) {
    ShoppingCart shoppingCart = new ShoppingCart();
    BeanUtils.copyProperties(shoppingCartDTO,shoppingCart);
    shoppingCart.setUserId(BaseContext.getCurrentId());
    shopCartMapper.updateOne(shoppingCart);
    List<ShoppingCart> list = shopCartMapper.list(shoppingCart);
    ShoppingCart shoppingCart1 = list.get(0);
    if (shoppingCart1.getNumber()==0){
        shopCartMapper.deleteById(shoppingCart1.getId());
    }
}

这里做了判断,更改完数量后,如果数量为0就直接删除;

mapper:

java 复制代码
<update id="updateOne">
    update sky_take_out.shopping_cart
    set number=number - 1
    <where>
        <if test="dishId!=null">
            dish_id=#{dishId}
        </if>
        <if test="setmealId!=null">
            setmeal_id=#{setmealId}
        </if>
        <if test="dishFlavor!=null">
            and dish_flavor=#{dishFlavor}
        </if>
        and user_id=#{userId}
    </where>
</update>

更改数量

java 复制代码
@Delete("delete from sky_take_out.shopping_cart where id=#{id}")
void deleteById(Long id);

删除数量为0的商品;

总结

今天学习了springcache进行注解缓存开发,然后利用redis缓存菜品和套餐,添加购物车,查看购物车等功能;

相关推荐
科技小花2 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸3 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain3 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希3 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神3 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员3 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java4 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿4 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴4 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存
YOU OU4 小时前
三大范式和E-R图
数据库