Переглянути джерело

1、获取树接口增加缓存
2、其他接口优化

yuchengwei 5 місяців тому
батько
коміт
a987b9a914

+ 9 - 0
pom.xml

@@ -187,6 +187,15 @@
             <optional>true</optional>
         </dependency>
 
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
+
     </dependencies>
     <dependencyManagement>
         <dependencies>

+ 26 - 0
src/main/java/com/qizhen/healsphere/config/CacheConfig.java

@@ -0,0 +1,26 @@
+package com.qizhen.healsphere.config;
+
+import com.github.benmanes.caffeine.cache.Caffeine;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.caffeine.CaffeineCacheManager;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.TimeUnit;
+
+@Configuration
+@EnableCaching
+public class CacheConfig {
+    
+    @Bean
+    public CacheManager cacheManager() {
+        CaffeineCacheManager cacheManager = new CaffeineCacheManager();
+        cacheManager.setCaffeine(Caffeine.newBuilder()
+                .initialCapacity(10)
+                .maximumSize(200)
+                .recordStats() // 开启统计
+                .expireAfterWrite(1, TimeUnit.HOURS));
+        return cacheManager;
+    }
+}

+ 0 - 33
src/main/java/com/qizhen/healsphere/config/MybatisPlusConfig.java

@@ -1,33 +0,0 @@
-package com.qizhen.healsphere.config;
-
-import com.baomidou.mybatisplus.annotation.DbType;
-import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
-import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class MybatisPlusConfig {
-    
-    private static final Logger log = LoggerFactory.getLogger(MybatisPlusConfig.class);
-    
-    @Bean
-    public MybatisPlusInterceptor mybatisPlusInterceptor() {
-        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
-        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
-        return interceptor;
-    }
-    
-    @Bean
-    public ConfigurationCustomizer configurationCustomizer() {
-        return configuration -> {
-            configuration.setMapUnderscoreToCamelCase(true);
-            configuration.setCallSettersOnNulls(true);
-            log.info("MyBatis-Plus configuration: mapUnderscoreToCamelCase={}", 
-                configuration.isMapUnderscoreToCamelCase());
-        };
-    }
-} 

+ 0 - 33
src/main/java/com/qizhen/healsphere/config/MybatisPlusConfigurer.java

@@ -1,33 +0,0 @@
-//package com.qizhen.healsphere.config;
-//
-//import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
-//import org.mybatis.spring.annotation.MapperScan;
-//import org.springframework.context.annotation.Bean;
-//import org.springframework.context.annotation.Configuration;
-//import org.springframework.transaction.annotation.EnableTransactionManagement;
-//
-///**
-// * @Description: MybatisPlus配置类
-// * @author: gaodm
-// * @time: 2018/8/2 13:39
-// */
-//@EnableTransactionManagement
-//@Configuration
-//@MapperScan("com.qizhen.healsphere.repository.mapper*")//这个注解,作用相当于下面的@Bean MapperScannerConfigurer,2者配置1份即可
-//public class MybatisPlusConfigurer {
-//
-//    /**
-//     * mybatis-plus分页插件<br>
-//     * 文档:http://mp.baomidou.com<br>
-//     */
-//    @Bean
-//    public PaginationInterceptor paginationInterceptor() {
-//        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
-//        // 设置请求的页面大于最大页后操作,true调回到首页,false继续请求,默认false
-//        //paginationInterceptor.setOverflow(false);
-//        // 设置最大单页限制数量,默认500条,-1不受限制
-//        paginationInterceptor.setLimit(500L);
-//        return paginationInterceptor;
-//    }
-//
-//}

+ 17 - 0
src/main/java/com/qizhen/healsphere/config/MysqlConfig.java

@@ -1,6 +1,9 @@
 package com.qizhen.healsphere.config;
 
+import com.baomidou.mybatisplus.annotation.DbType;
 import com.baomidou.mybatisplus.core.MybatisConfiguration;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
 import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
 import org.apache.ibatis.session.SqlSessionFactory;
 import org.springframework.beans.factory.annotation.Qualifier;
@@ -21,6 +24,17 @@ public class MysqlConfig {
         return DataSourceBuilder.create().build();
     }
 
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        // 添加分页插件
+        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor(DbType.POSTGRE_SQL);
+        // 设置最大单页限制数量,默认 500 条,-1 不受限制
+        paginationInterceptor.setMaxLimit(500L);
+        interceptor.addInnerInterceptor(paginationInterceptor);
+        return interceptor;
+    }
+
     @Bean
     public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
         MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
@@ -32,6 +46,9 @@ public class MysqlConfig {
         configuration.setCallSettersOnNulls(true);
         sqlSessionFactoryBean.setConfiguration(configuration);
         
+        // 设置插件
+        sqlSessionFactoryBean.setPlugins(mybatisPlusInterceptor());
+        
         return sqlSessionFactoryBean.getObject();
     }
 }

+ 3 - 3
src/main/java/com/qizhen/healsphere/facade/KgFacade.java

@@ -77,9 +77,9 @@ public class KgFacade extends KgServiceImpl {
                         for (NextNodeDTO baseNodeDTO : baseNodeRSDTO.getENodeDTOS()) {
                             Map<String,Object> childrenItemStyleMap = new HashMap<>();
                             String symbol = "circle";
-                            if (baseNodeDTO.getPCount() == 0) {
-                                childrenItemStyleMap.put("color", "#808080");
-                            }
+//                            if (baseNodeDTO.getPCount() == 0) {
+//                                childrenItemStyleMap.put("color", "#808080");
+//                            }
                             GNodeDTO eNodeDTO
                                     = new GNodeDTO(baseNodeDTO.getLabel(), cMap.get(baseNodeRSDTO.getRType()),
                                     baseNodeDTO.getName(), nodeId, symbol, 28, baseNodeDTO.getProperties(),baseNodeDTO.getId(),childrenItemStyleMap);

+ 6 - 3
src/main/java/com/qizhen/healsphere/repository/mapper/KgCountTotalInfoMapper.java

@@ -15,7 +15,7 @@ public interface KgCountTotalInfoMapper extends BaseMapper<KgCountTotalInfo> {
     
     @Select("SELECT id, gmt_create, gmt_modified, " +
             "node_type_num, node_num, node_prop_num, " +
-            "relation_type_num, relation_num " +
+            "relation_type_num, relation_num, term_num " +
             "FROM kg_count_total_info LIMIT 1")
     KgCountTotalInfo getCountTotalInfo();
     
@@ -27,13 +27,16 @@ public interface KgCountTotalInfoMapper extends BaseMapper<KgCountTotalInfo> {
             "t1.node_num as node_num, " +
             "t2.node_prop_num as node_prop_num, " +
             "t3.relation_type_num as relation_type_num, " +
-            "t3.relation_num as relation_num " +
+            "t3.relation_num as relation_num, " +
+            "t4.term_num as term_num " +
             "FROM (" +
             "   SELECT COUNT(DISTINCT category) as node_type_num, COUNT(*) as node_num FROM kg_nodes" +
             ") t1, (" +
             "   SELECT COUNT(*) as node_prop_num FROM kg_props" +
             ") t2, (" +
             "   SELECT COUNT(DISTINCT name) as relation_type_num, COUNT(*) as relation_num FROM kg_edges" +
-            ") t3")
+            ") t3, (" +
+            "   SELECT COUNT(DISTINCT name) as term_num FROM kg_nodes" +
+            ") t4")
     KgCountTotalInfo calculateTotalInfo();
 }

+ 3 - 0
src/main/java/com/qizhen/healsphere/repository/mapper/entity/KgCountTotalInfo.java

@@ -31,4 +31,7 @@ public class KgCountTotalInfo {
     
     @TableField("relation_num")
     private Integer relationNum;
+    
+    @TableField("term_num")
+    private Integer termNum;
 }

+ 90 - 36
src/main/java/com/qizhen/healsphere/repository/neo4j/BaseNodeRepository.java

@@ -213,43 +213,11 @@ public class BaseNodeRepository {
             Node newNode = newNodeResult.single().get("n").asNode();
             long newNodeId = newNode.id();
 
-            // 合并关系 - 修改这部分代码
-            // 合并关系 - 保持原始方向
-            String firstRelationQuery = String.format(
-                "MATCH (a:`%s`)-[r]->(other) WHERE id(a) = $firstId " +  // 出向关系
-                "WITH r, other, type(r) as relType, properties(r) as props " +
-                "MATCH (n) WHERE id(n) = $newNodeId " +
-                            "MERGE (n)-[newRel:relType]->(other) " +  // 创建出向关系
-                "SET newRel += props " +
-                "UNION ALL " +
-                "MATCH (a:`%s`)<-[r]-(other) WHERE id(a) = $firstId " +  // 入向关系
-                "WITH r, other, type(r) as relType, properties(r) as props " +
-                "MATCH (n) WHERE id(n) = $newNodeId " +
-                            "MERGE (n)<-[newRel:relType]-(other) " +  // 创建入向关系
-                "SET newRel += props", 
-                mergeNodeParam.getFirstLabel(),
-                mergeNodeParam.getFirstLabel()
-            );
+            // 处理第一个节点的关系
+            processNodeRelations(session, mergeNodeParam.getFirstLabel(), mergeNodeParam.getFirstId(), newNodeId);
             
-            String secondRelationQuery = String.format(
-                "MATCH (b:`%s`)-[r]->(other) WHERE id(b) = $secondId " +  // 出向关系
-                "WITH r, other, type(r) as relType, properties(r) as props " +
-                "MATCH (n) WHERE id(n) = $newNodeId " +
-                            "MERGE (n)-[newRel:relType]->(other) " +  // 创建出向关系
-                "SET newRel += props " +
-                "UNION ALL " +
-                "MATCH (b:`%s`)<-[r]-(other) WHERE id(b) = $secondId " +  // 入向关系
-                "WITH r, other, type(r) as relType, properties(r) as props " +
-                "MATCH (n) WHERE id(n) = $newNodeId " +
-                            "MERGE (n)<-[newRel:relType]-(other) " +  // 创建入向关系
-                "SET newRel += props",
-                mergeNodeParam.getSecondLabel(),
-                mergeNodeParam.getSecondLabel()
-            );
-
-            // 执行关系迁移
-            session.run(firstRelationQuery, Values.parameters("firstId", mergeNodeParam.getFirstId(), "newNodeId", newNodeId));
-            session.run(secondRelationQuery, Values.parameters("secondId", mergeNodeParam.getSecondId(), "newNodeId", newNodeId));
+            // 处理第二个节点的关系
+            processNodeRelations(session, mergeNodeParam.getSecondLabel(), mergeNodeParam.getSecondId(), newNodeId);
 
             // 删除原始节点
             session.run(
@@ -269,6 +237,92 @@ public class BaseNodeRepository {
         }
     }
 
+    /**
+     * 处理节点的所有关系
+     */
+    private void processNodeRelations(Session session, String label, Long sourceNodeId, Long newNodeId) {
+        // 获取所有关系类型
+        String getRelationsQuery = String.format(
+            "MATCH (a:`%s`)-[r]-() WHERE id(a) = $nodeId " +
+            "WITH DISTINCT type(r) as relType " +
+            "ORDER BY relType " +
+            "RETURN relType", 
+            label
+        );
+
+        // 使用cursor处理关系类型
+        StatementResult relTypes = session.run(getRelationsQuery, 
+            Values.parameters("nodeId", sourceNodeId));
+        
+        while (relTypes.hasNext()) {
+            String relType = relTypes.next().get("relType").asString();
+            
+            // 使用cursor处理出向关系
+            String outRelQuery = String.format(
+                "MATCH (a:`%s`)-[r:`%s`]->(other) WHERE id(a) = $sourceId " +
+                "WITH r, other " +
+                "ORDER BY id(other) " +
+                "RETURN r, other",
+                label, relType
+            );
+            
+            StatementResult outRels = session.run(outRelQuery, 
+                Values.parameters("sourceId", sourceNodeId));
+            
+            while (outRels.hasNext()) {
+                Record record = outRels.next();
+                Relationship rel = record.get("r").asRelationship();
+                Node other = record.get("other").asNode();
+                
+                // 创建新关系
+                String createRelQuery = String.format(
+                    "MATCH (n), (other) WHERE id(n) = $newNodeId AND id(other) = $otherId " +
+                    "MERGE (n)-[newRel:`%s`]->(other) " +
+                    "SET newRel += $props",
+                    relType
+                );
+                
+                session.run(createRelQuery, Values.parameters(
+                    "newNodeId", newNodeId,
+                    "otherId", other.id(),
+                    "props", rel.asMap()
+                ));
+            }
+            
+            // 使用cursor处理入向关系
+            String inRelQuery = String.format(
+                "MATCH (a:`%s`)<-[r:`%s`]-(other) WHERE id(a) = $sourceId " +
+                "WITH r, other " +
+                "ORDER BY id(other) " +
+                "RETURN r, other",
+                label, relType
+            );
+            
+            StatementResult inRels = session.run(inRelQuery, 
+                Values.parameters("sourceId", sourceNodeId));
+            
+            while (inRels.hasNext()) {
+                Record record = inRels.next();
+                Relationship rel = record.get("r").asRelationship();
+                Node other = record.get("other").asNode();
+                
+                // 创建新关系
+                String createRelQuery = String.format(
+                    "MATCH (n), (other) WHERE id(n) = $newNodeId AND id(other) = $otherId " +
+                    "MERGE (other)-[newRel:`%s`]->(n) " +
+                    "SET newRel += $props",
+                    relType
+                );
+                
+                session.run(createRelQuery, Values.parameters(
+                    "newNodeId", newNodeId,
+                    "otherId", other.id(),
+                    "props", rel.asMap()
+                ));
+            }
+        }
+    }
+
     /**
      * 新增实体
      * @param label

+ 32 - 16
src/main/java/com/qizhen/healsphere/service/impl/KgCountServiceImpl.java

@@ -18,7 +18,9 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.stream.Collectors;
 
 /**
@@ -30,6 +32,18 @@ import java.util.stream.Collectors;
 @Service
 public class KgCountServiceImpl implements KgCountService {
 
+    private static final Map<String, String> NODE_TYPE_MAP = new HashMap<>();
+    
+    static {
+        NODE_TYPE_MAP.put("Food", "食品");
+        NODE_TYPE_MAP.put("Department", "科室");
+        NODE_TYPE_MAP.put("Drug", "药品");
+        NODE_TYPE_MAP.put("Check", "检查");
+        NODE_TYPE_MAP.put("Symptom", "症状");
+        NODE_TYPE_MAP.put("Producer", "厂商");
+        NODE_TYPE_MAP.put("Disease", "疾病");
+    }
+
     @Autowired
     private KgCountTotalInfoMapper kgCountTotalInfoMapper;
 
@@ -47,8 +61,9 @@ public class KgCountServiceImpl implements KgCountService {
         infoVOS.add(createInfoVO("实体属性", 0));
         infoVOS.add(createInfoVO("关系类型", 0));
         infoVOS.add(createInfoVO("关系", 0));
+        infoVOS.add(createInfoVO("术语", 0));
 
-        // 查询统计数据 - 使用原来的方法
+        // 查询统计数据
         KgCountTotalInfo countTotalInfo = kgCountTotalInfoMapper.getCountTotalInfo();
 
         // 更新统计数据
@@ -58,6 +73,7 @@ public class KgCountServiceImpl implements KgCountService {
             infoVOS.get(2).setNum(countTotalInfo.getNodePropNum());
             infoVOS.get(3).setNum(countTotalInfo.getRelationTypeNum());
             infoVOS.get(4).setNum(countTotalInfo.getRelationNum());
+            infoVOS.get(5).setNum(countTotalInfo.getTermNum());
         }
 
         countInfoVO.setInfos(infoVOS);
@@ -74,36 +90,36 @@ public class KgCountServiceImpl implements KgCountService {
     @Override
     public com.qizhen.healsphere.web.vo.Page<CountListVO> getCountListInfo(KgCountListPageQuery query) {
         try {
-            // 在这里设置断点
             Page<KgCountInfo> page = new Page<>(query.getPageNo(), query.getPageSize());
             
-            // 在这里设置断点
             QueryWrapper<KgCountInfo> queryWrapper = new QueryWrapper<>();
             queryWrapper.orderByDesc("node_num");
             
-            // 在这里设置断点
             Page<KgCountInfo> result = kgCountInfoMapper.selectPage(page, queryWrapper);
             
             if (result == null || result.getRecords() == null) {
                 log.warn("查询结果为null");
-                return new com.qizhen.healsphere.web.vo.Page<>(query.getPageNo(), query.getPageSize(), 0, 0, new ArrayList<>());
+                return new com.qizhen.healsphere.web.vo.Page<>(
+                    query.getPageNo(), 
+                    query.getPageSize(), 
+                    0, 
+                    0, 
+                    new ArrayList<>()
+                );
             }
             
-            log.info("查询到 {} 条记录", result.getRecords().size());
-            result.getRecords().forEach(record -> {
-                log.info("记录详情: {}", record);
-                log.info("SQL查询结果字段值: id={}, nodeType={}, nodeNum={}, nodePropNum={}, relationType={}, relationNum={}",
-                    record.getId(), record.getNodeType(), record.getNodeNum(), 
-                    record.getNodePropNum(), record.getRelationType(), record.getRelationNum());
-            });
-            
-            // 转换为 VO 对象
+            // 转换为 VO 对象,并进行类型名称转换
             List<CountListVO> listVOS = result.getRecords().stream()
                 .map(info -> {
                     CountListVO vo = new CountListVO();
-                    log.info("转换前的实体对象: {}", info);
                     BeanUtil.copyProperties(info, vo);
-                    log.info("转换后的VO对象: {}", vo);
+                    
+                    // 转换节点类型名称
+                    String nodeType = info.getNodeType();
+                    if (nodeType != null) {
+                        vo.setNodeType(NODE_TYPE_MAP.getOrDefault(nodeType, nodeType));
+                    }
+                    
                     return vo;
                 })
                 .collect(Collectors.toList());

+ 104 - 2
src/main/java/com/qizhen/healsphere/web/KgController.java

@@ -1,5 +1,8 @@
 package com.qizhen.healsphere.web;
 
+import cn.hutool.json.JSONUtil;
+import com.github.benmanes.caffeine.cache.Cache;
+import com.github.benmanes.caffeine.cache.stats.CacheStats;
 import com.qizhen.healsphere.web.dto.GraphLabelDTO;
 import com.qizhen.healsphere.web.dto.NodeDTO;
 import com.qizhen.healsphere.web.dto.RespDTO;
@@ -11,12 +14,17 @@ 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.CacheManager;
+import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.caffeine.CaffeineCache;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.*;
 
 import javax.validation.Valid;
 import java.util.List;
+import java.util.Map;
+import java.util.HashMap;
 
 /**
  * @Description: 朗通知识图谱控制层
@@ -34,6 +42,9 @@ public class KgController {
     @Autowired
     private KgFacade kgFacade;
 
+    @Autowired
+    private CacheManager cacheManager;
+
     @ApiOperation(value = "获取图谱", notes = "获取图谱")
     @RequestMapping(value = "/getGraph", method = RequestMethod.POST)
     @ResponseBody
@@ -53,8 +64,11 @@ public class KgController {
     @ResponseBody
     @Cacheable(value = KGTREECACHE, key = "'kgtree:t_' + #kgTree.type + '_st_' + #kgTree.subType")
     public RespDTO<TreeDTO> getTree(@RequestBody @Valid KgTree kgTree) {
-        log.info("获取树形分类缓存成功");
-        return RespDTO.onSuc(kgFacade.getTreeFac(kgTree));
+        log.info("Cache miss for key: kgtree:t_{}_st_{}, executing method...", 
+            kgTree.getType(), kgTree.getSubType());
+        TreeDTO result = kgFacade.getTreeFac(kgTree);
+        log.info("Method executed, result will be cached");
+        return RespDTO.onSuc(result);
     }
 
     @ApiOperation(value = "查询节点", notes = "查询节点")
@@ -63,5 +77,93 @@ public class KgController {
     public RespDTO<List<NodeDTO>> getNode(@RequestBody @Valid KgQuery kgQuery) {
         return RespDTO.onSuc(kgFacade.getNode(kgQuery));
     }
+
+    @ApiOperation(value = "清理树形分类缓存", notes = "清理树形分类缓存")
+    @RequestMapping(value = "/delKgTreeCache",method = RequestMethod.POST)
+    @ResponseBody
+    @CacheEvict(cacheNames = KGTREECACHE, allEntries = true)
+    public RespDTO<Boolean> delKgTreeCache() {
+        log.info("清理树形分类缓存成功");
+        return RespDTO.onSuc(true);
+    }
+
+    @ApiOperation(value = "获取缓存数据", notes = "获取指定key的缓存数据")
+    @RequestMapping(value = "/cache-stats", method = RequestMethod.GET)
+    @ResponseBody
+    public RespDTO<Map<String, Object>> getCacheStats() {
+        Map<String, Object> stats = new HashMap<>();
+        
+        CaffeineCache caffeineCache = (CaffeineCache) cacheManager.getCache(KGTREECACHE);
+        if (caffeineCache != null) {
+            Cache<Object, Object> nativeCache = caffeineCache.getNativeCache();
+            
+            // 获取缓存统计信息
+            CacheStats cacheStats = nativeCache.stats();
+            stats.put("hitCount", cacheStats.hitCount());
+            stats.put("missCount", cacheStats.missCount());
+            stats.put("hitRate", cacheStats.hitRate());
+            
+            // 获取所有缓存的key
+            Map<Object, Object> cacheData = nativeCache.asMap();
+            stats.put("cacheSize", cacheData.size());
+            stats.put("cacheKeys", cacheData.keySet());
+            
+            // 获取具体缓存内容
+            stats.put("cacheContent", cacheData);
+        }
+        
+        return RespDTO.onSuc(stats);
+    }
+
+    @ApiOperation(value = "获取指定key的缓存数据", notes = "获取指定key的缓存数据")
+    @RequestMapping(value = "/cache-data/{type}/{subType}", method = RequestMethod.GET)
+    @ResponseBody
+    public RespDTO<TreeDTO> getCacheData(@PathVariable Integer type, @PathVariable Integer subType) {
+        String cacheKey = String.format("kgtree:t_%d_st_%d", type, subType);
+        log.info("尝试获取缓存key: {}", cacheKey);
+        
+        try {
+            CaffeineCache caffeineCache = (CaffeineCache) cacheManager.getCache(KGTREECACHE);
+            if (caffeineCache == null) {
+                log.warn("未找到名为 {} 的缓存", KGTREECACHE);
+                return RespDTO.onError("Cache manager not found");
+            }
+            
+            Cache<Object, Object> nativeCache = caffeineCache.getNativeCache();
+            Object value = nativeCache.getIfPresent(cacheKey);
+            
+            if (value == null) {
+                log.info("未找到key为 {} 的缓存数据", cacheKey);
+                return RespDTO.onError("Cache data not found");
+            }
+            
+            log.debug("获取到的缓存数据类型: {}", value.getClass().getName());
+            
+            // 如果是RespDTO类型
+            if (value instanceof RespDTO) {
+                log.info("缓存数据是RespDTO类型");
+                return (RespDTO<TreeDTO>) value;
+            }
+            
+            // 如果是JSON字符串
+            if (value instanceof String) {
+                log.info("缓存数据是String类型,尝试解析JSON");
+                String jsonStr = (String) value;
+                TreeDTO treeDTO = JSONUtil.toBean(
+                    JSONUtil.parseObj(jsonStr).getObj("data").toString(), 
+                    TreeDTO.class
+                );
+                return RespDTO.onSuc(treeDTO);
+            }
+            
+            // 其他类型的处理
+            log.warn("未知的缓存数据类型: {}", value.getClass().getName());
+            return RespDTO.onError("Unknown cache data type");
+            
+        } catch (Exception e) {
+            log.error("获取缓存数据失败", e);
+            return RespDTO.onError("获取缓存数据失败: " + e.getMessage());
+        }
+    }
 }
 

+ 4 - 0
src/main/resources/application.yml

@@ -6,6 +6,10 @@ spring:
   jackson:
     serialization:
       indent-output: false
+  cache:
+    type: caffeine
+    caffeine:
+      spec: initialCapacity=10,maximumSize=200
 
 server:
   servlet: