diff --git a/src/main/java/com/ctgu/lost_found/common/exception/GlobalExceptionHandler.java b/src/main/java/com/ctgu/lost_found/common/exception/GlobalExceptionHandler.java
index 6f667a6..caae731 100644
--- a/src/main/java/com/ctgu/lost_found/common/exception/GlobalExceptionHandler.java
+++ b/src/main/java/com/ctgu/lost_found/common/exception/GlobalExceptionHandler.java
@@ -35,7 +35,7 @@ public class GlobalExceptionHandler {
log.info("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
log.error("未登录异常: " + e.getMessage());
log.info("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- return Result.error("未登录, 请登录后访问");
+ return Result.notLogin();
}
/**
@@ -46,7 +46,7 @@ public class GlobalExceptionHandler {
log.info("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
log.error("角色权限异常: " + e.getMessage());
log.info("\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n");
- return Result.error("不具备访问该接口的权限");
+ return Result.noPermissions("不具备访问该接口的权限");
}
/**
diff --git a/src/main/java/com/ctgu/lost_found/common/util/redis/RedisCacheUtil.java b/src/main/java/com/ctgu/lost_found/common/util/redis/RedisCacheUtil.java
new file mode 100644
index 0000000..e161d66
--- /dev/null
+++ b/src/main/java/com/ctgu/lost_found/common/util/redis/RedisCacheUtil.java
@@ -0,0 +1,115 @@
+package com.ctgu.lost_found.common.util.redis;
+
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+
+/**
+ * @author ZMC
+ *
+ * Redis缓存工具类
+ */
+@Slf4j
+@Component
+public class RedisCacheUtil {
+
+ private final StringRedisTemplate stringRedisTemplate;
+
+ public RedisCacheUtil(StringRedisTemplate stringRedisTemplate) {
+ this.stringRedisTemplate = stringRedisTemplate;
+ }
+
+ /**
+ * 向redis缓存进行写请求: 插入任意Java类型的数据,并设置随机TTL
+ * TTL: 缓存有效期,过期后缓存自动删除
+ * 随机设置TTL: 使缓存的TTL尽可能均匀,可以在一定程度上避免缓存雪崩
+ *
+ * @param key 数据的key
+ * @param value 数据
+ * @param time 过期时间
+ * @param unit 时间单位
+ */
+ public void setWithTTL(String key, Object value, Long time, TimeUnit unit) {
+ // 随机获取[1,100] * [0.1, 1.1]的浮点数
+ Random random = new Random();
+ int randomInt = (int) ((random.nextInt(100) + 1) * (random.nextFloat() + 0.1)) + 1;
+ // 手动序列化: JSONUtil.toJsonStr(value)
+ stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(value), randomInt * time, unit);
+ }
+
+ /**
+ * 向redis缓存进行写请求: 插入任意Java类型的数据,并设置逻辑过期时间
+ *
+ * @param key 数据的key
+ * @param value 数据
+ * @param time 过期时间
+ * @param unit 时间单位
+ */
+ public void setWithLogicalExpire(String key, Object value, Long time, TimeUnit unit) {
+ // 设置逻辑过期
+ RedisData redisData = new RedisData();
+ redisData.setData(value);
+ // redis缓存里的TTL数值单位为s,因此逻辑过期时间单位使用s更合适
+ redisData.setExpireTime(LocalDateTime.now().plusSeconds(unit.toSeconds(time)));
+ // 手动序列化: JSONUtil.toJsonStr(value)
+ stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(redisData));
+ }
+
+ /**
+ * 按key删除redis缓存
+ *
+ * @param key 要删除的数据的key
+ */
+ public void deleteByKey(String key) {
+ stringRedisTemplate.delete(key);
+ }
+
+ /**
+ * 向redis缓存进行读请求: 使用 缓存空对象 解决 缓存穿透问题
+ *
+ * @param keyPrefix key的前缀
+ * @param id 数据库表的主键id(或unique字段)
+ * @param type 实体类的Class
+ * @param dbFallback 查询MySQL数据库的方法
+ * @param time 过期时间
+ * @param unit 时间单位
+ */
+ public R queryWithPassThrough(String keyPrefix, ID id, Class type, Function dbFallback, Long time, TimeUnit unit) {
+ String key = keyPrefix + id;
+ // 1.查询redis缓存
+ String json = stringRedisTemplate.opsForValue().get(key);
+ // 判断json是否是空串(因为采用缓存空对象解决缓存穿透的问题)
+ if ("".equals(json)) {
+ // 返回错误信息
+ return null;
+ }
+ // 2.判断缓存是否命中,并且是合理数据
+ if (StrUtil.isNotBlank(json)) {
+ // 3.缓存命中,手动反序列化,返回正确数据
+ return JSONUtil.toBean(json, type);
+ }
+ // 4.缓存未命中(json为null),根据id查询MySQL数据库
+ R r = dbFallback.apply(id);
+ // 5.MySQL数据库中不存在
+ if (r == null) {
+ // 缓存空字符串,设置TTL为3分钟: 解决缓存穿透的问题
+ stringRedisTemplate.opsForValue().set(key, "", RedisConstants.CACHE_NULL_TTL, TimeUnit.MINUTES);
+ // 返回错误信息
+ return null;
+ }
+ // 6.MySQL数据库存在,写入redis缓存
+ this.setWithTTL(key, r, time, unit);
+ // 7.返回正确数据
+ return r;
+ }
+
+
+}
diff --git a/src/main/java/com/ctgu/lost_found/common/util/redis/RedisConstants.java b/src/main/java/com/ctgu/lost_found/common/util/redis/RedisConstants.java
new file mode 100644
index 0000000..cbda344
--- /dev/null
+++ b/src/main/java/com/ctgu/lost_found/common/util/redis/RedisConstants.java
@@ -0,0 +1,18 @@
+package com.ctgu.lost_found.common.util.redis;
+
+
+/**
+ * @author ZMC
+ *
+ * Redis缓存常量池
+ */
+public class RedisConstants {
+
+ public static final Long CACHE_NULL_TTL = 3L;
+
+ public static final String CACHE_ITEM_TYPE_KEY = "cache:ItemType:";
+
+ public static final Long CACHE_ITEM_TYPE_TTL = 24L;
+
+
+}
diff --git a/src/main/java/com/ctgu/lost_found/common/util/redis/RedisData.java b/src/main/java/com/ctgu/lost_found/common/util/redis/RedisData.java
new file mode 100644
index 0000000..9d631c2
--- /dev/null
+++ b/src/main/java/com/ctgu/lost_found/common/util/redis/RedisData.java
@@ -0,0 +1,16 @@
+package com.ctgu.lost_found.common.util.redis;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * @author ZMC
+ *
+ * Redis缓存---逻辑过期传输对象
+ */
+@Data
+public class RedisData {
+ private LocalDateTime expireTime;
+ private Object data;
+}
diff --git a/src/main/java/com/ctgu/lost_found/service/Impl/ItemTypeServiceImpl.java b/src/main/java/com/ctgu/lost_found/service/Impl/ItemTypeServiceImpl.java
index 5679e0b..4f78d81 100644
--- a/src/main/java/com/ctgu/lost_found/service/Impl/ItemTypeServiceImpl.java
+++ b/src/main/java/com/ctgu/lost_found/service/Impl/ItemTypeServiceImpl.java
@@ -2,6 +2,8 @@ package com.ctgu.lost_found.service.Impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ctgu.lost_found.common.util.Result;
+import com.ctgu.lost_found.common.util.redis.RedisCacheUtil;
+import com.ctgu.lost_found.common.util.redis.RedisConstants;
import com.ctgu.lost_found.dao.ItemTypeDao;
import com.ctgu.lost_found.entity.ItemType;
import com.ctgu.lost_found.service.ItemTypeService;
@@ -9,6 +11,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/**
* @author ZMC
@@ -19,8 +22,11 @@ public class ItemTypeServiceImpl implements ItemTypeService {
private final ItemTypeDao itemTypeDao;
- public ItemTypeServiceImpl(ItemTypeDao itemTypeDao) {
+ private final RedisCacheUtil redisCacheUtil;
+
+ public ItemTypeServiceImpl(ItemTypeDao itemTypeDao, RedisCacheUtil redisCacheUtil) {
this.itemTypeDao = itemTypeDao;
+ this.redisCacheUtil = redisCacheUtil;
}
/**
@@ -45,9 +51,12 @@ public class ItemTypeServiceImpl implements ItemTypeService {
*/
@Override
public Result deleteItemType(Integer id) {
+ // 1.先更新MySQL
if (itemTypeDao.deleteById(id) == 0) {
return Result.error("删除失败,物品类型id不存在");
}
+ // 2.再更新(删除)Redis缓存
+ redisCacheUtil.deleteByKey(RedisConstants.CACHE_ITEM_TYPE_KEY + id);
return Result.success("删除成功");
}
@@ -59,9 +68,12 @@ public class ItemTypeServiceImpl implements ItemTypeService {
*/
@Override
public Result updateItemType(ItemType itemType) {
+ // 1.先更新MySQL
if (itemTypeDao.updateById(itemType) == 0) {
return Result.error("修改失败,可能是传入数据不符合数据库约束或者物品类型id不存在");
}
+ // 2.再更新(删除)Redis缓存
+ redisCacheUtil.deleteByKey(RedisConstants.CACHE_ITEM_TYPE_KEY + itemType.getId());
return Result.success("修改成功");
}
@@ -73,11 +85,21 @@ public class ItemTypeServiceImpl implements ItemTypeService {
*/
@Override
public Result getItemTypeList(Integer id) {
- List itemTypeList = itemTypeDao.getItemTypeList(id);
- if (itemTypeList.isEmpty()) {
- return Result.error("查询失败,物品类型不存在");
+ if (id == null) {
+ //查询所有物品类型
+ List itemTypeList = itemTypeDao.getItemTypeList(null);
+ if (itemTypeList == null || itemTypeList.isEmpty()) {
+ return Result.error("查询失败,物品类型不存在");
+ }
+ return Result.success("200", itemTypeList);
+ } else {
+ //按id查询单个物品类型
+ ItemType itemType = redisCacheUtil.queryWithPassThrough(RedisConstants.CACHE_ITEM_TYPE_KEY, id, ItemType.class, this::getItemTypeById, RedisConstants.CACHE_ITEM_TYPE_TTL, TimeUnit.HOURS);
+ if (itemType == null) {
+ return Result.error("查询失败,物品类型不存在");
+ }
+ return Result.success("200", itemType);
}
- return Result.success(itemTypeList);
}
/**
@@ -88,17 +110,32 @@ public class ItemTypeServiceImpl implements ItemTypeService {
*/
@Override
public Result fuzzyItemTypeList(String type) {
- if(type == null){
+ if (type == null) {
type = "";
}
QueryWrapper queryWrapper = new QueryWrapper<>();
queryWrapper.like("type", type);
List itemTypeList = itemTypeDao.selectList(queryWrapper);
queryWrapper.clone();
- if (itemTypeList.isEmpty()) {
+ if (itemTypeList == null || itemTypeList.isEmpty()) {
return Result.error("查询失败,物品类型不存在");
}
return Result.success(itemTypeList);
}
+ /**
+ * 按id查询单个物品类型
+ *
+ * @param id 主键id
+ * @return ItemType
+ */
+ public ItemType getItemTypeById(Integer id) {
+ List itemTypeList = itemTypeDao.getItemTypeList(id);
+ if (itemTypeList == null || itemTypeList.isEmpty()) {
+ return null;
+ }
+ return itemTypeList.get(0);
+ }
+
+
}
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index 8e87a0d..197d3df 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -1,9 +1,9 @@
spring:
# 配置MySQL连接与Druid数据源
datasource:
- username: "zmc1_mysql"
- password: "zmc1_mysql@ctgu"
- url: "jdbc:mysql://rm-bp1yq8zn4da1x08scho.mysql.rds.aliyuncs.com:3306/lost_found?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=Asia/Shanghai"
+ username: "xxxxxxx"
+ password: "xxxxxxx"
+ url: "jdbc:mysql://xxxxxxx:3306/lost_found?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=Asia/Shanghai"
# 数据库驱动
driver-class-name: com.mysql.cj.jdbc.Driver
# 使用Druid数据源
@@ -13,7 +13,7 @@ spring:
druid:
initialsize: 5
minIdle: 5
- maxActive: 20
+ maxActive: 200
maxwait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
@@ -55,15 +55,43 @@ spring:
config:
drop-table-allow: false
+
+ # 配置Redis
+ redis:
+ # Redis服务器地址,默认为localhost
+ host: xxxxxxx
+ # Redis服务器连接端口,默认为6379
+ port: 9736
+ # Redis数据库索引,默认为0(使用0号数据库)
+ database: 0
+ # Redis服务器连接密码,默认为空
+ password: xxxxxxx
+ # 连接超时时间
+ timeout: 10s
+
+ lettuce:
+ # 配置连接池
+ pool:
+ # 连接池最大连接数
+ max-active: 200
+ # 连接池中的最大空闲连接
+ max-idle: 10
+ # 连接池中的最小空闲连接
+ min-idle: 0
+ # 连接池最大阻塞等待时间(使用负值表示没有限制)
+ max-wait: 100ms
+
+
mvc:
pathmatch:
# 解决因springboot版本过高而无法运行Swagger的问题
matching-strategy: ant_path_matcher
+
#配置邮件任务
mail:
username: 2869581855@qq.com
- password: icbcjgclczfjdegd
+ password: xxxxxxx
default-encoding: utf-8
port: 587
host: smtp.qq.com
@@ -75,6 +103,7 @@ spring:
enable: true
required: true
+
# 设置项目名称
application:
name: lost_found
--
Gitee