#331 外贸公社

Merge realizado
wangfan mesclou 2 commits de wangfan/apc em wangfan/master há 6 dias atrás

+ 27 - 47
jeecg-module-system/jeecg-system-biz/src/main/java/org/jeecg/modules/adweb/dmp/controller/TradeSparqController.java

@@ -1,12 +1,13 @@
 package org.jeecg.modules.adweb.dmp.controller;
 
 import com.alibaba.fastjson.JSONObject;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
 
 import jakarta.servlet.http.HttpServletRequest;
 
 import lombok.extern.slf4j.Slf4j;
 
-import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.tuple.Pair;
 import org.apache.shiro.SecurityUtils;
 import org.jeecg.common.api.vo.Result;
@@ -24,7 +25,8 @@ import org.springframework.web.client.RestClientResponseException;
 import org.springframework.web.client.RestTemplate;
 
 import java.util.Objects;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 /**
@@ -52,24 +54,25 @@ public class TradeSparqController {
 
     @Autowired private AdwebRedisUtil adwebRedisUtil;
 
-    private RestTemplate restTemplate = new RestTemplate();
+    @Autowired private RestTemplate restTemplate;
 
-    // 用户级加锁,确保TradeSparq API串行调用,准确控制额度
-    private final ConcurrentHashMap<String, Object> userLocks = new ConcurrentHashMap<>();
+    // 用户级加锁,确保TradeSparq API串行调用,准确控制用户额度
+    private final Cache<String, Object> userLocks =
+            CacheBuilder.newBuilder().expireAfterAccess(1, TimeUnit.HOURS).build();
 
     @PostMapping("/**")
     @ResponseBody
     public Result<JSONObject> forwardPost(
-            HttpServletRequest httpRequest, @RequestBody JSONObject requestBody) {
-        String uid = ((LoginUser) SecurityUtils.getSubject().getPrincipal()).getId();
-        if (StringUtils.isBlank(uid)) {
-            return Result.error("用户ID为空");
+            HttpServletRequest httpRequest, @RequestBody JSONObject requestBody)
+            throws ExecutionException {
+        LoginUser loginUser = ((LoginUser) SecurityUtils.getSubject().getPrincipal());
+        if (Objects.isNull(loginUser)) {
+            return Result.error("用户信息未找到");
         }
 
         // 获取用户锁
-        Object userLock = userLocks.computeIfAbsent(uid, k -> new Object());
+        Object userLock = userLocks.get(loginUser.getId(), Object::new);
         synchronized (userLock) {
-            // 0. 检查Redis缓存
             String apiPath = httpRequest.getServletPath().split(BASE_PATH)[1]; // 获取TradeSparq API路径
             String sortedParams =
                     requestBody.keySet().stream()
@@ -77,6 +80,7 @@ public class TradeSparqController {
                             .map(key -> FastJsonUtil.toJSONString(requestBody.get(key)))
                             .collect(Collectors.joining());
 
+            // 0. 检查Redis缓存
             String redisKey =
                     String.format(
                             "tradesparq:%s:%s",
@@ -84,8 +88,9 @@ public class TradeSparqController {
             JSONObject cachedResult = (JSONObject) adwebRedisUtil.get(redisKey);
             if (Objects.nonNull(cachedResult)) {
                 log.info(
-                        "TradeSparq API返回Redis缓存数据,uid = {}, path = {}, request body = {}",
-                        uid,
+                        "TradeSparq返回Redis缓存数据,uid = {}, name = {}, path = {}, request body = {}",
+                        loginUser.getId(),
+                        loginUser.getUsername(),
                         apiPath,
                         requestBody);
                 return Result.ok(cachedResult);
@@ -95,9 +100,9 @@ public class TradeSparqController {
             boolean isQuotaLimited = this.isQuotaLimited(httpRequest, requestBody);
             if (isQuotaLimited) {
                 Pair<Integer, Integer> customsDataQuota =
-                        resourceQuotaService.getCustomsDataQuota(uid);
+                        resourceQuotaService.getCustomsDataQuota(loginUser.getId());
                 if (customsDataQuota.getLeft() <= customsDataQuota.getRight()) {
-                    log.warn("用户 {} 海关查询资源额度不足", uid);
+                    log.warn("用户 {} {} 海关查询资源额度不足", loginUser.getId(), loginUser.getUsername());
                     return Result.error(
                             String.format(
                                     "查询失败。用户资源额度为%d,已使用%d",
@@ -118,14 +123,15 @@ public class TradeSparqController {
                 ResponseEntity<JSONObject> responseEntity =
                         restTemplate.exchange(requestEntity, JSONObject.class);
                 log.info(
-                        "TradeSparq API调用成功,uid = {}, path = {}, request body = {}",
-                        uid,
+                        "TradeSparq API调用成功,uid = {}, name = {}, path = {}, request body = {}",
+                        loginUser.getId(),
+                        loginUser.getUsername(),
                         apiPath,
                         requestBody);
 
                 // 3.1 记录资源额度消耗
                 if (isQuotaLimited) {
-                    resourceQuotaService.consumeCustomsDataQuota(uid);
+                    resourceQuotaService.consumeCustomsDataQuota(loginUser.getId());
                 }
 
                 // 3.2 缓存到Redis,TTL为3小时
@@ -134,8 +140,9 @@ public class TradeSparqController {
                 return Result.ok(responseEntity.getBody());
             } catch (RestClientResponseException e) {
                 log.error(
-                        "TradeSparq API调用失败,uid = {}, path = {}, request body = {}",
-                        uid,
+                        "TradeSparq API调用失败,uid = {}, name = {}, path = {}, request body = {}",
+                        loginUser.getId(),
+                        loginUser.getUsername(),
                         apiPath,
                         requestBody,
                         e);
@@ -144,33 +151,6 @@ public class TradeSparqController {
         }
     }
 
-    // TODO 暂无GET请求调用 - 待Redis缓存 + 额度控制
-    // @GetMapping("/**")
-    // @ResponseBody
-    public Result<JSONObject> forwardGet(HttpServletRequest httpRequest) {
-        // 1. 生成签名
-        String apiPath = httpRequest.getServletPath().split(BASE_PATH)[1]; // 获取TradeSparq API路径
-        String queryString = httpRequest.getQueryString();
-        String apiUrl =
-                String.format(
-                        "%s%s%s",
-                        apiHost,
-                        apiPath,
-                        StringUtils.isNotBlank(queryString) ? "?" + queryString : "");
-        String sign = DigestUtils.md5DigestAsHex((apiSecret + apiUrl).getBytes());
-
-        // 2. 构建并发送GET请求
-        RequestEntity<?> requestEntity =
-                RequestEntity.get(apiUrl).headers(this.getHttpHeaders(sign)).build();
-        try {
-            ResponseEntity<JSONObject> responseEntity =
-                    restTemplate.exchange(requestEntity, JSONObject.class);
-            return Result.ok(responseEntity.getBody());
-        } catch (RestClientResponseException e) {
-            return Result.error(e.getStatusCode().value(), e.getMessage());
-        }
-    }
-
     private HttpHeaders getHttpHeaders(String sign) {
         HttpHeaders httpHeaders = new HttpHeaders();
         httpHeaders.setContentType(MediaType.APPLICATION_JSON);

+ 2 - 2
jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml

@@ -435,8 +435,8 @@ payment:
 tradesparq:
   api:
     host: https://openapi.tradesparq.com
-    id: Sw5bYYe7
-    secret: j4ThjI10jiV3L3y7
+    id: fu3owEv4
+    secret: jdWcRMII70cSk07E
 
 ### 询盘列表配置
 enquiry:

+ 2 - 2
jeecg-module-system/jeecg-system-start/src/main/resources/application-prod.yml

@@ -434,8 +434,8 @@ logistics:
 ### 跨境支付 - PingPong,Alibaba Pay 等
 payment:
   apc:
-    encrypt-key: QG+Y4ChKwPR9Ua7i/v9Lx/htPZP64R2eR1KBJ1BHofY=
-    sign-key: 2ce25a15426e4f1290bf5e4c3b5def1a
+    encrypt-key: gfdfX8qY/MlyIk3JvaIEJ38mViTCwqTJBacrBpfWj2c=
+    sign-key: 118c2fed89a9421dbf51bbbdd28486b5
 
 ### 外贸大数据 - 外贸公社
 tradesparq:

+ 2 - 2
jeecg-module-system/jeecg-system-start/src/main/resources/application-test.yml

@@ -434,8 +434,8 @@ payment:
 tradesparq:
   api:
     host: https://openapi.tradesparq.com
-    id: Sw5bYYe7
-    secret: j4ThjI10jiV3L3y7
+    id: fu3owEv4
+    secret: jdWcRMII70cSk07E
 
 ### 询盘列表配置
 enquiry: