feat(缓存): 添加Caffeine缓存管理接口及功能扩展

- 新增CaffeineController提供缓存查询、统计和清空功能
- 在AbstractCaffeineCacheTemplate中添加getAll和getAllWithOptional方法
- 更新.claude配置添加mvnw相关命令
This commit is contained in:
dzq 2025-11-11 17:10:57 +08:00
parent a78da5cb59
commit e41c7c27f5
3 changed files with 219 additions and 1 deletions

View File

@ -36,7 +36,8 @@
"Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/query/SearchUserQuery.java\")", "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/query/SearchUserQuery.java\")",
"Bash(./mvnw clean compile -pl agileboot-api -am -DskipTests)", "Bash(./mvnw clean compile -pl agileboot-api -am -DskipTests)",
"Bash(./mvnw clean compile -pl agileboot-api,agileboot-domain -am -DskipTests)", "Bash(./mvnw clean compile -pl agileboot-api,agileboot-domain -am -DskipTests)",
"Bash(./mvnw clean compile -pl agileboot-domain -am -DskipTests)" "Bash(./mvnw clean compile -pl agileboot-domain -am -DskipTests)",
"Bash(./mvnw:*)"
], ],
"deny": [], "deny": [],
"ask": [] "ask": []

View File

@ -0,0 +1,185 @@
package com.agileboot.api.controller;
import com.agileboot.domain.common.cache.CaffeineCacheService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
* Caffeine缓存管理控制器
* 提供缓存查询统计清空等管理功能
*
* @author valarchie
*/
@Slf4j
@RestController
@RequestMapping("/api/caffeine")
@Tag(name = "Caffeine缓存管理", description = "Caffeine本地缓存查询和管理接口")
@RequiredArgsConstructor
public class CaffeineController {
@Autowired
private CaffeineCacheService caffeineCacheService;
/**
* 获取所有Caffeine缓存的统计信息
*/
@GetMapping("/stats")
@Operation(summary = "获取缓存统计信息", description = "返回所有Caffeine缓存的详细统计信息")
public ResponseEntity<String> getCacheStats() {
try {
String stats = caffeineCacheService.getCacheStats();
return ResponseEntity.ok(stats);
} catch (Exception e) {
log.error("获取缓存统计信息失败", e);
return ResponseEntity.internalServerError()
.body("获取缓存统计信息失败: " + e.getMessage());
}
}
/**
* 清空指定类型的缓存
*
* @param cacheName 缓存名称 (captchaCache, loginUserCache, userCache, roleCache, postCache, qyUseridCache, dynamicCodeCache)
*/
@DeleteMapping("/cache/{cacheName}")
@Operation(summary = "清空指定缓存", description = "清空指定类型的Caffeine缓存")
public ResponseEntity<String> clearCache(@PathVariable String cacheName) {
try {
switch (cacheName) {
case "captchaCache":
caffeineCacheService.captchaCache.invalidateAll();
break;
case "loginUserCache":
caffeineCacheService.loginUserCache.invalidateAll();
break;
case "userCache":
caffeineCacheService.userCache.invalidateAll();
break;
case "roleCache":
caffeineCacheService.roleCache.invalidateAll();
break;
case "postCache":
caffeineCacheService.postCache.invalidateAll();
break;
case "qyUseridCache":
caffeineCacheService.qyUseridCache.invalidateAll();
break;
case "dynamicCodeCache":
caffeineCacheService.dynamicCodeCache.invalidateAll();
break;
default:
return ResponseEntity.badRequest()
.body("未知的缓存类型: " + cacheName + ",支持的类型: captchaCache, loginUserCache, userCache, roleCache, postCache, qyUseridCache, dynamicCodeCache");
}
return ResponseEntity.ok("缓存 [" + cacheName + "] 已清空");
} catch (Exception e) {
log.error("清空缓存失败: {}", cacheName, e);
return ResponseEntity.internalServerError()
.body("清空缓存失败: " + e.getMessage());
}
}
/**
* 清空所有Caffeine缓存
*/
@DeleteMapping("/cache")
@Operation(summary = "清空所有缓存", description = "清空所有类型的Caffeine缓存")
public ResponseEntity<String> clearAllCaches() {
try {
caffeineCacheService.captchaCache.invalidateAll();
caffeineCacheService.loginUserCache.invalidateAll();
caffeineCacheService.userCache.invalidateAll();
caffeineCacheService.roleCache.invalidateAll();
caffeineCacheService.postCache.invalidateAll();
caffeineCacheService.qyUseridCache.invalidateAll();
caffeineCacheService.dynamicCodeCache.invalidateAll();
return ResponseEntity.ok("所有Caffeine缓存已清空");
} catch (Exception e) {
log.error("清空所有缓存失败", e);
return ResponseEntity.internalServerError()
.body("清空所有缓存失败: " + e.getMessage());
}
}
/**
* 获取所有缓存数据
*/
@GetMapping("/cache/all")
@Operation(summary = "获取所有缓存数据", description = "获取所有Caffeine缓存中的数据")
public ResponseEntity<?> getAllCacheData() {
try {
Map<String, Object> allCaches = new HashMap<>();
allCaches.put("captchaCache", caffeineCacheService.captchaCache.getAll());
allCaches.put("loginUserCache", caffeineCacheService.loginUserCache.getAll());
allCaches.put("userCache", caffeineCacheService.userCache.getAll());
allCaches.put("roleCache", caffeineCacheService.roleCache.getAll());
allCaches.put("postCache", caffeineCacheService.postCache.getAll());
allCaches.put("qyUseridCache", caffeineCacheService.qyUseridCache.getAll());
allCaches.put("dynamicCodeCache", caffeineCacheService.dynamicCodeCache.getAll());
return ResponseEntity.ok(allCaches);
} catch (Exception e) {
log.error("获取所有缓存数据失败", e);
return ResponseEntity.internalServerError()
.body("获取所有缓存数据失败: " + e.getMessage());
}
}
/**
* 获取指定缓存的数据
*/
@GetMapping("/cache/{cacheName}/data")
@Operation(summary = "获取指定缓存数据", description = "获取指定类型的Caffeine缓存数据")
public ResponseEntity<?> getCacheData(@PathVariable String cacheName) {
try {
Map<String, Object> result = new HashMap<>();
result.put("cacheName", cacheName);
switch (cacheName) {
case "captchaCache":
result.put("data", caffeineCacheService.captchaCache.getAll());
break;
case "loginUserCache":
result.put("data", caffeineCacheService.loginUserCache.getAll());
break;
case "userCache":
result.put("data", caffeineCacheService.userCache.getAll());
break;
case "roleCache":
result.put("data", caffeineCacheService.roleCache.getAll());
break;
case "postCache":
result.put("data", caffeineCacheService.postCache.getAll());
break;
case "qyUseridCache":
result.put("data", caffeineCacheService.qyUseridCache.getAll());
break;
case "dynamicCodeCache":
result.put("data", caffeineCacheService.dynamicCodeCache.getAll());
break;
default:
return ResponseEntity.badRequest()
.body(Map.of("error", "未知的缓存类型: " + cacheName,
"supportedTypes", new String[]{
"captchaCache", "loginUserCache", "userCache",
"roleCache", "postCache", "qyUseridCache", "dynamicCodeCache"
}));
}
return ResponseEntity.ok(result);
} catch (Exception e) {
log.error("获取缓存数据失败: {}", cacheName, e);
return ResponseEntity.internalServerError()
.body(Map.of("error", "获取缓存数据失败: " + e.getMessage()));
}
}
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.util.StrUtil;
import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.CacheLoader;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache; import com.github.benmanes.caffeine.cache.LoadingCache;
import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -132,6 +133,37 @@ public abstract class AbstractCaffeineCacheTemplate<T> {
return caffeineCache.stats().toString(); return caffeineCache.stats().toString();
} }
/**
* 获取缓存中所有数据
* @return 缓存中的所有数据不包含值为null的条目
*/
public java.util.Map<String, T> getAll() {
try {
return caffeineCache.asMap().entrySet().stream()
.filter(entry -> entry.getValue().isPresent())
.collect(java.util.stream.Collectors.toMap(
Map.Entry::getKey,
entry -> entry.getValue().get()
));
} catch (Exception e) {
log.error("获取Caffeine缓存所有数据失败", e);
return new java.util.HashMap<>();
}
}
/**
* 获取缓存中所有数据包括key和value
* @return 包含key和Optional<T>的Map
*/
public java.util.Map<String, Optional<T>> getAllWithOptional() {
try {
return new java.util.HashMap<>(caffeineCache.asMap());
} catch (Exception e) {
log.error("获取Caffeine缓存所有数据失败", e);
return new java.util.HashMap<>();
}
}
/** /**
* 从数据库加载数据 * 从数据库加载数据
* @param id 数据ID * @param id 数据ID