緩存菜品
問題說明
用戶端小程序展示的菜品數據都是通過查詢數據庫獲得,如果用戶端訪問量比較大,數據庫訪問壓力隨之增大。
結果:系統響應慢,用戶體驗差
實現思路
通過 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 {@Autowiredprivate DishService dishService;@Autowiredprivate RedisTemplate redisTemplate;/*** 根據分類id查詢菜品** @param categoryId* @return*/@GetMapping("/list")@ApiOperation("根據分類id查詢菜品")public Result<List<DishVO>> list(Long categoryId) {//構造 redis 中的 keyString key = "dish_" + categoryId;//查詢 redis 中是否存在這個 key 的 valueList<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 里面查,查到之后就存入 redislist = 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 {@AutowiredRedisTemplate 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 {@AutowiredShopCartMapper shopCartMapper;@AutowiredDishMapper dishMapper;@AutowiredSetmealMapper setmealMapper;@Overridepublic 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);// 菜品不為空,說明菜品已經存在,我們只需要讓它的數量 + 1if(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{// 菜品為空,我們就需要查找對應的菜品數據,然后賦值給 shoppingCartDish 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);}
@Overridepublic 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();}
@Overridepublic void clean() {shopCartMapper.clean(BaseContext.getCurrentId());}
@Delete("delete from sky_take_out.shopping_cart where user_id = #{currentId}")void clean(Long currentId);
功能測試
直接可以看到數據庫中的數據被刪除了