Browse Source

coding:投流数据统计

zhangqin 2 days ago
parent
commit
27a013c41a

+ 1 - 0
fs-ad-new-api/src/main/java/com/fs/app/controller/CallbackController.java

@@ -120,6 +120,7 @@ public class CallbackController {
         if (ObjectUtil.isNotEmpty(accessToken)) {
             byId.setAccessToken(accessToken.getAccessToken());
             byId.setRefreshToken(accessToken.getRefreshToken());
+            byId.setExpireTime(accessToken.getExpireTime());
             byId.setUpdateTime(LocalDateTime.now());
             promotionAccountService.updateById(byId);
         } else {

+ 5 - 5
fs-ad-new-api/src/main/java/com/fs/app/task/ConversionRetryTask.java

@@ -2,12 +2,12 @@ package com.fs.app.task;
 
 
 import cn.hutool.json.JSONUtil;
-import com.fs.newAdv.enums.AdvertiserTypeEnum;
-import com.fs.newAdv.integration.client.IApiClient;
-import com.fs.newAdv.integration.factory.AdvertiserHandlerFactory;
 import com.fs.common.annotation.DistributeLock;
 import com.fs.common.constant.SystemConstant;
 import com.fs.newAdv.domain.ConversionLog;
+import com.fs.newAdv.enums.AdvertiserTypeEnum;
+import com.fs.newAdv.integration.client.IApiClient;
+import com.fs.newAdv.integration.factory.AdvertiserHandlerFactory;
 import com.fs.newAdv.mapper.ConversionLogMapper;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -37,8 +37,8 @@ public class ConversionRetryTask {
      * 转化回传重试任务
      * cron: 每10分钟执行
      */
-    // @Scheduled(cron = "0 */1 * * * ?")
-    @DistributeLock(scene = "task", key = "conversion_retry", waitTime = 0, errorMsg = "任务已执行")
+    @Scheduled(cron = "0 */5 * * * ?")
+    @DistributeLock(scene = "task", key = "conversion_retry", waitTime = 0, errorMsg = "conversion_retry任务已执行")
     public void execute() {
         // 查询待重试的转化记录
         List<ConversionLog> pendingList = conversionLogMapper.selectPendingConversions();

+ 14 - 13
fs-ad-new-api/src/main/java/com/fs/app/task/DataSyncTask.java

@@ -2,6 +2,7 @@ package com.fs.app.task;
 
 import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.fs.common.annotation.DistributeLock;
 import com.fs.newAdv.domain.Lead;
 import com.fs.newAdv.service.ILeadService;
 import com.fs.newAdv.service.ISiteStatisticsService;
@@ -48,6 +49,7 @@ public class DataSyncTask {
      * cron: 每天00:10
      */
     @Scheduled(cron = "0 10 0 * * ?")
+    @DistributeLock(scene = "task", key = "sync_yesterday_data", waitTime = 0, errorMsg = "sync_yesterday_data任务已执行")
     public void syncYesterdayData() {
         String batchNo = DateUtil.format(LocalDateTime.now().minusDays(1), "yyyy-MM-dd");
         statisticsService.syncData(batchNo, 1);
@@ -58,7 +60,8 @@ public class DataSyncTask {
      * cron: 每1小时统计站点数据
      */
     @Scheduled(cron = "0 0/1 * * * ?")
-    public void syncTodayData() {
+    @DistributeLock(scene = "task", key = "sync_today_data", waitTime = 0, errorMsg = "sync_today_data任务已执行")
+    public void syncTodayData() throws InterruptedException {
         String batchNo = DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd");
         statisticsService.syncData(batchNo, 1);
     }
@@ -68,9 +71,8 @@ public class DataSyncTask {
      * 今日加群数据
      * cron: 每1小时统计站点数据
      */
-    // @Scheduled(cron = "0 0 0/1 * * ?")
-    @Scheduled(cron = "0 0/1 * * * ?")
-
+    @Scheduled(cron = "0 0 0/1 * * ?")
+    @DistributeLock(scene = "task", key = "wei_chat_group_to_day_data", waitTime = 0, errorMsg = "wei_chat_group_to_day_data任务已执行")
     public void weiChatGroupToDayData() {
         // 统计今日加群数量
         Optional.ofNullable(leadService.getToDayGroupNum())
@@ -97,9 +99,8 @@ public class DataSyncTask {
      * 累计加群数据
      * cron: 每天00:20
      */
-    // @Scheduled(cron = "0 20 0 * * ?")
-    @Scheduled(cron = "0 0/1 * * * ?")
-
+    @Scheduled(cron = "0 20 0 * * ?")
+    @DistributeLock(scene = "task", key = "wei_chat_group_count_data", waitTime = 0, errorMsg = "wei_chat_group_count_data任务已执行")
     public void weiChatGroupCountData() {
         // 统计累积加群数量
         Optional.ofNullable(leadService.getYesterdayGroupNum())
@@ -125,8 +126,8 @@ public class DataSyncTask {
      * 微信当天数据
      * cron: 一小时执行一次
      */
-    // @Scheduled(cron = "0 0 0/1 * * ?")
-    @Scheduled(cron = "0 0/1 * * * ?")
+    @Scheduled(cron = "0 0 0/1 * * ?")
+    @DistributeLock(scene = "task", key = "wei_chat_to_day_data", waitTime = 0, errorMsg = "wei_chat_to_day_data任务已执行")
     public void weiChatToDayData() {
         // 统计累积加微数量
         Optional.ofNullable(leadService.getToDayWeiChatNum())
@@ -174,8 +175,8 @@ public class DataSyncTask {
      * 微信累计数据
      * cron: 每天00:30
      */
-    // @Scheduled(cron = "0 30 0 * * ?")
-    @Scheduled(cron = "0 0/1 * * * ?")
+    @Scheduled(cron = "0 30 0 * * ?")
+    @DistributeLock(scene = "task", key = "wei_chat_count_data", waitTime = 0, errorMsg = "wei_chat_count_data任务已执行")
     public void weiChatCountData() {
         // 统计累积加微数量
         Optional.ofNullable(leadService.getYesterdayWeiChatNum())
@@ -194,7 +195,7 @@ public class DataSyncTask {
                                             qwAssignRuleUserService.update(
                                                     new LambdaUpdateWrapper<QwAssignRuleUser>()
                                                             .eq(QwAssignRuleUser::getId, k)
-                                                            .set(QwAssignRuleUser::getAssignNumCount, v+byId.getAssignNumCount())
+                                                            .set(QwAssignRuleUser::getAssignNumCount, v + byId.getAssignNumCount())
                                             );
                                         }
                                     });
@@ -213,7 +214,7 @@ public class DataSyncTask {
                                             qwAssignRuleUserService.update(
                                                     new LambdaUpdateWrapper<QwAssignRuleUser>()
                                                             .eq(QwAssignRuleUser::getId, k)
-                                                            .set(QwAssignRuleUser::getAddNumCount, v+byId.getAddNumCount())
+                                                            .set(QwAssignRuleUser::getAddNumCount, v + byId.getAddNumCount())
                                             );
                                         }
                                     });

+ 5 - 0
fs-company/src/main/java/com/fs/company/controller/newAdv/PromotionAccountController.java

@@ -10,6 +10,7 @@ import com.fs.newAdv.enums.AdvertiserTypeEnum;
 import com.fs.newAdv.service.IPromotionAccountService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -73,6 +74,7 @@ public class PromotionAccountController {
      * @param account 推广账号信息
      */
     @PostMapping
+    @Transactional(rollbackFor = Exception.class)
     public Result<Void> create(@RequestBody @Validated PromotionAccount account) {
 
         boolean success = promotionAccountService.save(account);
@@ -82,6 +84,9 @@ public class PromotionAccountController {
     }
 
     private void checkAuthUrl(PromotionAccount account) {
+        if (account.getApiSwitch() == 2){
+            return;
+        }
         if (account.getAdvertiserId().equals(AdvertiserTypeEnum.OCEANENGINE.getCode())){
             // 巨量
             account.setAuthUrl("https://open.oceanengine.com/audit/oauth.html?app_id="+account.getAppId()+"&state="+account.getId()+"&redirect_uri=https://track.mynatapp.cc/callback/oceanEngine/getAuthCode");

+ 1 - 0
fs-service/src/main/java/com/fs/newAdv/domain/PromotionAccount.java

@@ -103,6 +103,7 @@ public class PromotionAccount implements Serializable {
      * 应用授权链接
      */
     private String refreshToken;
+    private LocalDateTime expireTime;
 
     /**
      * 创建时间

+ 47 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/AbstractApiClient.java

@@ -4,19 +4,29 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
+import com.fs.newAdv.domain.PromotionAccount;
 import com.fs.newAdv.enums.AdvertiserTypeEnum;
+import com.fs.newAdv.integration.factory.AdvertiserHandlerFactory;
 import com.fs.newAdv.service.IApiCallLogService;
+import com.fs.newAdv.service.IPromotionAccountService;
+import com.fs.newAdv.vo.AccessTokenVo;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.formula.functions.T;
 import org.springframework.beans.factory.annotation.Autowired;
 
+import java.time.LocalDateTime;
 import java.util.Map;
+import java.util.function.Function;
 
 @Slf4j
 public abstract class AbstractApiClient implements IApiClient {
 
     @Autowired
     private IApiCallLogService apiCallLogService;
-
+    @Autowired
+    private IPromotionAccountService promotionAccountService;
+    @Autowired
+    private AdvertiserHandlerFactory advertiserHandlerFactory;
 
     /**
      * 构建回传接口上下文信息 (traceId, userId等)
@@ -60,4 +70,40 @@ public abstract class AbstractApiClient implements IApiClient {
     protected interface ApiCall {
         HttpResponse call() throws Exception;
     }
+
+    protected String getAccessToken(Long promotionAccountId) {
+        PromotionAccount byId = promotionAccountService.getById(promotionAccountId);
+        // 判断token是否过期 提前1小时刷新
+        if (byId.getExpireTime().isBefore(LocalDateTime.now().plusHours(1))) {
+            // 获取请求参数
+            IApiClient apiClient = advertiserHandlerFactory.getApiClient(AdvertiserTypeEnum.getByCode(byId.getAdvertiserId()));
+            IAccessTokenClient tokenClient = (IAccessTokenClient) apiClient;
+            AccessTokenVo accessTokenVo = tokenClient.refreshAccessToken(byId);
+            byId.setAccessToken(accessTokenVo.getAccessToken());
+            byId.setRefreshToken(accessTokenVo.getRefreshToken());
+            byId.setExpireTime(accessTokenVo.getExpireTime());
+            byId.setUpdateTime(LocalDateTime.now());
+            promotionAccountService.updateById(byId);
+            return accessTokenVo.getAccessToken();
+        }
+        return byId.getAccessToken();
+    }
+
+    protected <R> R executeToken(Function<JSONObject, R> mapper, ApiCall action) {
+        HttpResponse execute = null;
+        try {
+            execute = action.call();
+        } catch (Exception e) {
+            log.error("广告token调用失败", e);
+        }
+        String body = execute.body();
+        log.info("广告 token 接口响应: {}", body);
+        JSONObject res = new JSONObject(body);
+        int code = res.getInt("code");
+        if (code == 0 || code == 200) {
+            // 不同广告商返回的字段可能不一样 兼容
+            return mapper.apply(res);
+        }
+        return null;
+    }
 }

+ 2 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/IAccessTokenClient.java

@@ -1,10 +1,11 @@
 package com.fs.newAdv.integration.client;
 
+import com.fs.newAdv.domain.PromotionAccount;
 import com.fs.newAdv.vo.AccessTokenByAuthCodeVo;
 import com.fs.newAdv.vo.AccessTokenVo;
 
 public interface IAccessTokenClient extends IApiClient {
-    AccessTokenVo refreshAccessToken(String appId, String appSecret, String refreshToken);
+    AccessTokenVo refreshAccessToken(PromotionAccount promotionAccount);
 
     AccessTokenVo getAccessTokenByAuthCode(AccessTokenByAuthCodeVo codeVo);
 }

+ 2 - 0
fs-service/src/main/java/com/fs/newAdv/integration/client/IApiClient.java

@@ -1,9 +1,11 @@
 package com.fs.newAdv.integration.client;
 
+import cn.hutool.json.JSONObject;
 import com.fs.newAdv.domain.PromotionAccount;
 import com.fs.newAdv.domain.Site;
 import com.fs.newAdv.domain.SiteStatistics;
 import com.fs.newAdv.enums.AdvertiserTypeEnum;
+import com.fs.newAdv.vo.AccessTokenVo;
 
 import java.util.Map;
 

+ 50 - 54
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/BaiduApiClient.java

@@ -6,13 +6,13 @@ import cn.hutool.http.HttpResponse;
 import cn.hutool.json.JSONArray;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import com.fs.newAdv.integration.client.AbstractApiClient;
-import com.fs.newAdv.integration.client.IAccessTokenClient;
 import com.fs.common.constant.SystemConstant;
 import com.fs.common.exception.ThirdPartyException;
 import com.fs.newAdv.domain.PromotionAccount;
 import com.fs.newAdv.domain.SiteStatistics;
 import com.fs.newAdv.enums.AdvertiserTypeEnum;
+import com.fs.newAdv.integration.client.AbstractApiClient;
+import com.fs.newAdv.integration.client.IAccessTokenClient;
 import com.fs.newAdv.vo.AccessTokenByAuthCodeVo;
 import com.fs.newAdv.vo.AccessTokenVo;
 import lombok.extern.slf4j.Slf4j;
@@ -39,8 +39,8 @@ public class BaiduApiClient extends AbstractApiClient implements IAccessTokenCli
      */
     private static final String CONVERSION_API_URL = "https://ocpc.baidu.com/ocpcapi/api/uploadConvertData";
     private static final String REPORT_DATA_API_URL = "https://api.baidu.com/json/sms/service/OpenApiReportService/getReportData";
-    private static final String ACCESSTOKEN_URL = "https://u.baidu.com/oauth/accessToken";
-    private static final String REFRESHTOKEN_URL = "https://u.baidu.com/oauth/refreshToken";
+    private static final String ACCESS_TOKEN_URL = "https://u.baidu.com/oauth/accessToken";
+    private static final String REFRESH_TOKEN_URL = "https://u.baidu.com/oauth/refreshToken";
 
 
     /**
@@ -118,12 +118,12 @@ public class BaiduApiClient extends AbstractApiClient implements IAccessTokenCli
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account,String ideaId, String startDate, String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account, String ideaId, String startDate, String endDate) {
         // 构建请求参数
         Map<String, Object> map = new HashMap<>();
         Map<String, Object> header = new HashMap<>();
         header.put("accessToken", account.getAccessToken());
-        header.put("userName", "BDCC-yyt19");
+        header.put("userName", account.getAccountShortName());
         map.put("header", header);
         Map<String, Object> body = new HashMap<>();
         // 基础信息
@@ -142,8 +142,13 @@ public class BaiduApiClient extends AbstractApiClient implements IAccessTokenCli
         body.put("columns", Arrays.asList("impression", "click", "cost", "ctr", "cpc", "cpm", "phoneButtonClicks"));
         body.put("startRow", 0);
         body.put("rowCount", 1000);
+        Map<String,Object> filters = new HashMap<>();
+        filters.put("column","adGroupId");
+        filters.put("operator","IN");
+        filters.put("values",Arrays.asList(ideaId));
+        body.put("filters", filters);
         map.put("body", body);
-
+        log.info("百度数据请求参数:{}", JSONUtil.toJsonStr(map));
         HttpResponse execute = HttpRequest.post(REPORT_DATA_API_URL)
                 .header("Content-Type", "application/json")
                 .body(JSONUtil.toJsonStr(map))
@@ -166,58 +171,49 @@ public class BaiduApiClient extends AbstractApiClient implements IAccessTokenCli
 
 
     @Override
-    public AccessTokenVo refreshAccessToken(String appId, String appSecret, String refreshToken) {
-        // 调用接口换取授权令牌
-        Map<String, Object> requestMap = new HashMap<>();
-        requestMap.put("appId", appId);
-        requestMap.put("secretKey", appSecret);
-        requestMap.put("refreshToken", refreshToken);
-        // requestMap.put("userId", userId);
-        String paramsJson = JSONUtil.toJsonStr(requestMap);
-        HttpResponse execute = HttpRequest.post(REFRESHTOKEN_URL)
-                .header("Content-Type", "application/json")
-                .body(paramsJson)
-                .timeout(SystemConstant.API_TIMEOUT)
-                .execute();
-        JSONObject res = new JSONObject(execute.body());
-        int code = (int) res.get("code");
-        if (code == 0) {
-            JSONObject data = res.getJSONObject("data");
-            return AccessTokenVo.builder()
-                    .accessToken(data.getStr("accessToken"))
-                    .refreshToken(data.getStr("refreshToken"))
-                    .build();
-        }
-        return null;
+    public AccessTokenVo refreshAccessToken(PromotionAccount promotionAccount) {
+        return executeToken(this::getAccessTokenVo, () -> {
+            // 调用接口换取授权令牌
+            Map<String, Object> requestMap = new HashMap<>();
+            requestMap.put("appId", promotionAccount.getAppId());
+            requestMap.put("secretKey", promotionAccount.getAppSecret());
+            requestMap.put("refreshToken", promotionAccount.getRefreshToken());
+            requestMap.put("userId", promotionAccount.getAdAccountId());
+            // 发送HTTP请求
+            return HttpRequest.post(REFRESH_TOKEN_URL)
+                    .header("Content-Type", "application/json")
+                    .body(JSONUtil.toJsonStr(requestMap))
+                    .timeout(SystemConstant.API_TIMEOUT)
+                    .execute();
+        });
     }
 
     @Override
     public AccessTokenVo getAccessTokenByAuthCode(AccessTokenByAuthCodeVo codeVo) {
-        // 调用接口换取授权令牌
-        Map<String, Object> requestMap = new HashMap<>();
-        requestMap.put("appId", codeVo.getAppId());
-        requestMap.put("secretKey", codeVo.getAppSecret());
-        requestMap.put("authCode", codeVo.getAuthCode());
-        requestMap.put("grantType", "access_token");
-        requestMap.put("userId", codeVo.getUserId());
-        String paramsJson = JSONUtil.toJsonStr(requestMap);
-
-        HttpResponse execute = HttpRequest.post(ACCESSTOKEN_URL)
-                .header("Content-Type", "application/json")
-                .body(paramsJson)
-                .timeout(SystemConstant.API_TIMEOUT)
-                .execute();
+        return executeToken(this::getAccessTokenVo, () -> {
+            // 调用接口换取授权令牌
+            Map<String, Object> requestMap = new HashMap<>();
+            requestMap.put("appId", codeVo.getAppId());
+            requestMap.put("secretKey", codeVo.getAppSecret());
+            requestMap.put("authCode", codeVo.getAuthCode());
+            requestMap.put("grantType", "access_token");
+            requestMap.put("userId", codeVo.getUserId());
+            // 发送HTTP请求
+            return HttpRequest.post(ACCESS_TOKEN_URL)
+                    .header("Content-Type", "application/json")
+                    .body(JSONUtil.toJsonStr(requestMap))
+                    .timeout(SystemConstant.API_TIMEOUT)
+                    .execute();
+        });
+    }
 
-        JSONObject res = new JSONObject(execute.body());
-        int code = (int) res.get("code");
-        if (code == 0) {
-            JSONObject data = res.getJSONObject("data");
-            return AccessTokenVo.builder()
-                    .accessToken(data.getStr("accessToken"))
-                    .refreshToken(data.getStr("refreshToken"))
-                    .build();
-        }
-        return null;
+    public AccessTokenVo getAccessTokenVo(JSONObject res) {
+        JSONObject data = res.getJSONObject("data");
+        return AccessTokenVo.builder()
+                .accessToken((String) data.get("accessToken"))
+                .refreshToken((String) data.get("refreshToken"))
+                .expireTime(LocalDateTime.now().plusSeconds(data.getLong("expiresIn")))
+                .build();
     }
 }
 

+ 47 - 105
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OceanEngineApiClient.java

@@ -1,6 +1,5 @@
 package com.fs.newAdv.integration.client.advertiser;
 
-import cn.hutool.core.util.StrUtil;
 import cn.hutool.http.HttpRequest;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.json.JSONArray;
@@ -9,7 +8,6 @@ import cn.hutool.json.JSONUtil;
 import com.baidu.dev2.thirdparty.jackson.core.JsonProcessingException;
 import com.baidu.dev2.thirdparty.jackson.databind.ObjectMapper;
 import com.fs.common.constant.SystemConstant;
-import com.fs.common.exception.ThirdPartyException;
 import com.fs.newAdv.domain.PromotionAccount;
 import com.fs.newAdv.domain.SiteStatistics;
 import com.fs.newAdv.enums.AdvertiserTypeEnum;
@@ -22,9 +20,11 @@ import org.apache.http.client.utils.URIBuilder;
 import org.springframework.stereotype.Component;
 
 import java.math.BigDecimal;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.*;
+import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
 
 /**
  * 巨量引擎API客户端
@@ -87,65 +87,24 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
         return params;
     }
 
-    /**
-     * 构建上下文信息
-     *
-     * @param conversionData 转化数据
-     * @return 上下文Map
-     */
-    private Map<String, Object> buildContext(Map<String, Object> conversionData) {
-        Map<String, Object> context = new HashMap<>();
-
-        // 必填:点击ID
-        context.put("ad", buildAdContext(conversionData));
-
-        // 用户信息
-        if (conversionData.containsKey("userId")) {
-            Map<String, Object> user = new HashMap<>();
-            user.put("user_id", conversionData.get("userId"));
-            context.put("user", user);
-        }
-
-        return context;
-    }
-
-    /**
-     * 构建广告上下文
-     *
-     * @param conversionData 转化数据
-     * @return 广告上下文
-     */
-    private Map<String, Object> buildAdContext(Map<String, Object> conversionData) {
-        Map<String, Object> ad = new HashMap<>();
-
-        // 点击ID(必填)
-        String clickId = (String) conversionData.get("traceId");
-        if (StrUtil.isBlank(clickId)) {
-            throw new ThirdPartyException("点击ID不能为空");
-        }
-        ad.put("callback", clickId);
-
-        return ad;
-    }
-
     @Override
     public AdvertiserTypeEnum getAdvertiserType() {
         return AdvertiserTypeEnum.OCEANENGINE;
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account,String ideaId, String startDate, String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account, String ideaId, String startDate, String endDate) {
         // 构建请求参数
         Map<String, Object> map = new HashMap<>();
         map.put("advertiser_id", Long.valueOf(account.getAdAccountId()));
         // 纬度--天
         map.put("dimensions", Arrays.asList("stat_time_day"));
         // 过滤条件
-        Map<String,Object> filters = new HashMap<>();
-        filters.put("field","cdp_promotion_id");
-        filters.put("type",2);
-        filters.put("operator",1);
-        filters.put("values ",Arrays.asList(ideaId));
+        Map<String, Object> filters = new HashMap<>();
+        filters.put("field", "cdp_promotion_id");
+        filters.put("type", 2);
+        filters.put("operator", 1);
+        filters.put("values", Arrays.asList(ideaId));
         map.put("filters", Arrays.asList(filters));
         /**
          * stat_cost 消耗(元)
@@ -180,20 +139,10 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
             throw new RuntimeException(e);
         }
         HttpResponse execute = HttpRequest.get(url)
-                .header("Access-Token", account.getAccessToken())
+                .header("Access-Token", getAccessToken(account.getId()))
                 .timeout(SystemConstant.API_TIMEOUT)
                 .execute();
         JSONObject jsonObject = JSONUtil.parseObj(execute.body());
-        if (jsonObject.getInt("code") != 0) {
-            // 刷新token重新请求
-            log.info("巨量刷新token重新请求");
-            AccessTokenVo accessTokenVo = refreshAccessToken(account.getAppId(), account.getAppSecret(), account.getRefreshToken());
-            execute = HttpRequest.get(url)
-                    .header("Access-Token", accessTokenVo.getAccessToken())
-                    .timeout(SystemConstant.API_TIMEOUT)
-                    .execute();
-            jsonObject = JSONUtil.parseObj(execute.body());
-        }
         JSONObject data = jsonObject.getJSONObject("data");
         JSONArray rows = data.getJSONArray("rows");
         JSONObject jsonObject1 = rows.getJSONObject(0);
@@ -208,55 +157,48 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
         return siteStatistics;
     }
 
+
     @Override
-    public AccessTokenVo refreshAccessToken(String appId, String appSecret, String refreshToken) {
-        Map<String, Object> map = new HashMap<>();
-        map.put("app_id", appId);
-        map.put("secret", appSecret);
-        map.put("refresh_token", refreshToken);
-        HttpResponse response = HttpRequest.post(ACCESS_TOKEN_URL)
-                .header("Content-Type", "application/json")
-                .form(JSONUtil.toJsonStr(map))
-                .timeout(SystemConstant.API_TIMEOUT)
-                .execute();
-        JSONObject res = new JSONObject(response.body());
-        int code = (int) res.get("code");
-        if (code == 0) {
-            JSONObject data = res.getJSONObject("data");
-            return AccessTokenVo.builder()
-                    .accessToken((String) data.get("access_token"))
-                    .refreshToken((String) data.get("refresh_token"))
-                    .build();
-        }
-        return null;
+    public AccessTokenVo refreshAccessToken(PromotionAccount promotionAccount) {
+        return executeToken(this::getAccessTokenVo, () -> {
+            Map<String, Object> map = new HashMap<>();
+            map.put("app_id", promotionAccount.getAppId());
+            map.put("secret", promotionAccount.getAppSecret());
+            map.put("refresh_token", promotionAccount.getRefreshToken());
+            // 发送HTTP请求
+            return HttpRequest.post(REFRESH_TOKEN_URL)
+                    .header("Content-Type", "application/json")
+                    .body(JSONUtil.toJsonStr(map))
+                    .timeout(SystemConstant.API_TIMEOUT)
+                    .execute();
+        });
     }
 
 
     @Override
     public AccessTokenVo getAccessTokenByAuthCode(AccessTokenByAuthCodeVo request) {
-        Map<String, Object> map = new HashMap<>();
-        map.put("app_id", request.getAppId());
-        map.put("secret", request.getAppSecret());
-        map.put("auth_code", request.getAuthCode());
-        HttpResponse response = HttpRequest.post(ACCESS_TOKEN_URL)
-                .header("Content-Type", "application/json")
-                .body(JSONUtil.toJsonStr(map))
-                .timeout(SystemConstant.API_TIMEOUT)
-                .execute();
-        String body = response.body();
-        log.info("巨量获取token数据{}", body);
-        JSONObject res = new JSONObject(response.body());
-        int code = (int) res.get("code");
-        if (code == 0) {
-            JSONObject data = res.getJSONObject("data");
-            return AccessTokenVo.builder()
-                    .accessToken((String) data.get("access_token"))
-                    .refreshToken((String) data.get("refresh_token"))
-                    .build();
-        }
-        return null;
+        return executeToken(this::getAccessTokenVo, () -> {
+            // 调用接口换取授权令牌
+            Map<String, Object> map = new HashMap<>();
+            map.put("app_id", request.getAppId());
+            map.put("secret", request.getAppSecret());
+            map.put("auth_code", request.getAuthCode());
+            // 发送HTTP请求
+            return HttpRequest.post(ACCESS_TOKEN_URL)
+                    .header("Content-Type", "application/json")
+                    .body(JSONUtil.toJsonStr(map))
+                    .timeout(SystemConstant.API_TIMEOUT)
+                    .execute();
+        });
     }
 
-
+    public AccessTokenVo getAccessTokenVo(JSONObject res) {
+        JSONObject data = res.getJSONObject("data");
+        return AccessTokenVo.builder()
+                .accessToken((String) data.get("access_token"))
+                .refreshToken((String) data.get("refresh_token"))
+                .expireTime(LocalDateTime.now().plusSeconds(data.getLong("refresh_token_expires_in")))
+                .build();
+    }
 }
 

+ 35 - 41
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/TencentApiClient.java

@@ -1,21 +1,21 @@
 package com.fs.newAdv.integration.client.advertiser;
 
 import cn.hutool.http.HttpRequest;
-import cn.hutool.http.HttpResponse;
 import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
-import com.fs.newAdv.integration.client.AbstractApiClient;
-import com.fs.newAdv.integration.client.IAccessTokenClient;
 import com.fs.common.constant.SystemConstant;
 import com.fs.common.utils.SnowflakeUtil;
 import com.fs.newAdv.domain.PromotionAccount;
 import com.fs.newAdv.domain.SiteStatistics;
 import com.fs.newAdv.enums.AdvertiserTypeEnum;
+import com.fs.newAdv.integration.client.AbstractApiClient;
+import com.fs.newAdv.integration.client.IAccessTokenClient;
 import com.fs.newAdv.vo.AccessTokenByAuthCodeVo;
 import com.fs.newAdv.vo.AccessTokenVo;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Component;
 
+import java.time.LocalDateTime;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -83,52 +83,46 @@ public class TencentApiClient extends AbstractApiClient implements IAccessTokenC
     }
 
     @Override
-    public SiteStatistics getDataReport(PromotionAccount account,String ideaId, String startDate, String endDate) {
+    public SiteStatistics getDataReport(PromotionAccount account, String ideaId, String startDate, String endDate) {
         return null;
     }
 
 
-    public AccessTokenVo refreshAccessToken(String appId, String appSecret, String refreshToken) {
-        HttpResponse response = HttpRequest.get(TOKEN_API_URL)
-                .form("client_id", appId)
-                .form("client_secret", appSecret)
-                .form("grant_type", "refresh_token")
-                .form("refresh_token", refreshToken)
-                .timeout(SystemConstant.API_TIMEOUT)
-                .execute();
-
-        JSONObject res = new JSONObject(response.body());
-        int code = (int) res.get("code");
-        if (code == 0) {
-            JSONObject data = res.getJSONObject("data");
-            return AccessTokenVo.builder()
-                    .accessToken(data.getStr("access_token"))
-                    .refreshToken(data.getStr("refresh_token"))
-                    .build();
-        }
-        return null;
+    public AccessTokenVo refreshAccessToken(PromotionAccount promotionAccount) {
+        return executeToken(this::getAccessTokenVo, () -> {
+            // 发送HTTP请求
+            return HttpRequest.get(TOKEN_API_URL)
+                    .form("client_id", promotionAccount.getAppId())
+                    .form("client_secret", promotionAccount.getAppSecret())
+                    .form("grant_type", "refresh_token")
+                    .form("refresh_token", promotionAccount.getRefreshToken())
+                    .timeout(SystemConstant.API_TIMEOUT)
+                    .execute();
+        });
     }
 
     @Override
     public AccessTokenVo getAccessTokenByAuthCode(AccessTokenByAuthCodeVo codeVo) {
-        HttpResponse response = HttpRequest.get(TOKEN_API_URL)
-                .form("client_id", codeVo.getAppId())
-                .form("client_secret", codeVo.getAppSecret())
-                .form("grant_type", "authorization_code")
-                .form("authorization_code", codeVo.getAuthCode())
-                .form("redirect_uri", "authorization_code")
-                .timeout(SystemConstant.API_TIMEOUT)
-                .execute();
-        JSONObject res = new JSONObject(response.body());
-        int code = (int) res.get("code");
-        if (code == 0) {
-            JSONObject data = res.getJSONObject("data");
-            return AccessTokenVo.builder()
-                    .accessToken(data.getStr("access_token"))
-                    .refreshToken(data.getStr("refresh_token"))
-                    .build();
-        }
-        return null;
+        return executeToken(this::getAccessTokenVo, () -> {
+            // 发送HTTP请求
+            return HttpRequest.get(TOKEN_API_URL)
+                    .form("client_id", codeVo.getAppId())
+                    .form("client_secret", codeVo.getAppSecret())
+                    .form("grant_type", "authorization_code")
+                    .form("authorization_code", codeVo.getAuthCode())
+                    .form("redirect_uri", "authorization_code")
+                    .timeout(SystemConstant.API_TIMEOUT)
+                    .execute();
+        });
+    }
+
+    public AccessTokenVo getAccessTokenVo(JSONObject res) {
+        JSONObject data = res.getJSONObject("data");
+        return AccessTokenVo.builder()
+                .accessToken((String) data.get("access_token"))
+                .refreshToken((String) data.get("refresh_token"))
+                .expireTime(LocalDateTime.now().plusSeconds(data.getLong("access_token_expires_in")))
+                .build();
     }
 }
 

+ 2 - 0
fs-service/src/main/java/com/fs/newAdv/vo/AccessTokenVo.java

@@ -4,10 +4,12 @@ import lombok.Builder;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.time.LocalDateTime;
 
 @Data
 @Builder
 public class AccessTokenVo implements Serializable {
     private String accessToken;
     private String refreshToken;
+    private LocalDateTime expireTime;
 }