From ea7427fe15da6155519a7483914013081ac46234 Mon Sep 17 00:00:00 2001
From: xingjinshuang <xingjs@qq.com>
Date: 星期二, 17 十二月 2024 16:48:22 +0800
Subject: [PATCH] @xingjs@20241217@添加实体库查询系列接口,返回实体库相关属性信息

---
 src/main/java/com/se/simu/domain/EntityTypeInfo.java                  |   30 +
 src/main/resources/application-zyy.yml                                |   13 
 src/main/java/com/se/simu/constant/RedisCache.java                    |  243 ++++++++++
 src/main/java/com/se/simu/domain/EntityDataBase.java                  |   38 +
 src/main/java/com/se/simu/service/ProjectRelatedService.java          |   33 +
 src/main/resources/application-prod.yml                               |   16 
 src/main/java/com/se/simu/domain/LoginParams.java                     |   17 
 src/main/java/com/se/simu/controller/ProjectRelatedController.java    |   89 +++
 src/main/java/com/se/simu/service/Impl/ProjectRelatedServiceImpl.java |  337 ++++++++++++++
 pom.xml                                                               |   12 
 src/main/java/com/se/simu/constant/CacheConstants.java                |   48 ++
 src/main/java/com/se/simu/utils/CustomWebClient.java                  |  500 +++++++++++++++++++++
 12 files changed, 1,376 insertions(+), 0 deletions(-)

diff --git a/pom.xml b/pom.xml
index a397813..101c53a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -166,6 +166,18 @@
             <version>1.33</version>
             <scope>compile</scope>
         </dependency>
+
+
+        <!--webclient璇锋眰-->
+        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-webflux -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+            <version>3.3.1</version>
+        </dependency>
+
+
+
     </dependencies>
 
     <build>
