《苍穹外卖》Day07部分知识点记录

发布于:2024-04-26 ⋅ 阅读:(27) ⋅ 点赞:(0)

一、菜品缓存

减少查询数据库的次数,优化性能

客户端:

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,规则: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);//查询起售中的菜品

        // 如果不存在,查询数据库,将查询到的数据放入redis中
        list = dishService.listWithFlavor(dish);
        redisTemplate.opsForValue().set(key, list);

        return Result.success(list);
    }

}

管理端:

package com.sky.controller.admin;

import com.sky.dto.DishDTO;
import com.sky.dto.DishPageQueryDTO;
import com.sky.entity.Dish;
import com.sky.result.PageResult;
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.*;

import java.util.List;
import java.util.Set;

/**
 * 菜品管理
 */
@RestController
@RequestMapping("/admin/dish")
@Api(tags = "菜品相关接口")
@Slf4j
public class DishController {
    @Autowired
    private DishService dishService;
    @Autowired
    private RedisTemplate redisTemplate;

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

        // 清理缓存数据
        String key = "dish_" + dishDTO.getCategoryId();
        clearCache(key);

        return Result.success();
    }

    /**
     * 菜品分页查询
     * @param dishPageQueryDTO
     * @return
     */
    @GetMapping("/page")
    @ApiOperation("菜品分页查询")
    public Result<PageResult> page(DishPageQueryDTO dishPageQueryDTO) {
        log.info("菜品分页查询:{}", dishPageQueryDTO);
        PageResult pageResult = dishService.pageQuery(dishPageQueryDTO);
        return Result.success(pageResult);
    }


    /**
     * 菜品批量删除
     * @param ids
     * @return
     */
    @DeleteMapping
    @ApiOperation("菜品批量删除")
    public Result delete(@RequestParam List<Long> ids) {
        log.info("菜品批量删除:{}", ids);
        dishService.deleteBatch(ids);

        // 将所以的菜品缓存数据清除,所有以dish_开头的key
        clearCache("dish_*");

        return Result.success();
    }


    /**
     * 根据id查询菜品
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    @ApiOperation("根据id查询菜品")
    public Result<DishVO> getById(@PathVariable Long id) {
        log.info("根据id查询菜品:{}", id);
        DishVO dishVO = dishService.getByIdWithFlavor(id);
        return Result.success(dishVO);
    }

    /**
     * 修改菜品
     * @param dishDTO
     * @return
     */
    @PutMapping
    @ApiOperation("修改菜品")
    public Result update(@RequestBody DishDTO dishDTO) {
        log.info("修改菜品:{}", dishDTO);
        dishService.updateWithFlavor(dishDTO);

        // 将所以的菜品缓存数据清除,所有以dish_开头的key
        clearCache("dish_*");

        return Result.success();
    }

    /**
     * 菜品起售停售
     * @param status
     * @param id
     * @return
     */
    @PostMapping("/status/{status}")
    @ApiOperation("菜品起售停售")
    public Result<String> startOrStop(@PathVariable Integer status, Long id) {
        dishService.startOrStop(status, id);

        // 将所以的菜品缓存数据清除,所有以dish_开头的key
        clearCache("dish_*");

        return Result.success();
    }

    /**
     * 根据分类id查询菜品
     * @param categoryId
     * @return
     */
    @GetMapping("/list")
    @ApiOperation("根据分类id查询菜品")
    public Result<List<Dish>> list(Long categoryId) {
        List<Dish> list = dishService.list(categoryId);
        return Result.success(list);
    }


    /**
     * 清理缓存数据
     * @param pattern
     */
    private void clearCache(String pattern) {
        Set keys = redisTemplate.keys(pattern);
        redisTemplate.delete(keys);
    }
}

二、Spring Cache

1. 概述

介绍

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

Spring Cache提供了一层抽象,底层可以切换不同的缓存实现,例如:

  • EHCache
  • Caffeine
  • Redis

常用注解

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

2. 入门小案例

具体参见day07/springcache-demo项目

  • 导入Maven坐标
<!--        缓存-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
            <version>2.7.3</version>
        </dependency>

<!--        缓存中间件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
  • 创建数据库
CREATE DATABASE IF NOT EXISTS spring_cache_demo;
USE spring_cache_demo;

DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
  `id` bigint NOT NULL AUTO_INCREMENT,
  `name` varchar(45) DEFAULT NULL,
  `age` int DEFAULT NULL,
  PRIMARY KEY (`id`)
);
  • 修改配置文件里的数据库连接密码和redis连接密码以及使用的缓存数据库

  • 添加注解

①启动类

  • UserController——使用注解
package com.itheima.controller;

import com.itheima.entity.User;
import com.itheima.mapper.UserMapper;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/user")
@Slf4j
@Api(tags = "用户相关接口")
public class UserController {

    @Autowired
    private UserMapper userMapper;

    @PostMapping
    // 将方法的返回值放到缓存中
    // 如果使用Spring Cache缓存数据,key的生成:cacheNames::key
    @CachePut(cacheNames = "userCache", key = "#user.id")  // 从参数获取key
    // @CachePut(cacheNames = "userCache", key = "#result.id")  // 从返回值获取key
    // @CachePut(cacheNames = "userCache", key = "#p0.id")  // 从第一个参数获取
    // @CachePut(cacheNames = "userCache", key = "#a0.id")  // 从第一个参数获取
    // @CachePut(cacheNames = "userCache", key = "#root.args[0].id")  // 从第一个参数获取
    public User save(@RequestBody User user){
        userMapper.insert(user);
        return user;
    }

    @DeleteMapping
    @CacheEvict(cacheNames = "userCache", key = "#id")
    public void deleteById(Long id){
        userMapper.deleteById(id);
    }

	@DeleteMapping("/delAll")
    @CacheEvict(cacheNames = "userCache", allEntries = true)
    public void deleteAll(){
        userMapper.deleteAll();
    }

    @GetMapping
    @Cacheable(cacheNames = "userCache", key = "#id")
    public User getById(Long id){
        User user = userMapper.getById(id);
        return user;
    }

}

3. spEL的简单介绍

SpEL(Spring Expression Language)是Spring框架中的表达式语言,用于在Spring应用程序中进行动态计算和引用。SpEL提供了一种类似于传统编程语言的表达式语法,可以在运行时对对象图进行访问和操作。

SpEL主要用于以下方面:

  • 在Spring配置文件中引用bean的属性值;
  • 在注解中引用bean的属性值;
  • 在Spring的注解驱动开发中进行条件判断和动态配置;
  • 在Spring Security中进行权限控制;
  • 在Spring Data中进行查询定义。

SpEL支持各种表达式操作,包括算术运算、逻辑运算、关系运算、正则表达式匹配、集合操作等。通过SpEL,可以使Spring应用程序更加灵活和动态,减少硬编码的情况,提高代码的的可维护性和可读性。

示例1:

@Value("#systemProperties['java.home']}")
private String javaHome;

在这个示例中,@Value注解中使用SpEL表达式#systemProperties['java.home']}来获取Java的安装路径,并将其赋值给javaHome变量。

示例2:

    @PostMapping
    // 将方法的返回值放到缓存中
    // 如果使用Spring Cache缓存数据,key的生成:cacheNames::key
    // @CachePut(cacheNames = "userCache", key = "#user.id")  // 从参数获取key
    // @CachePut(cacheNames = "userCache", key = "#result.id")  // 从返回值获取key
    // @CachePut(cacheNames = "userCache", key = "#p0.id")  // 从第一个参数获取
    // @CachePut(cacheNames = "userCache", key = "#a0.id")  // 从第一个参数获取
    @CachePut(cacheNames = "userCache", key = "#root.args[0].id")  // 从第一个参数获取
    public User save(@RequestBody User user){
        userMapper.insert(user);
        return user;
    }

三、作业代码——删除购物车中一个商品

1. ShoppingCartController

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

2. ShoppingCartService

    /**
     * 删除购物车中一个商品
     * @param shoppingCartDTO
     */
    void subShoppingCart(ShoppingCartDTO shoppingCartDTO);

3. ShoppingCartServiceImpl

    /**
     * 删除购物车中一个商品
     * @param shoppingCartDTO
     */
    @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.updateNumberById(shoppingCart);
            }
        }

4. ShoppingCartMapper

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

网站公告

今日签到

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