一、缓存菜品
通过缓存的方式提高查询性能
1.1问题说明
大量的用户访问导致数据库访问压力增大,造成系统响应慢,用户体验差
1.2 实现思路
优先查询缓存,如果缓存没有再去查询数据库,然后载入缓存
将菜品集合序列化后缓存入redis key为每个分类的id
1.3 代码开发(缓存菜品)
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);
}
//如果不存在,查询数据库,将查询到的数据放入redis中
Dish dish = new Dish();
dish.setCategoryId(categoryId);
dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品
list = dishService.listWithFlavor(dish);
redisTemplate.opsForValue().set(key,list);
return Result.success(list);
}
}
1.4 代码开发(清除缓存)
为什么要清除缓存? 为了保证数据的一致性,数据库修改后,缓存中的数据并没有发生改变,用户再次请求后不会请求到新修改的数据,而是过期的数据所以要清除缓存。
什么时候清除缓存? 后端修改数据后对缓存进行及时的清除
/**
* 统一清除缓存数据
* @param pattern
*/
private void cleanCache(String pattern){
Set keys = redisTemplate.keys(pattern);
redisTemplate.delete(keys);
}
}
/**
* 启用禁用菜品
* @param status
* @param id
* @return
*/
@PostMapping("/status/{status}")
@ApiOperation("启用禁用菜品")
public Result startOrStop(@PathVariable Integer status,Long id){
log.info("启用禁用菜品,{},{}",status,id);
dishService.startOrStop(status,id);
//将所有的菜品缓存数据清理掉,所有以dish_开头的key
// Set keys = redisTemplate.keys("dish_");
// redisTemplate.delete(keys);
cleanCache("dish_*");
return Result.success();
}
二、缓存套餐(基于SpringCache)
2.1 SpringCache
-
被写死了(没有意义) @CachePut(cacheNames ="userCache",key = "abc")//如果使用SpringCache缓存数据,key的生成:userCache::abc //生成的key 与cacheNames,key有关系
-
动态生成key + SpEL表达式 @CachePut(cacheNames ="userCache",key = "#user.id")//如果使用SpringCache缓存数据,key的生成:userCache::#user.id
2.2 入门案例
1.CachePut:将方法返回值放到缓存中
// @CachePut(cacheNames ="userCache",key = "#user.id")//如果使用SpringCache缓存数据,key的生成:userCache::abc
@PostMapping
// @CachePut(cacheNames = "userCache",key ="#result.id")//对象导航
// @CachePut(cacheNames = "userCache",key = "#p0.id")//#p0代表第一个参数
// @CachePut(cacheNames = "userCache",key = "#a0.id")
@CachePut(cacheNames = "userCache",key = "#root.args[0].id")//#root.args[0]代表第一个参数
public User save(@RequestBody User user){
userMapper.insert(user);
return user;
}
2.Cacheable:在方法执行前先查询缓存,如果缓存中有该数据,直接返回缓存中的数据。如果没有在方法执行后再将返回值放入缓存中
@GetMapping
@Cacheable(cacheNames = "userCache",key = "#id")
public User getById(Long id){
User user = userMapper.getById(id);
return user;
}
Cacheable 不能使用#result.id这种方式设置key的值
3.CacheEvict :将一条或者多条数据从缓存中删除
- 删除单条数据
@CacheEvict(cacheNames = "userCache",key ="#id" )
@DeleteMapping
public void deleteById(Long id){
userMapper.deleteById(id);
}
- 删除多条数据(allEntries = true)
@CacheEvict(cacheNames = "userCache",allEntries = true)
@DeleteMapping("/delAll")
public void deleteAll(){
userMapper.deleteAll();
}
2.3实现思路
2.4代码开发
import com.sky.constant.StatusConstant;
import com.sky.entity.Setmeal;
import com.sky.result.Result;
import com.sky.service.SetmealService;
import com.sky.vo.DishItemVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController("userSetmealController")
@RequestMapping("/user/setmeal")
@Api(tags = "C端-套餐浏览接口")
public class SetmealController {
@Autowired
private SetmealService setmealService;
/**
* 条件查询
*
* @param categoryId
* @return
*/
@Cacheable(cacheNames = "setmealCache",key = "#categoryId")//key :setmealCache::100
@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);
}
/**
* 根据套餐id查询包含的菜品列表
*
* @param id
* @return
*/
@GetMapping("/dish/{id}")
@ApiOperation("根据套餐id查询包含的菜品列表")
public Result<List<DishItemVO>> dishList(@PathVariable("id") Long id) {
List<DishItemVO> list = setmealService.getDishItemById(id);
return Result.success(list);
}
}
import com.github.pagehelper.Page;
import com.sky.dto.SetmealDTO;
import com.sky.dto.SetmealPageQueryDTO;
import com.sky.result.PageResult;
import com.sky.result.Result;
import com.sky.service.SetmealService;
import com.sky.vo.SetmealVO;
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.cache.annotation.CacheEvict;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 套餐管理
*/
@RestController
@RequestMapping("/admin/setmeal")
@Api(tags = "套餐管理相关接口")
@Slf4j
public class SetmealController {
@Autowired
private SetmealService setmealService;
@CacheEvict(cacheNames = "setmealCache",key = "setmealDTO.categoryId")
@PostMapping
@ApiOperation("新增套餐接口")
public Result save(@RequestBody SetmealDTO setmealDTO){
log.info("新增套餐:{}",setmealDTO);
setmealService.saveWithDish(setmealDTO);
return Result.success();
}
/**
* 套餐分页查询
* @param setmealPageQueryDTO
* @return
*/
@GetMapping("/page")
@ApiOperation("套餐分页查询")
public Result<PageResult> pageQuery(SetmealPageQueryDTO setmealPageQueryDTO){
log.info("套餐分页查询:{}",setmealPageQueryDTO);
PageResult pageResult = setmealService.pageQuery(setmealPageQueryDTO);
return Result.success(pageResult);
}
/**
* 批量删除套餐
* @param ids
* @return
*/
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
@DeleteMapping
@ApiOperation("批量删除菜品")
public Result delete(@RequestParam List<Long> ids){
log.info("批量删除套餐:{}",ids);
setmealService.deleteBatch(ids);
return Result.success();
}
/**
* 根据id查询套餐,用于修改页面回显数据
*
* @param id
* @return
*/
@GetMapping("/{id}")
@ApiOperation("根据id查询套餐")
public Result<SetmealVO> getById(@PathVariable Long id) {
SetmealVO setmealVO = setmealService.getByIdWithDish(id);
return Result.success(setmealVO);
}
/**
* 修改套餐
*
* @param setmealDTO
* @return
*/
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
@PutMapping
@ApiOperation("修改套餐")
public Result update(@RequestBody SetmealDTO setmealDTO) {
setmealService.update(setmealDTO);
return Result.success();
}
/**
* 套餐起售停售
* @param status
* @param id
* @return
*/
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
@PostMapping("/status/{status}")
@ApiOperation("套餐起售停售")
public Result startOrStop(@PathVariable Integer status, Long id) {
setmealService.startOrStop(status, id);
return Result.success();
}
}
三、添加购物车
3.1需求分析和设计
3.2 代码开发
3.2.1Controller
import com.sky.dto.ShoppingCartDTO;
import com.sky.result.Result;
import com.sky.service.ShoppingCartService;
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.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/user/shoppingCart")
@Api(tags = "C端购物车相关接口")
@Slf4j
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();
}
}
3.2.2 Serveice层
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.ShoppingCartMapper;
import com.sky.service.ShoppingCartService;
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;
@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);
//如果已经存在了,只需要将其数量加1
if (list !=null && list.size()>0){
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());
// shoppingCart.setNumber(1);
// shoppingCart.setCreateTime(LocalDateTime.now());
//
}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());
}
shoppingCart.setNumber(1);
shoppingCart.setCreateTime(LocalDateTime.now());
shoppingCartMapper.insert(shoppingCart);
}
}
}
四、查看购物车
4.1 需求分析和设计
4.2 代码开发
4.2.1Controller层
/**
* 查看购物车
* @return
*/
@GetMapping("/list")
@ApiOperation("查看购物车")
public Result<List<ShoppingCart>> list(){
List<ShoppingCart> list = shoppingCartService.showShoppingCart();
return Result.success(list);
}
4.2.2 Service层
/**
* 查看购物车
* @return
*/
@Override
public List<ShoppingCart> showShoppingCart() {
//获取当前微信用户的id
Long userId = BaseContext.getCurrentId();
ShoppingCart shoppingCart = ShoppingCart.builder()
.userId(userId)
.build();
List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);
return list;
}
五、清空购物车
5.1 需求分析和设计
5.2 代码开发
5.2.1 Controller层
/**
* 清空购物车
* @return
*/
@DeleteMapping("/clean")
public Result clean(){
shoppingCartService.cleanShoppingCart();
return Result.success();
}
5.2.2 Service层
/**
* 清空购物车
*/
@Override
public void cleanShoppingCart() {
Long userId = BaseContext.getCurrentId();
shoppingCartMapper.deleteByUserId(userId);
}
5.2.3 Mapper层
/**
* 根据用户id删除购物车数据
* @param userId
*/
@Delete("delete from shopping_cart where user_id =#{userId}")
void deleteByUserId(Long userId);