目录
1、问题说明
2、环境搭建
2.1、导入依赖
2.2、配置文件
2.3、配置类
3、缓存短信验证码
3.1、实现思路
3.2、代码
3.2.1、发送验证码时将验证码缓存到Redis
3.2.1、登录
4、缓存菜品数据
4.1、实现思路
4.2、代码
4.2.1、list 方法
4.2.2、update 方法
4.2.3、save 方法
5、Spring Cache
5.1、Spring Cache 介绍
5.2、常用注解
5.3、基本使用
5.3.1、依赖
5.3.2、@CachePut
5.3.3、@CacheEvict
5.3.4、Cacheable
5.4、以 Redis 作为缓存
5.4.1、依赖
5.4.2、application.yml 配置
6、缓存套餐数据
6.1、实现思路
6.2、代码
6.2.1、导入依赖
6.2.2、设置缓存数据过期时间
6.2.3、开启缓存,加上 @EnableCaching 注解
6.2.4、R 类序列化
6.2.5、list 方法
6.2.6、delete 和 save 方法
方法:通过缓存进行优化
在 pom.xml 中导入依赖
org.springframework.boot
spring-boot-starter-data-redis
在 application.yml 中添加配置
注意,这里由于使用 host、port、password 报错 ERR wrong number of arguments for ‘auth‘ command,所以改为使用 url 进行配置
详情查看:ERR wrong number of arguments for ‘auth‘ command_lisen_123a的博客-CSDN博客
spring:
redis:
# host: 192.168.44.128
# port: 6379
username: root
# password: ***
url: redis://@:
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;
/**
* Redis配置类
* @Author zhang
* @Date 2022/9/12 - 15:02
* @Version 1.0
*/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate
/**
* 发送手机验证码
* @param user
* @return
*/
@PostMapping("/sendMsg")
public R sendMsg(@RequestBody User user, HttpSession session) throws ExecutionException, InterruptedException {
// 获取手机号
String phone = user.getPhone();
if(StringUtils.isNotEmpty(phone)) {
// 生成随机的4为验证码
String code = ValidateCodeUtils.generateValidateCode(4).toString();
log.info("code={}", code);
// 调用阿里云提供的短信服务API完成发送短信
//SMSUtils.sendMessage(phone, code);
// 将验证码存储到Session中
//session.setAttribute(phone, code);
// 将验证码缓存到Redis,有效期为5分钟
redisTemplate.opsForValue().set(phone, code, 5, TimeUnit.MINUTES);
return R.success("手机验证码发送成功");
}
return R.error("短信发送失败");
}
/**
* 移动端用户登录
* @param map
* @param session
* @return
*/
@PostMapping("/login")
public R login(@RequestBody Map map, HttpSession session){
// 获取手机号、验证码
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);
// 验证码比对
if(codeInSession != null && codeInSession.equals(code)){
// 比对成功,登录成功
// 判断当前手机号对应的用户是否为新用户,若是则自动完成注册
LambdaQueryWrapper 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());
// 登录成功,删除Redis中缓存的验证码
redisTemplate.delete(phone)l;
return R.success(user);
}
return R.error("验证码错误,请重新输入");
}
这里删除的方法也要请缓存
@GetMapping("/list")
public R> list(Dish dish){
List dishDtoList = null;
// 动态构造key
String key = "dish_" + dish.getCategoryId() + "_" + dish.getStatus();
// 从redis中获取缓存数据
dishDtoList = (List) redisTemplate.opsForValue().get(key);
if(dishDtoList != null) {
// 若存在,直接返回,无需查询数据库
return R.success(dishDtoList);
}
// 若不存在,查询数据库,将查询到的菜品缓存到redis
LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(dish.getCategoryId() != null, Dish::getCategoryId, dish.getCategoryId());
queryWrapper.eq(Dish::getStatus, 1);
queryWrapper.orderByAsc(Dish::getSort).orderByDesc(Dish::getUpdateTime);
List list = dishSerivce.list(queryWrapper);
dishDtoList = list.stream().map((item) -> {
DishDto dishDto = new DishDto();
BeanUtils.copyProperties(item, dishDto);
// 获取分类名称
Long categoryId = item.getCategoryId();
Category category = categoryService.getById(categoryId);
if(category != null){
String categoryName = category.getName();
dishDto.setCategoryName(categoryName);
}
// 获取口味信息
Long dishId = item.getId();
LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>();
wrapper.eq(DishFlavor::getDishId, dishId);
List dishFlavorList = dishFlavorService.list(wrapper);
dishDto.setFlavors(dishFlavorList);
return dishDto;
}).collect(Collectors.toList());
redisTemplate.opsForValue().set(key, dishDtoList, 60, TimeUnit.MINUTES);
return R.success(dishDtoList);
}
/**
* 修改菜品
* @return
*/
@PutMapping
public R update(@RequestBody DishDto dishDto){
dishSerivce.updateWithFlavor(dishDto);
// 清理所有菜品的缓存数据
Set keys = redisTemplate.keys("dish_*");
redisTemplate.delete(keys);
return R.success("修改菜品成功");
}
/**
* 新增菜品
* @param dishDto
* @return
*/
@PostMapping
public R save(@RequestBody DishDto dishDto){
//log.info(dishDto.toString());
dishSerivce.saveWithFlavor(dishDto);
// 清理修改的菜品的缓存数据
String key = "dish_" + dishDto.getCategoryId() + "_1";
redisTemplate.delete(key);
return R.success("新增菜品成功");
}
Spring Cache 的依赖在 spring-boot-starter-web 中
org.springframework.boot
spring-boot-starter-web
compile
/**
* CachePut:将方法返回值放入缓存
* value:缓存的名称,每个缓存下可以有多个key
* key:缓存的key
* @param user
* @return
*/
@CachePut(value = "userCache", key = "#user.id")
@PostMapping
public User save(User user){
userService.save(user);
return user;
}
/**
* CacheEvict:清理指定缓存,key有多种写法
* @param id
*/
@CacheEvict(value = "userCache", key = "#id")
//@CacheEvict(value = "userCache", key = "#root.args[0]")
//@CacheEvict(value = "userCache", key = "#p0")
@DeleteMapping("/{id}")
public void delete(@PathVariable Long id){
userService.removeById(id);
}
@CacheEvict(value = "userCache", key = "#p0.id")
//@CacheEvict(value = "userCache", key = "#root.args[0].id")
//@CacheEvict(value = "userCache", key = "#user.id")
//@CacheEvict(value = "userCache", key = "#result.id")
@PutMapping
public User update(User user){
userService.updateById(user);
return user;
}
/**
* Cacheable:在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;若没有数据,调用方法并将方法返回值放到缓存中
* 若数据库没有找到数据,以null为key
* condition:缓存条件,满足条件才缓存
* @param id
* @return
*/
@Cacheable(value = "userCache", key = "#id", unless = "#result == null")
@GetMapping("/{id}")
public User getById(@PathVariable Long id){
User user = userService.getById(id);
return user;
}
org.springframework.boot
spring-boot-starter-cache
org.springframework.boot
spring-boot-starter-data-redis
主要使用
spring:
redis:
host: 192.168.44.128
port: 6379
password: root
database: 0
cache:
redis:
time-to-live: 1800000 # 设置缓存有效时间,以毫秒为单位
org.springframework.boot
spring-boot-starter-data-redis
org.springframework.boot
spring-boot-starter-cache
spring:
cache:
redis:
time-to-live: 1800000 # 设置缓存有效时间,以毫秒为单位
@EnableCaching // 开启Spring Cache缓存
public class R implements Serializable
/**
* 根据条件获取套餐数据
* @param setmeal
* @return
*/
@GetMapping("/list")
@Cacheable(value = "setmealCache", key = "#setmeal.categoryId + '_' + #setmeal.status")
public R> list(Setmeal setmeal){
LambdaQueryWrapper 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 list = setmealService.list(queryWrapper);
return R.success(list);
}
/**
* 批量删除套餐
* allEntries:清理value分类下所有缓存数据
* @param ids
* @return
*/
@DeleteMapping
@CacheEvict(value = "setmealCache", allEntries = true)
public R delete(@RequestParam List ids){
setmealService.removeWithDish(ids);
return R.success("套餐数据删除成功");
}
/**
* 新增套餐
* allEntries:清理value分类下所有缓存数据
* @param setmealDto
* @return
*/
@PostMapping
@CacheEvict(value = "setmealCache", allEntries = true)
public R save(@RequestBody SetmealDto setmealDto){
setmealService.saveWithDish(setmealDto);
return R.success("新增套餐成功");
}