目录
一、环境搭建
1.1 maven坐标
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
1.2 配置文件
在项目的application.yml中加入redis相关配置
spring: redis: host: localhost port: 6379 password: database: 0
1.3 配置类
package com.learn.reggie.config; import org.springframework.cache.annotation.CachingConfigurerSupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author 咕咕猫 * @version 1.0 */ @Configuration public class RedisConfig extends CachingConfigurerSupport { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) { RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>(); //默认的Key序列化器为:JdkSerializationRedisSerializer redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setConnectionFactory(connectionFactory); return redisTemplate; } }
二、缓存短信验证码
2.1 实现思路
2.2 代码改造
package com.learn.reggie.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.learn.reggie.common.R; import com.learn.reggie.entity.User; import com.learn.reggie.service.UserService; import com.learn.reggie.utils.ValidateCodeUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; 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; import javax.servlet.http.HttpSession; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @author 咕咕猫 * @version 1.0 */ @RestController @RequestMapping("/user") @Slf4j public class UserController { @Autowired private UserService userService; @Autowired private RedisTemplate redisTemplate; /** * 发送手机短信验证码 * * @param user * @return */ @PostMapping("/sendMsg") public R<String> sendMsg(@RequestBody User user, HttpSession session) { //获取手机号 String phone = user.getPhone(); if (StringUtils.isNotEmpty(phone)) { //生成随机的4位验证码 String code = ValidateCodeUtils.generateValidateCode(6).toString(); log.info("code={}", code); //调用阿里云提供的短信服务API完成发送短信 // SMSUtils.sendMessage("瑞吉外卖","",phone,code); //需要将生成的验证码保存到Session // session.setAttribute(phone, code); //将生成的验证码缓存到Redis中,并且设置有效期为五分钟 redisTemplate.opsForValue().set(phone,code,5, TimeUnit.MINUTES); return R.success("手机验证码短信发送成功"); } return R.error("短信发送失败"); } /** * 移动端用户登录 * @param map * @param session * @return */ @PostMapping("/login") public R<User> login(@RequestBody Map map, HttpSession session) { log.info(map.toString()); //获取手机号 String phone = map.get("phone").toString(); //获取验证码 String code = map.get("code").toString(); //从Session中获取保存的验证码 // Object codeInSession = session.getAttribute(phone); //从Redis获取缓存的验证码 Object codeInSession = redisTemplate.opsForValue().get(phone); //进行验证码的比对(页面提交的验证码和Session中保存的验证码比对) if (codeInSession != null && codeInSession.equals(code)){ //如果能够比对成功,说明登陆成功 LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(User::getPhone,phone); //根据用户的手机号去用户表获取用户 User user = userService.getOne(queryWrapper); if (user == null) { //判断当前手机号对应的用户是否为新用户,如果是新用户就自动完成注册 user = new User(); user.setPhone(phone); user.setStatus(1);//可设置也可不设置,因为数据库我们设置了默认值 //注册新用户 userService.save(user); } session.setAttribute("user",user.getId());//在session中保存用户的登录状态,这样过滤器就不会被拦截了 //如果用户登录成功,删除Redis缓存的验证码 redisTemplate.delete(phone); return R.success(user); } return R.error("登录失败"); } }
三、缓存菜品数据
3.1 实现思路
3.2 代码改造
package com.learn.reggie.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.learn.reggie.common.R; import com.learn.reggie.dto.DishDto; import com.learn.reggie.entity.Category; import com.learn.reggie.entity.Dish; import com.learn.reggie.entity.DishFlavor; import com.learn.reggie.service.CategoryService; import com.learn.reggie.service.DishFlavorService; import com.learn.reggie.service.DishService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; 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; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; /** * 菜品管理 */ @RestController @RequestMapping("/dish") @Slf4j public class DishController { @Autowired private DishService dishService; @Autowired private DishFlavorService dishFlavorService; @Autowired private CategoryService categoryService; @Autowired private RedisTemplate redisTemplate; /** * 新增菜品 * * @param dishDto * @return */ @PostMapping public R<String> save(@RequestBody DishDto dishDto) { //前端提交的是json数据的话,我们在后端就要使用这个注解来接收参数,否则接收到的数据全是null log.info(dishDto.toString()); dishService.saveWithFlavor(dishDto); return R.success("新增菜品成功"); } /** * 菜品信息分页查询 * * @param page * @param pageSize * @param name * @return */ @GetMapping("/page") public R<Page> page(int page, int pageSize, String name) { //构造分页构造器对象 Page<Dish> pageInfo = new Page<>(page, pageSize); Page<DishDto> dishDtoPage = new Page<>(); //条件构造器 LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>(); //添加过滤条件 queryWrapper.like(name != null, Dish::getName, name); //添加排序条件 queryWrapper.orderByDesc(Dish::getUpdateTime); //执行分页查询 dishService.page(pageInfo, queryWrapper); //对象拷贝 BeanUtils.copyProperties(pageInfo, dishDtoPage, "records"); List<Dish> records = pageInfo.getRecords(); List<DishDto> list = records.stream().map((item) -> { DishDto dishDto = new DishDto(); BeanUtils.copyProperties(item, dishDto); Long categoryId = item.getCategoryId();//分类id //根据id查询分类对象 Category category = categoryService.getById(categoryId); if (category != null) { String categoryName = category.getName(); dishDto.setCategoryName(categoryName); } return dishDto; }).collect(Collectors.toList()); dishDtoPage.setRecords(list); return R.success(dishDtoPage); } /** * 根据id查询菜品信息和对应的口味信息 * * @param id * @return */ @GetMapping("/{id}") public R<DishDto> get(@PathVariable Long id) { DishDto dishDto = dishService.getByIdWithFlavor(id); return R.success(dishDto); } /** * 修改菜品 * * @param dishDto * @return */ @PutMapping public R<String> update(@RequestBody DishDto dishDto) { //前端提交的是json数据的话,我们在后端就要使用这个注解来接收参数,否则接收到的数据全是null log.info(dishDto.toString()); dishService.updateWithFlavor(dishDto); //清理所有菜品的缓存数据 //Set keys = redisTemplate.keys("dish_*"); //redisTemplate.delete(keys); //清理某个分类下面的缓存 String key = "dish_" + dishDto.getCategoryId() + "_1"; redisTemplate.delete(key); return R.success("新增菜品成功"); } /** * 根据条件查询对应的菜品数据 * * @param dish * @return */ /* @GetMapping("/list") public R<List<Dish>> list(Dish dish) { //这里可以传categoryId,但是为了代码通用性更强,这里直接使用dish类来接受(因为dish里面是有categoryId的),以后传dish的其他属性这里也可以使用 //构造查询条件对象 LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId()); //添加条件,查询状态为1(起售状态)的菜品 queryWrapper.eq(Dish::getStatus,1); //添加排序条件 queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime); List<Dish> list = dishService.list(queryWrapper); return R.success(list); }*/ @GetMapping("/list") public R<List<DishDto>> list(Dish dish){ List<DishDto> dishDtoList = null; //动态构造key String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus(); //dish_1577993434548723713_1 //先从Redis中获取缓存数据, dishDtoList = (List<DishDto>) redisTemplate.opsForValue().get(key); if(dishDtoList != null){ //如果存在直接返回,无需查询数据库 return R.success(dishDtoList); } //这里可以传categoryId,但是为了代码通用性更强,这里直接使用dish类来接受(因为dish里面是有categoryId的),以后传dish的其他属性这里也可以使用 //构造查询条件 LambdaQueryWrapper<Dish> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(dish.getCategoryId() != null ,Dish::getCategoryId,dish.getCategoryId()); //添加条件,查询状态为1(起售状态)的菜品 queryWrapper.eq(Dish::getStatus,1); //添加排序条件 queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime); List<Dish> list = dishService.list(queryWrapper); dishDtoList = list.stream().map((item) -> { DishDto dishDto = new DishDto(); BeanUtils.copyProperties(item,dishDto); Long categoryId = item.getCategoryId();//分类id //根据id查询分类对象 Category category = categoryService.getById(categoryId); if(category != null){ String categoryName = category.getName(); dishDto.setCategoryName(categoryName); } //当前菜品的id Long dishId = item.getId(); LambdaQueryWrapper<DishFlavor> lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(DishFlavor::getDishId,dishId); //SQL:select * from dish_flavor where dish_id = ? List<DishFlavor> dishFlavorList = dishFlavorService.list(lambdaQueryWrapper); dishDto.setFlavors(dishFlavorList); return dishDto; }).collect(Collectors.toList()); //如果不存在,需要查询数据库,然后将查询到的菜品数据缓存到Redis redisTemplate.opsForValue().set(key,dishDtoList,60, TimeUnit.MINUTES); return R.success(dishDtoList); } }
四、缓存套餐数据
4.1 实现思路
4.2 代码实现
导入maven坐标
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency>
在application.yml中配置缓存数据的过期时间
spring: cache: redis: time-to-live: 1800000 #设置缓存数据过期时间
在启动类上加入@EnableCaching注解,开启缓存注解功能
@Slf4j @SpringBootApplication @ServletComponentScan @EnableTransactionManagement @EnableCaching //开启Spring Cache注解缓存功能 public class ReggieApplication { public static void main(String[] args) { SpringApplication.run(ReggieApplication.class,args); log.info("项目启动成功"); } }
在SetmealController的list方法加入@Cacheable注解
在SetmealController的save和delete方法上加入CacheEvict注解
package com.learn.reggie.controller; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.learn.reggie.common.R; import com.learn.reggie.dto.SetmealDto; import com.learn.reggie.entity.Category; import com.learn.reggie.entity.Dish; import com.learn.reggie.entity.Setmeal; import com.learn.reggie.entity.SetmealDish; import com.learn.reggie.service.CategoryService; import com.learn.reggie.service.SetmealDishService; import com.learn.reggie.service.SetmealService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.Set; import java.util.stream.Collectors; /** * 套餐管理 */ @RestController @RequestMapping("/setmeal") @Slf4j public class SetmealController { @Autowired private SetmealService setmealService; @Autowired private CategoryService categoryService; @Autowired private SetmealDishService setmealDishService; /** * 新增套餐 * @param setmealDto * @return */ @PostMapping @CacheEvict(value = "setmealCache",allEntries = true) public R<String> save(@RequestBody SetmealDto setmealDto) { log.info("套餐信息:{}", setmealDto); setmealService.saveWithDish(setmealDto); return R.success("新增套餐成功"); } /** * 套餐分页查询 * @param page * @param pageSize * @param name * @return */ @GetMapping("/page") public R<Page> page(int page, int pageSize, String name) { //分页构造器对象 Page<Setmeal> pageInfo = new Page(page,pageSize); Page<SetmealDto> dtoPage = new Page<>(); LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); //添加查询条件,根据name进行like模糊查询 queryWrapper.like(name != null, Setmeal::getName,name); //添加排序条件,根据更新时间降序排列 queryWrapper.orderByDesc(Setmeal::getUpdateTime); setmealService.page(pageInfo,queryWrapper); //对象拷贝 BeanUtils.copyProperties(pageInfo, dtoPage,"records"); List<Setmeal> records = pageInfo.getRecords(); List<SetmealDto> list = records.stream().map((item) -> { SetmealDto setmealDto = new SetmealDto(); //对象拷贝 BeanUtils.copyProperties(item,setmealDto); //分类id Long categoryId = item.getCategoryId(); //根据分类id来查询分类对象 Category category = categoryService.getById(categoryId); if (category != null) { //分类名称 String categoryName = category.getName(); setmealDto.setCategoryName(categoryName); } return setmealDto; }).collect(Collectors.toList()); dtoPage.setRecords(list); return R.success(dtoPage); } /** * 删除套餐 * @param ids * @return */ @DeleteMapping @CacheEvict(value = "setmealCache",allEntries = true) public R<String> delete(@RequestParam List<Long> ids){ log.info("ids:{}",ids); setmealService.removeWithDish(ids); return R.success("套餐删除成功"); } /** * 根据条件来查询套餐数据 * @param setmeal * @return */ @GetMapping("/list") @Cacheable(value = "setmealCache",key = "#setmeal.categoryId + '_' + #setmeal.status") public R<List<Setmeal>> list(Setmeal setmeal){ LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(setmeal.getCategoryId() != null,Setmeal::getCategoryId,setmeal.getCategoryId()); queryWrapper.eq(setmeal.getStatus() != null,Setmeal::getStatus,setmeal.getStatus()); queryWrapper.orderByDesc(Setmeal::getUpdateTime); List<Setmeal> list = setmealService.list(queryWrapper); return R.success(list); } }