diff --git a/src/main/java/com/se/simu/constant/CacheConstants.java b/src/main/java/com/se/simu/constant/CacheConstants.java
new file mode 100644
index 0000000..00e5e4e
--- /dev/null
+++ b/src/main/java/com/se/simu/constant/CacheConstants.java
@@ -0,0 +1,48 @@
+package com.se.simu.constant;
+
+/**
+ * 缂撳瓨鐨刱ey 甯搁噺
+ *
+ * @author ruoyi
+ */
+public class CacheConstants {
+    /**
+     * 鐧诲綍鐢ㄦ埛 redis key
+     */
+    public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+    /**
+     * 楠岃瘉鐮� redis key
+     */
+    public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+    /**
+     * 鍙傛暟绠$悊 cache key
+     */
+    public static final String SYS_CONFIG_KEY = "sys_config:";
+
+    /**
+     * 瀛楀吀绠$悊 cache key
+     */
+    public static final String SYS_DICT_KEY = "sys_dict:";
+
+    /**
+     * 闃查噸鎻愪氦 redis key
+     */
+    public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
+
+    /**
+     * 闄愭祦 redis key
+     */
+    public static final String RATE_LIMIT_KEY = "rate_limit:";
+
+    /**
+     * 鐧诲綍璐︽埛瀵嗙爜閿欒娆℃暟 redis key
+     */
+    public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+
+    /**
+     * 鐢ㄦ埛鑷畾涔夌紦瀛� redis key
+     */
+    public static final String USER_CACHE_KEY = "user_cache_key:";
+}
diff --git a/src/main/java/com/se/simu/constant/RedisCache.java b/src/main/java/com/se/simu/constant/RedisCache.java
new file mode 100644
index 0000000..4dfed2b
--- /dev/null
+++ b/src/main/java/com/se/simu/constant/RedisCache.java
@@ -0,0 +1,243 @@
+package com.se.simu.constant;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.BoundSetOperations;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * spring redis 宸ュ叿绫�
+ *
+ * @author ruoyi
+ **/
+@SuppressWarnings(value = {"unchecked", "rawtypes"})
+@Component
+public class RedisCache {
+    @Autowired
+    public RedisTemplate redisTemplate;
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛�
+     *
+     * @param key   缂撳瓨鐨勯敭鍊�
+     * @param value 缂撳瓨鐨勫��
+     */
+    public <T> void setCacheObject(final String key, final T value) {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛�
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param value    缂撳瓨鐨勫��
+     * @param timeout  鏃堕棿
+     * @param timeUnit 鏃堕棿棰楃矑搴�
+     */
+    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
+        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
+    }
+
+    /**
+     * 璁剧疆鏈夋晥鏃堕棿
+     *
+     * @param key     Redis閿�
+     * @param timeout 瓒呮椂鏃堕棿
+     * @return true=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触
+     */
+    public boolean expire(final String key, final long timeout) {
+        return expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 璁剧疆鏈夋晥鏃堕棿
+     *
+     * @param key     Redis閿�
+     * @param timeout 瓒呮椂鏃堕棿
+     * @param unit    鏃堕棿鍗曚綅
+     * @return true=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触
+     */
+    public boolean expire(final String key, final long timeout, final TimeUnit unit) {
+        return redisTemplate.expire(key, timeout, unit);
+    }
+
+    /**
+     * 鑾峰彇鏈夋晥鏃堕棿
+     *
+     * @param key Redis閿�
+     * @return 鏈夋晥鏃堕棿
+     */
+    public long getExpire(final String key) {
+        return redisTemplate.getExpire(key);
+    }
+
+    /**
+     * 鍒ゆ柇 key鏄惁瀛樺湪
+     *
+     * @param key 閿�
+     * @return true 瀛樺湪 false涓嶅瓨鍦�
+     */
+    public Boolean hasKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨勫熀鏈璞°��
+     *
+     * @param key 缂撳瓨閿��
+     * @return 缂撳瓨閿�煎搴旂殑鏁版嵁
+     */
+    public <T> T getCacheObject(final String key) {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        return operation.get(key);
+    }
+
+    /**
+     * 鍒犻櫎鍗曚釜瀵硅薄
+     *
+     * @param key
+     */
+    public boolean deleteObject(final String key) {
+        return redisTemplate.delete(key);
+    }
+
+    /**
+     * 鍒犻櫎闆嗗悎瀵硅薄
+     *
+     * @param collection 澶氫釜瀵硅薄
+     * @return
+     */
+    public boolean deleteObject(final Collection collection) {
+        return redisTemplate.delete(collection) > 0;
+    }
+
+    /**
+     * 缂撳瓨List鏁版嵁
+     *
+     * @param key      缂撳瓨鐨勯敭鍊�
+     * @param dataList 寰呯紦瀛樼殑List鏁版嵁
+     * @return 缂撳瓨鐨勫璞�
+     */
+    public <T> long setCacheList(final String key, final List<T> dataList) {
+        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+        return count == null ? 0 : count;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨刲ist瀵硅薄
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @return 缂撳瓨閿�煎搴旂殑鏁版嵁
+     */
+    public <T> List<T> getCacheList(final String key) {
+        return redisTemplate.opsForList().range(key, 0, -1);
+    }
+
+    /**
+     * 缂撳瓨Set
+     *
+     * @param key     缂撳瓨閿��
+     * @param dataSet 缂撳瓨鐨勬暟鎹�
+     * @return 缂撳瓨鏁版嵁鐨勫璞�
+     */
+    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
+        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
+        Iterator<T> it = dataSet.iterator();
+        while (it.hasNext()) {
+            setOperation.add(it.next());
+        }
+        return setOperation;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨剆et
+     *
+     * @param key
+     * @return
+     */
+    public <T> Set<T> getCacheSet(final String key) {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+    /**
+     * 缂撳瓨Map
+     *
+     * @param key
+     * @param dataMap
+     */
+    public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
+        if (dataMap != null) {
+            redisTemplate.opsForHash().putAll(key, dataMap);
+        }
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨凪ap
+     *
+     * @param key
+     * @return
+     */
+    public <T> Map<String, T> getCacheMap(final String key) {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * 寰�Hash涓瓨鍏ユ暟鎹�
+     *
+     * @param key   Redis閿�
+     * @param hKey  Hash閿�
+     * @param value 鍊�
+     */
+    public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
+        redisTemplate.opsForHash().put(key, hKey, value);
+    }
+
+    /**
+     * 鑾峰彇Hash涓殑鏁版嵁
+     *
+     * @param key  Redis閿�
+     * @param hKey Hash閿�
+     * @return Hash涓殑瀵硅薄
+     */
+    public <T> T getCacheMapValue(final String key, final String hKey) {
+        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
+        return opsForHash.get(key, hKey);
+    }
+
+    /**
+     * 鑾峰彇澶氫釜Hash涓殑鏁版嵁
+     *
+     * @param key   Redis閿�
+     * @param hKeys Hash閿泦鍚�
+     * @return Hash瀵硅薄闆嗗悎
+     */
+    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
+        return redisTemplate.opsForHash().multiGet(key, hKeys);
+    }
+
+    /**
+     * 鍒犻櫎Hash涓殑鏌愭潯鏁版嵁
+     *
+     * @param key  Redis閿�
+     * @param hKey Hash閿�
+     * @return 鏄惁鎴愬姛
+     */
+    public boolean deleteCacheMapValue(final String key, final String hKey) {
+        return redisTemplate.opsForHash().delete(key, hKey) > 0;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨勫熀鏈璞″垪琛�
+     *
+     * @param pattern 瀛楃涓插墠缂�
+     * @return 瀵硅薄鍒楄〃
+     */
+    public Collection<String> keys(final String pattern) {
+        return redisTemplate.keys(pattern);
+    }
+}
diff --git a/src/main/java/com/se/simu/controller/ProjectRelatedController.java b/src/main/java/com/se/simu/controller/ProjectRelatedController.java
new file mode 100644
index 0000000..2bdda9f
--- /dev/null
+++ b/src/main/java/com/se/simu/controller/ProjectRelatedController.java
@@ -0,0 +1,89 @@
+package com.se.simu.controller;
+
+
+import com.se.simu.domain.EntityTypeInfo;
+import com.se.simu.domain.LoginParams;
+import com.se.simu.domain.vo.R;
+import com.se.simu.service.ProjectRelatedService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+@Api(tags = "瀹炰綋搴撶浉鍏虫帴鍙�")
+@CrossOrigin(origins = "*")
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/api/v1")
+public class ProjectRelatedController extends BaseController {
+
+    @Resource
+    private ProjectRelatedService projectRelatedService;
+
+
+    /**
+     * 鑾峰彇鍏挜
+     *
+     * @Cacheable 娣诲姞缂撳瓨锛岀浉鍚屾潯浠剁殑鏌ヨ涓嶅啀鏌ヨ鏁版嵁搴擄紝鑰屾槸浠庣紦瀛樹腑鏌ヨ锛�
+     * @CachePut 姣忔閮戒細璁块棶鏁版嵁搴擄紝骞舵洿鏂扮紦瀛橈紱
+     * @CacheEvict 娓呴櫎缂撳瓨
+     * <p>
+     * 娉ㄨВ涓弬鏁拌鏄庯細
+     * cacheNames/value锛氭寚瀹氱紦瀛樼粍浠剁殑鍚嶅瓧;
+     * key锛氱紦瀛樻暟鎹娇鐢ㄧ殑key;鍙互鐢ㄥ畠鏉ユ寚瀹氥�傞粯璁ゆ槸浣跨敤鏂规硶鍙傛暟鐨勫��  1-鏂规硶鍏ㄥ弬 2-鏂规硶鍙傛暟鐨勬煇鍑犱釜 3-key(SpEL)
+     * keyGenerator锛歬ey鐨勭敓鎴愬櫒锛涘彲浠ヨ嚜宸辨寚瀹歬ey鐨勭敓鎴愬櫒鐨勭粍浠秈d
+     * cacheManager锛氭寚瀹氱紦瀛樼鐞嗗櫒锛涙垨鑰卌acheResolver鎸囧畾鑾峰彇瑙f瀽鍣�
+     * condition锛氭寚瀹氱鍚堟潯浠剁殑鎯呭喌涓嬫墠缂撳瓨锛�
+     * unless锛氬惁瀹氱紦瀛橈紱褰搖nless鎸囧畾鐨勬潯浠朵负true锛屾柟娉曠殑杩斿洖鍊煎氨涓嶄細琚紦瀛橈紱鍙互鑾峰彇鍒扮粨鏋滆繘琛屽垽鏂�
+     * sync锛氭槸鍚︿娇鐢ㄥ紓姝ユā寮�
+     */
+    @ApiOperation("0-鑾峰彇鍏挜")
+//    @Cacheable(cacheNames="api",value="cachespace=30", key = "#root.methodName")
+    @GetMapping("/get-public-key")
+    public Object getPublicKey() {
+        return projectRelatedService.getPublicKey();
+    }
+
+    /**
+     * 鐧诲綍瀹炰綋搴�
+     */
+    @ApiOperation("1-鐧诲綍瀹炰綋搴�")
+//    @Cacheable(cacheNames = "api", key = "#loginParams")
+    @PostMapping("/login-entity")
+    public R<Object> loginEntity(@RequestBody LoginParams loginParams) {
+        return success(projectRelatedService.loginEntity(loginParams));
+    }
+
+
+    /**
+     * 鑾峰彇璁块棶瀹炰綋搴撶殑token
+     */
+    @ApiOperation("1-鑾峰彇璁块棶瀹炰綋搴撶殑token")
+    @GetMapping("/entity-public-key")
+    public R<Object> getEntityPublicKey() {
+        return success(projectRelatedService.getEntityPublicKey());
+    }
+
+
+    /**
+     * 鑾峰彇璁块棶瀹炰綋搴撴暟鎹簱鍒楄〃
+     */
+    @ApiOperation("2-鑾峰彇璁块棶瀹炰綋搴撴暟鎹簱鍒楄〃")
+    @GetMapping("/db-list")
+    public R<Object> getDbLits() {
+        return success(projectRelatedService.getDbLits());
+    }
+
+    /**
+     * 鏌ヨ瀹炰綋搴撲笉鍚岀被鍨嬬殑淇℃伅
+     */
+    @ApiOperation("3-鏌ヨ瀹炰綋搴撲笉鍚岀被鍨嬬殑淇℃伅")
+    @GetMapping("/entity-type-info")
+    public Object getEntityTypeInfo(EntityTypeInfo entityTypeInfo) {
+        return projectRelatedService.getEntityTypeInfo(entityTypeInfo);
+    }
+
+
+}
diff --git a/src/main/java/com/se/simu/domain/EntityDataBase.java b/src/main/java/com/se/simu/domain/EntityDataBase.java
new file mode 100644
index 0000000..c042563
--- /dev/null
+++ b/src/main/java/com/se/simu/domain/EntityDataBase.java
@@ -0,0 +1,38 @@
+package com.se.simu.domain;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 瀹炰綋鏁版嵁搴�
+ *
+ * @author xingjinshuang
+ * @date 2024/07/04
+ */
+@Data
+@ApiModel(value = "EntityDataBase", description = "瀹炰綋鏁版嵁搴撶浉鍏冲唴瀹�")
+public class EntityDataBase implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛鍚�
+     */
+    @ApiModelProperty("鐢ㄦ埛鍚�")
+    private String userName;
+
+    /**
+     * 鐢ㄦ埛瀵嗙爜
+     */
+    @ApiModelProperty("鐢ㄦ埛瀵嗙爜")
+    private String userPassword;
+
+    /**
+     * 鏁版嵁搴撳悕
+     */
+    @ApiModelProperty("鏁版嵁搴撳悕")
+    private String databaseName;
+
+}
diff --git a/src/main/java/com/se/simu/domain/EntityTypeInfo.java b/src/main/java/com/se/simu/domain/EntityTypeInfo.java
new file mode 100644
index 0000000..41ca4ad
--- /dev/null
+++ b/src/main/java/com/se/simu/domain/EntityTypeInfo.java
@@ -0,0 +1,30 @@
+package com.se.simu.domain;
+
+import io.swagger.annotations.ApiModel;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+@ApiModel(value = "EntityTypeInfo", description = "瀹炰綋搴撲笉鍚岀被鍨嬬殑淇℃伅")
+public class EntityTypeInfo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String token;
+
+    private Integer start;
+
+    private boolean containCount;
+
+    private Integer count;
+
+    private String dbid;
+
+    private String layerid;
+
+    private String like;
+
+    private String querytype;
+
+}
diff --git a/src/main/java/com/se/simu/domain/LoginParams.java b/src/main/java/com/se/simu/domain/LoginParams.java
new file mode 100644
index 0000000..d0e20ee
--- /dev/null
+++ b/src/main/java/com/se/simu/domain/LoginParams.java
@@ -0,0 +1,17 @@
+package com.se.simu.domain;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class LoginParams implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    // 鐢ㄦ埛鍚�
+    private String userid;
+    // 瀵嗙爜
+    private String password;
+
+}
diff --git a/src/main/java/com/se/simu/service/Impl/ProjectRelatedServiceImpl.java b/src/main/java/com/se/simu/service/Impl/ProjectRelatedServiceImpl.java
new file mode 100644
index 0000000..f288420
--- /dev/null
+++ b/src/main/java/com/se/simu/service/Impl/ProjectRelatedServiceImpl.java
@@ -0,0 +1,337 @@
+package com.se.simu.service.Impl;
+
+import cn.hutool.crypto.SecureUtil;
+import cn.hutool.crypto.asymmetric.AsymmetricAlgorithm;
+import cn.hutool.crypto.asymmetric.AsymmetricCrypto;
+import cn.hutool.crypto.asymmetric.KeyType;
+import cn.hutool.crypto.asymmetric.RSA;
+import com.alibaba.fastjson.JSONObject;
+import com.se.simu.constant.CacheConstants;
+import com.se.simu.constant.RedisCache;
+import com.se.simu.domain.EntityTypeInfo;
+import com.se.simu.domain.LoginParams;
+import com.se.simu.service.ProjectRelatedService;
+import com.se.simu.utils.CustomWebClient;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.Resource;
+import java.security.KeyPair;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.HashMap;
+import java.util.Objects;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+@Slf4j
+@Service
+public class ProjectRelatedServiceImpl implements ProjectRelatedService {
+
+    @Resource
+    private RedisCache redisCache;
+
+    @Resource
+    public RedisTemplate redisTemplate;
+
+
+    // 鍏挜鍦板潃
+    @Value(value = "${app-server.publicKeyUrl}")
+    private String publicKeyUrl;
+    // devops 鐧诲綍鍦板潃
+    @Value(value = "${app-server.loginUrl}")
+    private String loginUrl;
+    @Value(value = "${app-server.getDbUrl}")
+    private String getDbUrl;
+
+    // 鏌ヨ鍦板潃
+    @Value(value = "${app-server.queryUrl}")
+    private String queryUrl;
+
+
+    /**
+     * 鑾峰彇鍏挜
+     *
+     * @return {@link Object}
+     */
+    @Override
+    public Object getPublicKey() {
+        HashMap<String, String> headers = new HashMap<>();
+        headers.put("Content-Type", "application/json");
+        CompletableFuture<String> postResponse = CustomWebClient.postAsFuture(publicKeyUrl, "", headers, String.class);
+        // 寮傛澶勭悊鍝嶅簲
+        postResponse.thenAccept(response -> {
+            log.info("response: {}", response);
+            if (response.contains("code")) {
+                try {
+                    JSONObject postResponseJson = JSONObject.parseObject(response);
+                    int statusCode = postResponseJson.getIntValue("code");
+                    log.info("statusCode = " + statusCode);
+                    String data = postResponseJson.getString("data");
+                    // 缂撳瓨data,骞惰缃�1灏忔椂鏈夋晥鏈�
+                    redisCache.deleteObject(CacheConstants.USER_CACHE_KEY + "rsa_data_set");
+                    redisCache.setCacheObject(CacheConstants.USER_CACHE_KEY + "rsa_data_set", data, 1, TimeUnit.HOURS);
+                    log.info("publicKey = " + data);
+                } catch (Exception e) {
+                    log.info("Failed to parse JSON: " + e.getMessage());
+                }
+            } else {
+                log.info("No 'code' field in the response: " + response);
+            }
+        });
+        return JSONObject.parseObject(postResponse.join());
+    }
+
+    /**
+     * 鐧诲綍瀹炰綋
+     *
+     * @param loginParams 鐧诲綍鍙傛暟
+     * @return {@link String}
+     */
+    @Override
+    public Object loginEntity(LoginParams loginParams) {
+        // 鍒ゆ柇redis涓紦瀛樻槸鍚﹀瓨鍦紙杩囨湡锛�
+        Boolean isExists = redisCache.hasKey(CacheConstants.USER_CACHE_KEY + "entity_db_response");
+        if (isExists) {
+            return JSONObject.parseObject(redisCache.getCacheObject(CacheConstants.USER_CACHE_KEY + "entity_db_response"));
+        }
+        // 璁剧疆璇锋眰浣�
+        // 鑾峰彇绉侀挜鍜屽叕閽ワ紝闀垮害蹇呴』鏄�16銆�24鎴�32
+        String publicKey = redisCache.getCacheObject(CacheConstants.USER_CACHE_KEY + "rsa_data_set");
+        // 鍋囪浠嶳edis涓幏鍙栧埌鐢ㄦ埛鍚�,鍒ゆ柇
+        if (!StringUtils.isNotBlank(publicKey)) {
+            // 缂撳瓨涓病鏈夌敤鎴峰悕,鍒欒繘琛岀櫥褰�
+            getPublicKey();
+            log.info("璋冪敤浜嗙櫥褰曡幏鍙栫敤鎴峰悕鏂规硶 $= ");
+        }
+        // 闃叉涓荤嚎绋嬫彁鍓嶇粨鏉�
+        try {
+            // 绛夊緟寮傛璇锋眰瀹屾垚
+            Thread.sleep(500);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        publicKey = redisCache.getCacheObject(CacheConstants.USER_CACHE_KEY + "rsa_data_set");
+        log.info("publicKey = " + publicKey);
+        // 鍏挜鍔犲瘑
+        AsymmetricCrypto rsa = SecureUtil.rsa(null, publicKey);
+        String encrypt = rsa.encryptBase64(loginParams.getPassword(), KeyType.PublicKey);
+        // 璁剧疆鍔犲瘑鍚庣殑瀵嗙爜
+        loginParams.setPassword(encrypt);
+        // 灏唋oginParams瀹炰綋杞垚JSON瀛楃涓�
+//        String json = JSON.toJSONString(loginParams);
+//        log.info("json = " + json);
+        // 鍙戦�佺櫥褰曡姹�
+        Mono<String> postResponse = CustomWebClient.postAsMono(loginUrl, loginParams, String.class);
+        // 鐢ㄤ簬淇濆瓨鍝嶅簲鏁版嵁
+        AtomicReference<String> responseData = new AtomicReference<>();
+        postResponse.subscribe(response -> {
+            // 灏嗗搷搴旀暟鎹繚瀛樺埌鍙橀噺涓�
+            responseData.set(response);
+            String code = JSONObject.parseObject(response).getString("code");
+            // 濡傛灉code鏄�200鍒欑櫥褰曟垚鍔�
+            if (code.equals("200")) {
+                // 鐧诲綍鎴愬姛鍚�,鑾峰彇data
+                String data = JSONObject.parseObject(response).getString("data");
+                String token = JSONObject.parseObject(data).getString("token");
+                // 璁剧疆data鍒癛edis涓�
+                redisCache.deleteObject(CacheConstants.USER_CACHE_KEY + "entity_db_response");
+                redisCache.setCacheObject(CacheConstants.USER_CACHE_KEY + "entity_db_response", response, 1, TimeUnit.HOURS);
+                // 璁剧疆data鍒癛edis涓�
+                redisCache.deleteObject(CacheConstants.USER_CACHE_KEY + "entity_db_token");
+                redisCache.setCacheObject(CacheConstants.USER_CACHE_KEY + "entity_db_token", token, 1, TimeUnit.HOURS);
+            } else {
+                // 鐧诲綍澶辫触
+                log.error("鐧诲綍澶辫触 $= " + response);
+            }
+        });
+        // 闃叉涓荤嚎绋嬫彁鍓嶇粨鏉�
+        try {
+            postResponse.toFuture().get(); // 闃诲绛夊緟璁㈤槄鎿嶄綔瀹屾垚
+            // 绛夊緟寮傛璇锋眰瀹屾垚
+            Thread.sleep(1000);
+        } catch (InterruptedException | ExecutionException e) {
+            e.printStackTrace();
+        }
+        // 杩斿洖token
+        return JSONObject.parseObject(responseData.get());
+    }
+
+    /**
+     * 鑷畾涔夊瘑閽ョ敓鎴愬姞瀵嗘暟鎹�
+     *
+     * @param data      鏁版嵁
+     * @param publicKey 鍏挜
+     * @return {@link String}
+     */
+    private static String customKeysGenerateEncryptedData(String data, String publicKey) {
+        AsymmetricCrypto rsa = SecureUtil.rsa(null, publicKey);
+        String encrypt = rsa.encryptBase64(data, KeyType.PublicKey);
+        System.out.println("encrypt = " + encrypt);
+        return encrypt;
+    }
+
+    /**
+     * 鑷畾涔� RSAgenerate 鍔犲瘑鏁版嵁0
+     */
+    private static void customRSAGenerateEncryptedData0() {
+        RSA rsa = new RSA();
+        // 鑾峰彇鍏挜鍜岀閽�
+        System.out.println(rsa.getPublicKey());
+        System.out.println(rsa.getPrivateKeyBase64());
+        System.out.println(rsa.getPrivateKey());
+        System.out.println(rsa.getPrivateKeyBase64());
+        // 绉侀挜鍔犲瘑,鍏挜瑙e瘑
+        System.out.println(new String(rsa.encrypt("testaa", KeyType.PrivateKey)));
+        System.out.println(new String(rsa.decrypt(rsa.encrypt("testaa", KeyType.PrivateKey), KeyType.PublicKey)));
+        // 鍏挜鍔犲瘑,绉侀挜瑙e瘑
+        System.out.println(new String(rsa.encrypt("testaa", KeyType.PublicKey)));
+        System.out.println(new String(rsa.decrypt(rsa.encrypt("testaa", KeyType.PublicKey), KeyType.PrivateKey)));
+    }
+
+    /**
+     * 鑷畾涔� RSAgenerate 鍔犲瘑鏁版嵁1
+     */
+    private static void customRSAGenerateEncryptedData1() {
+        KeyPair keyPair = SecureUtil.generateKeyPair(AsymmetricAlgorithm.RSA.getValue());
+        PrivateKey privateKey = keyPair.getPrivate();
+        PublicKey publicKey = keyPair.getPublic();
+        System.out.println(publicKey);
+        System.out.println(privateKey);
+        System.out.println("----------");
+
+        RSA rsa = new RSA(privateKey, publicKey);
+        // 绉侀挜鍔犲瘑,鍏挜瑙e瘑
+        System.out.println(new String(rsa.encrypt("testaa", KeyType.PrivateKey)));
+        System.out.println(new String(rsa.decrypt(rsa.encrypt("testaa", KeyType.PrivateKey), KeyType.PublicKey)));
+        // 鍏挜鍔犲瘑,绉侀挜瑙e瘑
+        System.out.println(new String(rsa.encrypt("testaa", KeyType.PublicKey)));
+        System.out.println(new String(rsa.decrypt(rsa.encrypt("testaa", KeyType.PublicKey), KeyType.PrivateKey)));
+
+    }
+
+
+    /**
+     * 鑾峰彇璁块棶瀹炰綋搴撶殑token
+     *
+     * @return {@link Object}
+     */
+    @Override
+    public Object getEntityPublicKey() {
+        // 鍒ゆ柇redis涓紦瀛樻槸鍚﹀瓨鍦紙杩囨湡锛�
+        Boolean isExists = redisCache.hasKey(CacheConstants.USER_CACHE_KEY + "EntityPublicKey");
+        if (isExists) {
+            return JSONObject.parseObject(redisCache.getCacheObject(CacheConstants.USER_CACHE_KEY + "EntityPublicKey"));
+        }
+        HashMap<String, String> headers = new HashMap<>();
+        headers.put("Content-Type", "application/json");
+        CompletableFuture<String> postResponse = CustomWebClient.postAsFuture(queryUrl, "", headers, String.class);
+        // 寮傛澶勭悊鍝嶅簲
+        postResponse.thenAccept(response -> {
+            log.info("response: {}", response);
+            if (response.contains("code")) {
+                try {
+                    JSONObject postResponseJson = JSONObject.parseObject(response);
+                    int statusCode = postResponseJson.getIntValue("code");
+                    log.info("statusCode = " + statusCode);
+                    String data = postResponseJson.getString("data");
+                    // 缂撳瓨data,骞惰缃�1灏忔椂鏈夋晥鏈�
+                    redisCache.deleteObject(CacheConstants.USER_CACHE_KEY + "EntityPublicKey");
+                    redisCache.setCacheObject(CacheConstants.USER_CACHE_KEY + "EntityPublicKey", response, 1, TimeUnit.HOURS);
+                    log.info("EntityPublicKey = " + data);
+                } catch (Exception e) {
+                    log.info("Failed to parse JSON: " + e.getMessage());
+                }
+            } else {
+                log.info("No 'code' field in the response: " + response);
+            }
+        });
+        return JSONObject.parseObject(postResponse.join());
+    }
+
+
+    /**
+     * 鑾峰彇璁块棶瀹炰綋搴撶殑token
+     *
+     * @return {@link Object}
+     */
+    @Override
+    public Object getDbLits() {
+        HashMap<String, String> headers = new HashMap<>();
+        headers.put("Content-Type", "application/json");
+        String token = redisCache.getCacheObject(CacheConstants.USER_CACHE_KEY + "entity_db_token");
+        log.info("token = " + token);
+        // 娣诲姞form鍙傛暟
+        HashMap<String, Object> params = new HashMap<>();
+        params.put("token", token);
+
+        CompletableFuture<String> postResponse = CustomWebClient.postAsFuture(getDbUrl, params, headers, String.class);
+        // 寮傛澶勭悊鍝嶅簲
+        postResponse.thenAccept(response -> {
+            log.info("response: {}", response);
+            if (response.contains("code")) {
+                try {
+                    JSONObject postResponseJson = JSONObject.parseObject(response);
+                    int statusCode = postResponseJson.getIntValue("code");
+                    log.info("statusCode = " + statusCode);
+                    String data = postResponseJson.getString("data");
+                    // 缂撳瓨data,骞惰缃�1灏忔椂鏈夋晥鏈�
+                    redisCache.deleteObject(CacheConstants.USER_CACHE_KEY + "EntityDbNameList");
+                    redisCache.setCacheObject(CacheConstants.USER_CACHE_KEY + "EntityDbNameList", response, 1, TimeUnit.HOURS);
+                    log.info("EntityDbNameList = " + data);
+                } catch (Exception e) {
+                    log.info("Failed to parse JSON: " + e.getMessage());
+                }
+            } else {
+                log.info("No 'code' field in the response: " + response);
+            }
+        });
+        return JSONObject.parseObject(postResponse.join());
+    }
+
+    @Override
+    public Object getEntityTypeInfo(EntityTypeInfo entityTypeInfo) {
+        HashMap<String, String> headers = new HashMap<>();
+        headers.put("Content-Type", "application/json");
+        String token = redisCache.getCacheObject(CacheConstants.USER_CACHE_KEY + "entity_db_token");
+        log.info("token = " + token);
+        // 娣诲姞form鍙傛暟
+        HashMap<String, Object> params = new HashMap<>();
+        params.put("token", token);
+        params.put("start", Objects.nonNull(entityTypeInfo.getStart()) ? entityTypeInfo.getStart() : 1);
+        params.put("containCount", true);
+        params.put("count", Objects.nonNull(entityTypeInfo.getCount()) ? entityTypeInfo.getCount() : 20);
+        params.put("dbid", Objects.nonNull(entityTypeInfo.getDbid()) ? entityTypeInfo.getDbid() : "85257774fdb64e5f99f6778696cad02a");
+        params.put("layerid", "f6ff4412-4886-4c4b-83f7-13de24ee8353");
+        params.put("like", "");
+        params.put("querytype", "entity");
+
+        CompletableFuture<String> postResponse = CustomWebClient.postAsFuture(queryUrl, params, headers, String.class);
+        // 寮傛澶勭悊鍝嶅簲
+        postResponse.thenAccept(response -> {
+            log.info("response: {}", response);
+            if (response.contains("code")) {
+                try {
+                    JSONObject postResponseJson = JSONObject.parseObject(response);
+                    int statusCode = postResponseJson.getIntValue("code");
+                    log.info("statusCode = " + statusCode);
+                    String data = postResponseJson.getString("data");
+                    log.info("getEntityTypeInfo = " + data);
+                } catch (Exception e) {
+                    log.info("Failed to parse JSON: " + e.getMessage());
+                }
+            } else {
+                log.info("No 'code' field in the response: " + response);
+            }
+        });
+        return JSONObject.parseObject(postResponse.join());
+    }
+
+
+}
diff --git a/src/main/java/com/se/simu/service/ProjectRelatedService.java b/src/main/java/com/se/simu/service/ProjectRelatedService.java
new file mode 100644
index 0000000..2bca4ef
--- /dev/null
+++ b/src/main/java/com/se/simu/service/ProjectRelatedService.java
@@ -0,0 +1,33 @@
+package com.se.simu.service;
+
+import com.se.simu.domain.EntityTypeInfo;
+import com.se.simu.domain.LoginParams;
+
+public interface ProjectRelatedService {
+
+    /**
+     * 鑾峰彇鍏挜
+     *
+     * @return {@link String}
+     */
+    Object getPublicKey();
+
+    /**
+     * 鐧诲綍瀹炰綋
+     *
+     * @param loginParams 鐧诲綍鍙傛暟
+     * @return {@link String}
+     */
+    Object loginEntity(LoginParams loginParams);
+
+    /**
+     * 鑾峰彇璁块棶瀹炰綋搴撶殑token
+     *
+     * @return {@link Object}
+     */
+    Object getEntityPublicKey();
+
+    Object getDbLits();
+
+    Object getEntityTypeInfo(EntityTypeInfo entityTypeInfo);
+}
diff --git a/src/main/java/com/se/simu/utils/CustomWebClient.java b/src/main/java/com/se/simu/utils/CustomWebClient.java
new file mode 100644
index 0000000..2681e3e
--- /dev/null
+++ b/src/main/java/com/se/simu/utils/CustomWebClient.java
@@ -0,0 +1,500 @@
+package com.se.simu.utils;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.client.WebClient;
+import reactor.core.publisher.Mono;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * 鑷畾涔� Web 瀹㈡埛绔�
+ *
+ * @author xingjinshuang@smartearth.cn
+ * @date 2024/06/27
+ */
+public class CustomWebClient {
+
+    private static final Logger logger = LoggerFactory.getLogger(CustomWebClient.class);
+
+
+    private static final WebClient webClient;
+
+    static {
+        // 鍦ㄩ潤鎬佷唬鐮佸潡涓疄渚嬪寲WebClient.Builder骞舵瀯寤篧ebClient瀵硅薄
+        webClient = WebClient.builder().build();
+    }
+
+    //====鍩虹璇锋眰=====================================================================================================================================
+    public static Mono<String> get(String url) {
+        return webClient.get()
+                .uri(url)
+                .retrieve()
+                .bodyToMono(String.class);
+    }
+
+    public static Mono<String> post(String url, Object requestBody) {
+        return webClient.post()
+                .uri(url)
+                .bodyValue(requestBody)
+                .retrieve()
+                .bodyToMono(String.class);
+    }
+
+    public static Mono<String> postForm(String url, MultiValueMap<String, String> formData) {
+        return webClient.post()
+                .uri(url)
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .body(BodyInserters.fromFormData(formData))
+                .retrieve()
+                .bodyToMono(String.class);
+    }
+
+    public static Mono<String> put(String url, Object requestBody) {
+        return webClient.put()
+                .uri(url)
+                .bodyValue(requestBody)
+                .retrieve()
+                .bodyToMono(String.class);
+    }
+
+    // 鍙戦�丳UT璇锋眰
+    public static <T, R> Mono<T> put(String url, R requestBody, Class<T> responseType) {
+        return webClient.put()
+                .uri(url)
+                .contentType(MediaType.APPLICATION_JSON)
+                .body(BodyInserters.fromValue(requestBody))
+                .retrieve()
+                .bodyToMono(responseType);
+    }
+
+    public static Mono<String> delete(String url) {
+        return webClient.delete()
+                .uri(url)
+                .retrieve()
+                .onStatus(HttpStatus::is4xxClientError,
+                        clientResponse -> Mono.error(new CustomWebClientException1("Client error: " + clientResponse.statusCode())))
+                .onStatus(HttpStatus::is5xxServerError,
+                        clientResponse -> Mono.error(new CustomWebClientException1("Server error: " + clientResponse.statusCode())))
+                .bodyToMono(String.class);
+    }
+
+    //=======鑷畾涔夎繑鍥炵被鍨嬬殑璇锋眰===================================================================================================================================
+    public static <T> Mono<T> getAndParse(String url, Class<T> responseType) {
+        return webClient.get()
+                .uri(url)
+                .accept(MediaType.APPLICATION_JSON)
+                .retrieve()
+                .bodyToMono(responseType);
+    }
+
+    public static <T, R> Mono<T> postAndParse(String url, R requestBody, Class<T> responseType) {
+        return webClient.post()
+                .uri(url)
+                .contentType(MediaType.APPLICATION_JSON)
+                .body(BodyInserters.fromValue(requestBody))
+                .retrieve()
+                .bodyToMono(responseType);
+    }
+
+    /**
+     * toBodilessEntity涓嬭浇鎴栬�呭垹闄ょ殑鏃跺�欎笉闇�瑕佸鍝嶅簲浣撳鐞嗙殑
+     * toBodilessEntity() 鏄� Java Play Framework 涓� WebClient 绫荤殑涓�涓柟娉曪紝瀹冪敤浜庡皢鍝嶅簲杞崲涓烘病鏈変綋鐨勫搷搴斿疄浣撱��
+     * 閫氬父锛屾垜浠湪澶勭悊涓嶉渶瑕佽鍙栧搷搴斾綋鐨勫ぇ鍨嬩笅杞芥椂锛屽彲浠ヤ娇鐢ㄨ繖涓柟娉曟潵閬垮厤涓嶅繀瑕佺殑鍐呭瓨鍗犵敤銆�
+     */
+    public static Mono<String> postAndReceiveLocation(String url, Object requestBody) {
+        return webClient.post()
+                .uri(url)
+                .bodyValue(requestBody)
+                .retrieve()
+                .toBodilessEntity()
+                .flatMap(response -> {
+                    if (response.getHeaders().getLocation() != null) {
+                        return Mono.just(response.getHeaders().getLocation().toString());
+                    } else {
+                        // 濡傛灉Location涓虹┖锛岃繑鍥瀝esponse
+                        return Mono.just(response.getStatusCode().toString());
+                    }
+                });
+    }
+
+    public static Mono<String> postFormAndReceiveLocation(String url, MultiValueMap<String, String> formData) {
+        return webClient.post()
+                .uri(url)
+                .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                .body(BodyInserters.fromFormData(formData))
+                .retrieve()
+                .toBodilessEntity()
+                .flatMap(response -> {
+                    if (response.getHeaders().getLocation() != null) {
+                        return Mono.just(response.getHeaders().getLocation().toString());
+                    } else {
+                        // 濡傛灉Location涓虹┖锛岃繑鍥瀝esponse鐨勭姸鎬佺爜
+                        return Mono.just(response.getStatusCode().toString());
+                    }
+                });
+    }
+
+
+    //==========================================================================================================================================
+    // 寮傛璇锋眰鐨凣ET銆丳OST鏂瑰紡
+    public static <T> Mono<T> getAsMono(String path, Class<T> responseType) {
+        return webClient.get()
+                .uri(path)
+                .accept(MediaType.APPLICATION_JSON)
+                .retrieve()
+                .bodyToMono(responseType);
+    }
+
+    public static <T> Mono<T> postAsMono(String path, Object requestBody, Class<T> responseType) {
+        return webClient.post()
+                .uri(path)
+                .contentType(MediaType.APPLICATION_JSON)
+                .body(Mono.just(requestBody), requestBody.getClass())
+                .retrieve()
+                .bodyToMono(responseType);
+    }
+
+    public static <T> CompletableFuture<T> getAsFuture(String path, Class<T> responseType) {
+        return webClient
+                .method(HttpMethod.GET)
+                .uri(path)
+                .accept(MediaType.APPLICATION_JSON)
+                .retrieve()
+                .bodyToMono(responseType)
+                .toFuture();
+    }
+
+    public static <T> CompletableFuture<T> postAsFuture(String path, Object requestBody, HashMap<String, String> headers, Class<T> responseType) {
+        return webClient
+                .method(HttpMethod.POST)
+                .uri(path)
+                .contentType(MediaType.APPLICATION_JSON)
+                .headers(h -> headers.forEach(h::add))
+                .bodyValue(requestBody)
+                .retrieve()
+                .bodyToMono(responseType)
+                .toFuture();
+    }
+
+
+    //==========================================================================================================================================
+    // 鍏朵粬鏂瑰紡涓�鍙戣捣璇锋眰
+    private static final WebClient WEB_CLIENT = WebClient.create();
+
+    /**
+     * 鍙戣捣GET璇锋眰锛屾敮鎸丟et parameter
+     */
+    public static CompletableFuture<String> getParam(String url, HttpHeaders headers, MultiValueMap<String, String> queryParams) {
+        return Mono.from(WEB_CLIENT.get()
+                        .uri(uriBuilder -> uriBuilder
+                                .path(url)
+                                .queryParams(queryParams)
+                                .build())
+                        .headers(httpHeaders -> httpHeaders.putAll(headers))
+                        //.headers(h -> headers.forEach(h::add))
+                        .retrieve()
+                        .onStatus(HttpStatus::isError, clientResponse -> Mono.error(new RuntimeException("HTTP error status: " + clientResponse.statusCode())))
+                        .bodyToMono(String.class))
+                .onErrorResume(error -> Mono.just("Error: " + error.getMessage())) // 濡傛灉鏈夐敊璇紝杩斿洖閿欒淇℃伅
+                .toFuture();
+    }
+
+    /**
+     * 鍙戣捣GET璇锋眰锛屾敮鎸丟et parameter
+     * 鍙互鐢�
+     */
+    public static CompletableFuture<String> getNoParam(String url, HttpHeaders headers) {
+        return Mono.from(WEB_CLIENT.get()
+                        .uri(url)
+                        .headers(httpHeaders -> httpHeaders.putAll(headers))
+                        //.headers(h -> headers.forEach(h::add))
+                        .retrieve()
+                        .onStatus(HttpStatus::isError, clientResponse -> Mono.error(new RuntimeException("HTTP error status: " + clientResponse.statusCode())))
+                        .bodyToMono(String.class))
+                .onErrorResume(error -> Mono.just("Error: " + error.getMessage())) // 濡傛灉鏈夐敊璇紝杩斿洖閿欒淇℃伅
+                .toFuture();
+    }
+
+    /**
+     * 鍙戣捣POST璇锋眰锛屾敮鎸丣SON body
+     */
+    public static CompletableFuture<String> postJson(String url, Object body, HashMap<String, String> headers) {
+        return Mono.from(WEB_CLIENT.post()
+                        .uri(url)
+                        .contentType(MediaType.APPLICATION_JSON)
+                        .headers(h -> headers.forEach(h::add))
+                        .bodyValue(body)
+                        .retrieve()
+                        .onStatus(HttpStatus::isError, clientResponse -> Mono.error(new RuntimeException("HTTP error status: " + clientResponse.statusCode())))
+                        .bodyToMono(String.class))
+                .onErrorResume(error -> Mono.just("Error: " + error.getMessage())) // 濡傛灉鏈夐敊璇紝杩斿洖閿欒淇℃伅
+                .toFuture();
+    }
+
+    /**
+     * 鍙戣捣POST璇锋眰锛屾敮鎸佽〃鍗曟暟鎹�
+     */
+    public static CompletableFuture<String> postForm(String url, MultiValueMap<String, String> formData, Map<String, String> headers) {
+        return Mono.from(WEB_CLIENT.post()
+                        .uri(url)
+                        .headers(h -> headers.forEach(h::add))
+                        .contentType(MediaType.APPLICATION_FORM_URLENCODED)
+                        .body(BodyInserters.fromFormData(formData))
+                        .retrieve()
+                        .bodyToMono(String.class))
+                .toFuture();
+    }
+
+    //=========================================================================================================================================
+    // 鍏朵粬璇锋眰鏂瑰紡浜�
+    public Mono<String> getRequest(String url, long timeoutSeconds, int retryCount) {
+        return executeRequest(url, HttpMethod.GET, null, HttpHeaders.EMPTY, timeoutSeconds, retryCount);
+    }
+
+    public Mono<String> postRequest(String url, Object requestBody, HttpHeaders headers, long timeoutSeconds, int retryCount) {
+        return executeRequest(url, HttpMethod.POST, requestBody, headers, timeoutSeconds, retryCount);
+    }
+
+    /**
+     * 鎵ц璇锋眰
+     *
+     * @param url            缃戝潃
+     * @param method         鏂规硶
+     * @param requestBody    璇锋眰姝f枃
+     * @param headers        澶�
+     * @param timeoutSeconds 瓒呮椂绉掓暟
+     * @param retryCount     閲嶈瘯璁℃暟
+     * @return {@link Mono}<{@link String}>
+     */
+    private Mono<String> executeRequest(String url, HttpMethod method, Object requestBody, HttpHeaders headers, long timeoutSeconds, int retryCount) {
+        return executeRequestInternal(url, method, requestBody, headers, timeoutSeconds, retryCount)
+                .onErrorResume(throwable -> {
+                    logger.error("Error during request: {}", throwable.getMessage());
+                    return Mono.error(throwable);
+                });
+    }
+
+    /**
+     * 鍐呴儴鎵ц璇锋眰
+     *
+     * @param url            缃戝潃
+     * @param method         鏂规硶
+     * @param requestBody    璇锋眰姝f枃
+     * @param headers        澶�
+     * @param timeoutSeconds 瓒呮椂绉掓暟
+     * @param retryCount     閲嶈瘯璁℃暟
+     * @return {@link Mono}<{@link String}>
+     */
+    private Mono<String> executeRequestInternal(String url, HttpMethod method, Object requestBody, HttpHeaders headers, long timeoutSeconds, int retryCount) {
+        return webClient.method(method)
+                .uri(url)
+                .headers(httpHeaders -> httpHeaders.addAll(headers))
+                .bodyValue(requestBody)
+                .retrieve()
+                .bodyToMono(String.class)
+                .timeout(Duration.ofSeconds(timeoutSeconds))
+                .doOnError(error -> logger.error("Error during request: {}", error))
+                .retry(retryCount);
+    }
+
+    //=========================================================================================================================================
+    // 鍏朵粬鍙傛暟
+
+    /**
+     * 浣跨敤瓒呮椂鑾峰彇
+     *
+     * @param url            绔偣
+     * @param timeoutSeconds 瓒呮椂绉掓暟
+     * @return {@link Mono}<{@link String}>
+     */
+    public Mono<String> getWithTimeout(String url, long timeoutSeconds) {
+        return webClient.get()
+                .uri(url)
+                .accept(MediaType.APPLICATION_JSON)
+                .retrieve()
+                .bodyToMono(String.class)
+                .timeout(Duration.ofSeconds(timeoutSeconds))
+                .onErrorMap(error -> new CustomWebClientException("Request timeout", error));
+    }
+
+    /**
+     * 甯︽爣棰樺笘瀛�
+     *
+     * @param url         绔偣
+     * @param requestBody 璇锋眰姝f枃
+     * @param headers     澶�
+     * @return {@link Mono}<{@link String}>
+     */
+    public Mono<String> postWithHeaders(String url, Object requestBody, HttpHeaders headers) {
+        return webClient.post()
+                .uri(url)
+                .bodyValue(requestBody)
+                .headers(httpHeaders -> httpHeaders.addAll(headers))
+                .retrieve()
+                .bodyToMono(String.class);
+    }
+
+    /**
+     * 鑾峰彇骞跺彂
+     *
+     * @param endpoint1 绔偣 1
+     * @param endpoint2 绔偣 2
+     * @return {@link Mono}<{@link String}>
+     */
+    public Mono<String> getConcurrently(String endpoint1, String endpoint2) {
+        Mono<String> result1 = webClient.get()
+                .uri(endpoint1)
+                .retrieve()
+                .bodyToMono(String.class);
+        Mono<String> result2 = webClient.get()
+                .uri(endpoint2)
+                .retrieve()
+                .bodyToMono(String.class);
+        return result1.zipWith(result2).map(tuple -> tuple.getT1() + tuple.getT2());
+    }
+    //==========================================================================================================================================
+
+    /**
+     * 鑷畾涔� Web 瀹㈡埛绔紓甯�
+     * Custom exception class for WebClient error handling
+     *
+     * @author xingjinshuang@smartearth.cn
+     * @date 2024/06/27
+     */
+    public static class CustomWebClientException1 extends RuntimeException {
+        public CustomWebClientException1(String message) {
+            super(message);
+        }
+    }
+
+    /**
+     * 鑷畾涔� Web 瀹㈡埛绔紓甯�
+     *
+     * @author xingjinshuang
+     * @date 2024/06/27
+     */
+    public static class CustomWebClientException extends RuntimeException {
+        public CustomWebClientException(String message, Throwable cause) {
+            super(message, cause);
+        }
+    }
+
+
+    /**
+     * 涓昏
+     *
+     * @param args 鍙傛暟
+     */
+    public static void main(String[] args) {
+        HashMap<String, String> headers = new HashMap<>();
+        headers.put("Content-Type", "application/json");
+
+        Mono<String> res = getAndParse("https://api.example.com/data", String.class);
+        res.subscribe(dataResponse -> {
+            // 澶勭悊鏁版嵁鍝嶅簲
+            System.out.println("Received data response: " + dataResponse);
+        });
+
+        Mono<String> res1 = get("https://api.example.com/textdata");
+        res1.subscribe(textData -> {
+            // 澶勭悊鏂囨湰鏁版嵁鍝嶅簲
+            System.out.println("Received text data: " + textData);
+        });
+
+        String requestBody00 = new String("test");
+        Mono<String> res2 = postAndReceiveLocation("https://api.example.com/resource", requestBody00);
+        res2.subscribe(location -> {
+            // 澶勭悊杩斿洖鐨勮祫婧愪綅缃�
+            System.out.println("Resource location: " + location);
+        });
+
+        MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
+        formData.add("key1", "value1");
+        formData.add("key2", "value2");
+        Mono<String> res3 = postFormAndReceiveLocation("https://api.example.com/formsubmit", formData);
+        res3.subscribe(location -> {
+            // 澶勭悊杩斿洖鐨勮〃鍗曟彁浜や綅缃�
+            System.out.println("Form submission location: " + location);
+        });
+
+
+        // 寮傛GET璇锋眰,閫氳繃subscribe鏂规硶鏉ュ鐞嗗搷搴�
+        Mono<String> asyncResponse0 = getAsMono("/api/resource", String.class);
+        // asyncResponse0.subscribe(System.out::println);
+        asyncResponse0.flatMap(response -> {
+            System.out.println("GET璇锋眰缁撴灉锛�" + response);
+            return Mono.just(response);
+        }).subscribe();
+
+        // 寮傛POST璇锋眰,閫氳繃subscribe鏂规硶鏉ュ鐞嗗搷搴�
+        String requestBody0 = new String("data");
+        Mono<String> asyncPostedResponse0 = postAsMono("/api/resource", requestBody0, String.class);
+        // asyncPostedResponse0.subscribe(System.out::println);
+        asyncPostedResponse0.flatMap(response -> {
+            System.out.println("POST璇锋眰缁撴灉锛�" + response);
+            return Mono.just(response);
+        }).subscribe();
+
+        // 寮傛GET璇锋眰锛屼笉浼氱洿鎺ヨ繑鍥炶繑鍥炰綋
+        CompletableFuture<String> asyncResponse = getAsFuture("/api/resource", String.class);
+        asyncResponse.thenAccept(response -> {
+            System.out.println("GET璇锋眰缁撴灉锛�" + response);
+        });
+
+        // 寮傛POST璇锋眰锛屼笉浼氱洿鎺ヨ繑鍥炶繑鍥炰綋
+        String requestBody = new String("data");
+        CompletableFuture<String> asyncPostedResponse = postAsFuture("/api/resource", requestBody, headers, String.class);
+        asyncPostedResponse.thenAccept(response -> {
+            System.out.println("POST璇锋眰缁撴灉锛�" + response);
+        });
+
+        // henAccept鏂规硶鏄竴涓秷璐瑰瀷鐨勬柟娉曪紝瀹冧笉浼氳繑鍥炰换浣曞�笺��
+        // 瑕佽幏鍙栧紓姝ヨ姹傜殑杩斿洖鍊硷紝鍙互浣跨敤thenApply鏂规硶锛岃繖涓柟娉曚細杩斿洖涓�涓柊鐨凜ompletableFuture瀵硅薄锛岄噷闈㈠寘鍚粡杩囧鐞嗗悗鐨勮繑鍥炲��
+        // 寮傛GET璇锋眰锛岃繑鍥炶繑鍥炰綋
+        CompletableFuture<String> asyncResponseRes = getAsFuture("/api/resource", String.class);
+        asyncResponse.thenApply(response -> {
+            System.out.println("GET璇锋眰缁撴灉锛�" + response);
+            return response;
+        });
+
+        // henAccept鏂规硶鏄竴涓秷璐瑰瀷鐨勬柟娉曪紝瀹冧笉浼氳繑鍥炰换浣曞�笺��
+        // 瑕佽幏鍙栧紓姝ヨ姹傜殑杩斿洖鍊硷紝鍙互浣跨敤thenApply鏂规硶锛岃繖涓柟娉曚細杩斿洖涓�涓柊鐨凜ompletableFuture瀵硅薄锛岄噷闈㈠寘鍚粡杩囧鐞嗗悗鐨勮繑鍥炲��
+        // 寮傛POST璇锋眰锛岃繑鍥炶繑鍥炰綋
+        String requestBody1 = new String("data");
+        CompletableFuture<String> asyncPostedResponseRes = postAsFuture("/api/resource", requestBody1, headers, String.class);
+        asyncPostedResponse.thenApply(response -> {
+            System.out.println("POST璇锋眰缁撴灉锛�" + response);
+            return response;
+        });
+
+        // 鍚屾鏂瑰紡涓嬭幏鍙栧搷搴斾綋锛屽彲浠ヤ娇鐢╦oin鏂规硶鏉ョ瓑寰呭紓姝ユ搷浣滅殑瀹屾垚骞惰幏鍙栨渶缁堢殑缁撴灉銆傝繖鏍峰彲浠ョ‘淇濆湪鑾峰彇缁撴灉涔嬪墠闃诲褰撳墠绾跨▼锛岀洿鍒板紓姝ユ搷浣滃畬鎴愩��
+        // 浣跨敤join鏂规硶鏉ュ悓姝ヨ幏鍙栧搷搴斾綋锛�
+        String requestBody2 = new String("data");
+        CompletableFuture<String> asyncPostedResponse2 = CustomWebClient.postAsFuture("/api/resource", requestBody2, headers, String.class);
+        asyncPostedResponse2.thenAccept(response -> {
+            System.out.println("POST璇锋眰缁撴灉锛�" + response);
+        });
+        String syncResponse = asyncPostedResponse2.join();
+        System.out.println("鍚屾鑾峰彇鐨勫搷搴斾綋锛�" + syncResponse);
+
+        // 闃叉涓荤嚎绋嬫彁鍓嶇粨鏉�
+        try {
+            // 绛夊緟寮傛璇锋眰瀹屾垚
+            Thread.sleep(5000);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+}
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
index 4e2a0ea..57b10f2 100644
--- a/src/main/resources/application-prod.yml
+++ b/src/main/resources/application-prod.yml
@@ -91,6 +91,22 @@
   connectTimeout: -1
   readTimeout: -1
 
+
+
+# 椤圭洰瀹炰綋搴撴湇鍔′腑閰嶇疆
+app-server:
+  # 鍏挜鍦板潃
+  publicKeyUrl: http://106.120.22.26:8024/account-service/security/publickey
+  # 鐧诲綍鍦板潃
+  loginUrl: http://106.120.22.26:8024/account-service/security/login
+  # 鏌ヨ鏁版嵁搴撳湴鍧�
+  getDbUrl: http://106.120.22.26:8024/geo-service/entitydb/list/canview
+  # 鏌ヨ涓嶅悓鏁版嵁搴撶被鍨嬩笅鐨勬暟鎹湴鍧�
+  queryUrl: http://106.120.22.26:8024/geo-service/entitydbdata/layer/query
+
+
+
+
 config:
   ver: 0.2
   cacheTime: 60
diff --git a/src/main/resources/application-zyy.yml b/src/main/resources/application-zyy.yml
index 18adee8..28935e9 100644
--- a/src/main/resources/application-zyy.yml
+++ b/src/main/resources/application-zyy.yml
@@ -91,6 +91,19 @@
   connectTimeout: -1
   readTimeout: -1
 
+# 椤圭洰瀹炰綋搴撴湇鍔′腑閰嶇疆
+app-server:
+  # 鍏挜鍦板潃
+  publicKeyUrl: http://106.120.22.26:8024/account-service/security/publickey
+  # 鐧诲綍鍦板潃
+  loginUrl: http://106.120.22.26:8024/account-service/security/login
+  # 鏌ヨ鏁版嵁搴撳湴鍧�
+  getDbUrl: http://106.120.22.26:8024/geo-service/entitydb/list/canview
+  # 鏌ヨ涓嶅悓鏁版嵁搴撶被鍨嬩笅鐨勬暟鎹湴鍧�
+  queryUrl: http://106.120.22.26:8024/geo-service/entitydbdata/layer/query
+
+
+
 config:
   ver: 0.2
   cacheTime: 60

--
Gitblit v1.9.3