Browse Source

coding:广告线索

zhangqin 16 giờ trước cách đây
mục cha
commit
6689b7d7ef
17 tập tin đã thay đổi với 149 bổ sung55 xóa
  1. 1 2
      fs-ad-new-api/src/main/java/com/fs/app/controller/LandingPageController.java
  2. 14 10
      fs-ad-new-api/src/main/java/com/fs/app/controller/TestController.java
  3. 1 2
      fs-ad-new-api/src/main/java/com/fs/app/facade/CallbackProcessingFacadeService.java
  4. 3 2
      fs-ad-new-api/src/main/java/com/fs/app/facade/CallbackProcessingFacadeServiceImpl.java
  5. 3 1
      fs-ad-new-api/src/main/java/com/fs/app/facade/ConversionServiceImpl.java
  6. 1 12
      fs-ad-new-api/src/main/java/com/fs/app/mq/consumer/ConversionTrackingMessageConsumer.java
  7. 54 0
      fs-ad-new-api/src/main/java/com/fs/framework/aspectj/RocketMQTraceIdAspect.java
  8. 4 0
      fs-service/src/main/java/com/fs/newAdv/domain/Lead.java
  9. 10 0
      fs-service/src/main/java/com/fs/newAdv/dto/req/TraceIdDto.java
  10. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/adapter/BaiduAdapter.java
  11. 2 3
      fs-service/src/main/java/com/fs/newAdv/integration/adapter/OPPOAdapter.java
  12. 15 8
      fs-service/src/main/java/com/fs/newAdv/integration/client/AbstractApiClient.java
  13. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/BaiduApiClient.java
  14. 14 11
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OPPOApiClient.java
  15. 12 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OceanEngineApiClient.java
  16. 1 1
      fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/VIVOApiClient.java
  17. 12 0
      fs-service/src/main/java/com/fs/newAdv/vo/ConversionParmVo.java

+ 1 - 2
fs-ad-new-api/src/main/java/com/fs/app/controller/LandingPageController.java

@@ -33,9 +33,8 @@ public class LandingPageController {
     @PostMapping("/h5/home")
     public Result<LandingIndexRes> h5Home(
             @RequestBody LandingIndexReq req) {
-        log.info("落地页访问追踪:req={}", req);
         // 查询落地页模板
-        return Result.success(facadeService.getLandingIndexBySiteId(req.getAllParams()));
+        return Result.success(facadeService.getLandingIndexBySiteId(req.getViewUrl(),req.getAllParams()));
     }
 
     /**

+ 14 - 10
fs-ad-new-api/src/main/java/com/fs/app/controller/TestController.java

@@ -1,15 +1,13 @@
 package com.fs.app.controller;
 
+import com.fs.newAdv.dto.req.TraceIdDto;
 import com.fs.newAdv.integration.client.advertiser.BaiduApiClient;
 import com.fs.newAdv.enums.SystemEventTypeEnum;
 import com.fs.newAdv.event.ConversionEventPublisher;
 import com.fs.newAdv.service.IPromotionAccountService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 /**
  * 广告商监测链接
@@ -28,15 +26,21 @@ public class TestController {
     @Autowired
     private IPromotionAccountService promotionAccountService;
 
-    @GetMapping("/test1/{traceId}")
-    public void test1(@PathVariable("traceId") String traceId) {
+    @PostMapping("/test1")
+    public void test1(@RequestBody TraceIdDto traceId) {
         log.info("模拟 当日加群 事件完成");
-        conversionEventPublisher.publishConversionEvent(traceId, SystemEventTypeEnum.GROUP_TODAY);
+        conversionEventPublisher.publishConversionEvent(traceId.getTraceId(), SystemEventTypeEnum.GROUP_TODAY);
     }
 
-    @GetMapping("/test2/{traceId}")
-    public void test2(@PathVariable("traceId") String traceId) {
+    @PostMapping("/test2")
+    public void test2(@RequestBody TraceIdDto traceId) {
         log.info("模拟 当日加微 事件完成");
-        conversionEventPublisher.publishConversionEvent(traceId, SystemEventTypeEnum.WEI_CHAT_TODAY);
+        conversionEventPublisher.publishConversionEvent(traceId.getTraceId(), SystemEventTypeEnum.WEI_CHAT_TODAY);
+    }
+
+    @PostMapping("/test3")
+    public void test3(@RequestBody TraceIdDto traceId) {
+        log.info("模拟 微信授权 事件完成");
+        conversionEventPublisher.publishConversionEvent(traceId.getTraceId(), SystemEventTypeEnum.AUTH_TODAY_CREATE);
     }
 }

+ 1 - 2
fs-ad-new-api/src/main/java/com/fs/app/facade/CallbackProcessingFacadeService.java

@@ -19,10 +19,9 @@ public interface CallbackProcessingFacadeService {
     /**
      * 根据站点ID获取落地页信息
      *
-     * @param siteId
      * @return
      */
-    LandingIndexRes getLandingIndexBySiteId(Map<String, String> allParams);
+    LandingIndexRes getLandingIndexBySiteId(String viewUrl,Map<String, String> allParams);
 
     //----------------------code回调---------------------------------
     void gdtGetAuthCode(Integer code, Long state);

+ 3 - 2
fs-ad-new-api/src/main/java/com/fs/app/facade/CallbackProcessingFacadeServiceImpl.java

@@ -94,7 +94,7 @@ public class CallbackProcessingFacadeServiceImpl implements CallbackProcessingFa
                 traceId = allParams.get("clickid");
                 break;
             case OPPO:
-                traceId = allParams.get("click_id");
+                traceId = allParams.get("tid");
                 break;
             case BAIDU:
                 traceId = allParams.get("bd_vid");
@@ -117,7 +117,7 @@ public class CallbackProcessingFacadeServiceImpl implements CallbackProcessingFa
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public LandingIndexRes getLandingIndexBySiteId(Map<String, String> allParams) {
+    public LandingIndexRes getLandingIndexBySiteId(String viewUrl,Map<String, String> allParams) {
         // 站点信息
         String paramsSiteId = allParams.get("siteId");
         if (ObjectUtil.isEmpty(paramsSiteId)) {
@@ -181,6 +181,7 @@ public class CallbackProcessingFacadeServiceImpl implements CallbackProcessingFa
         byTraceId.setLandingPageTrigger(1);
         byTraceId.setLandingPageTs(now);
         byTraceId.setUpdateTime(now);
+        byTraceId.setViewUrl(viewUrl);
         if (isNewLead) {
             leadService.save(byTraceId);
         } else {

+ 3 - 1
fs-ad-new-api/src/main/java/com/fs/app/facade/ConversionServiceImpl.java

@@ -96,7 +96,7 @@ public class ConversionServiceImpl implements IConversionService {
             return false;
         }
 
-        Map<String, Object> params = JSONUtil.toBean(lead.getTraceRawParams(), Map.class);
+        Map<String, Object> params = JSONUtil.toBean(lead.getLandingPageRawParams(), Map.class);
         // 构建回传参数
         Map<String, Object> conversionData = new HashMap<>();
         // ------------------------------通用参数----------
@@ -109,6 +109,8 @@ public class ConversionServiceImpl implements IConversionService {
         conversionData.put("traceId", traceId);
         conversionData.put("eventType", advertiserEventType.getAdvertiserEventType());
         conversionData.put("timestamp", System.currentTimeMillis() / 1000);
+        conversionData.put("viewUrl", lead.getViewUrl());
+
         // 添加平台适应参数
         IAdvertiserAdapter adapter = advertiserHandlerFactory.getAdapter(AdvertiserTypeEnum.getByCode(callbackAccount.getAdvertiserId()));
         adapter.uploadConversionData(conversionData, params);

+ 1 - 12
fs-ad-new-api/src/main/java/com/fs/app/mq/consumer/ConversionTrackingMessageConsumer.java

@@ -2,12 +2,9 @@ package com.fs.app.mq.consumer;
 
 import com.fs.app.facade.IConversionService;
 import com.fs.common.annotation.DistributeLock;
-import com.fs.common.utils.RedisUtil;
-import com.fs.common.utils.TraceIdUtil;
 import com.fs.newAdv.constant.ConversionTrackingMessage;
 import com.fs.newAdv.constant.MqTopicConstant;
 import com.fs.newAdv.enums.SystemEventTypeEnum;
-import com.fs.newAdv.mapper.ConversionLogMapper;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.rocketmq.spring.annotation.ConsumeMode;
 import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
@@ -28,19 +25,13 @@ import org.springframework.stereotype.Component;
         // 并发消费模式(多线程并发消费,线程数由RocketMQ自动管理)
         consumeMode = ConsumeMode.CONCURRENTLY,
         // 最大重试次数(RocketMQ默认16次)
-        maxReconsumeTimes = 16
+        maxReconsumeTimes = 3
 )
 public class ConversionTrackingMessageConsumer implements RocketMQListener<ConversionTrackingMessage> {
 
     @Autowired
     private IConversionService conversionService;
 
-    @Autowired
-    private RedisUtil redisUtil;
-
-    @Autowired
-    private ConversionLogMapper conversionLogMapper;
-
     /**
      * 消费转化消息
      *
@@ -49,8 +40,6 @@ public class ConversionTrackingMessageConsumer implements RocketMQListener<Conve
     @Override
     @DistributeLock(scene = "mq", keyExpression = "#message.traceId", waitTime = 0, errorMsg = "重复消费")
     public void onMessage(ConversionTrackingMessage message) {
-        TraceIdUtil.put(message.getTrackId());
-
         String traceId = message.getTraceId();
         SystemEventTypeEnum eventType = message.getEventType();
 

+ 54 - 0
fs-ad-new-api/src/main/java/com/fs/framework/aspectj/RocketMQTraceIdAspect.java

@@ -0,0 +1,54 @@
+package com.fs.framework.aspectj;
+
+import com.fs.common.utils.TraceIdUtil;
+import com.fs.newAdv.constant.ConversionTrackingMessage;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * RocketMQ消费者链路ID切面
+ * 在消费消息前设置链路ID到MDC,保证整个消费链路的日志可追踪
+ *
+ * @author zhangqin
+ */
+@Aspect
+@Component
+@Slf4j
+@Order(1) // 优先于 DistributeLockAspect 执行
+public class RocketMQTraceIdAspect {
+
+    @Pointcut("execution(* com.fs.app.mq.consumer.*.onMessage(..))")
+    public void mqConsumerPointcut() {
+    }
+
+    @Around("mqConsumerPointcut()")
+    public Object around(ProceedingJoinPoint pjp) throws Throwable {
+        String trackId = null;
+        try {
+            // 从消息参数中提取 trackId
+            Object[] args = pjp.getArgs();
+            if (args != null && args.length > 0) {
+                Object message = args[0];
+                if (message instanceof ConversionTrackingMessage) {
+                    trackId = ((ConversionTrackingMessage) message).getTrackId();
+                }
+            }
+            // 设置链路ID到MDC
+            if (trackId != null && !trackId.isEmpty()) {
+                TraceIdUtil.put(trackId);
+            } else {
+                // 如果没有 trackId,则生成一个新的
+                TraceIdUtil.init();
+            }
+            return pjp.proceed();
+        } finally {
+            // 清理MDC,避免线程复用时链路ID污染
+            TraceIdUtil.clear();
+        }
+    }
+}

+ 4 - 0
fs-service/src/main/java/com/fs/newAdv/domain/Lead.java

@@ -174,5 +174,9 @@ public class Lead implements Serializable {
      * 落地页访问时间
      */
     private LocalDateTime landingPageTs;
+    /**
+     * 落地页原始Url
+     */
+    private String viewUrl;
 }
 

+ 10 - 0
fs-service/src/main/java/com/fs/newAdv/dto/req/TraceIdDto.java

@@ -0,0 +1,10 @@
+package com.fs.newAdv.dto.req;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class TraceIdDto implements Serializable {
+    private String traceId;
+}

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/adapter/BaiduAdapter.java

@@ -54,7 +54,7 @@ public class BaiduAdapter implements IAdvertiserAdapter {
 
     @Override
     public void uploadConversionData(Map<String, Object> conversionData, Map<String, Object> params) {
-        conversionData.put("logidUrl",params.get("logidUrl"));
+
     }
 }
 

+ 2 - 3
fs-service/src/main/java/com/fs/newAdv/integration/adapter/OPPOAdapter.java

@@ -29,7 +29,6 @@ public class OPPOAdapter implements IAdvertiserAdapter {
      */
     @Override
     public Lead adaptCallbackData(Map<String, String> rawData) {
-        log.info("腾讯数据适配:{}", rawData);
         Lead lead = new Lead();
         lead.setTraceId(rawData.get("request_id"));
         lead.setAdvertiserId(AdvertiserTypeEnum.TENCENT.getCode());
@@ -50,7 +49,7 @@ public class OPPOAdapter implements IAdvertiserAdapter {
                     Instant.ofEpochMilli(Long.parseLong(rawData.get("click_time"))),
                     ZoneId.systemDefault()));
         } catch (Exception e) {
-            log.error("时间转换异常", e);
+            log.error("时间转换异常");
         }
         return lead;
     }
@@ -63,8 +62,8 @@ public class OPPOAdapter implements IAdvertiserAdapter {
     @Override
     public void uploadConversionData(Map<String, Object> conversionData, Map<String, Object> params) {
         // ------------------------------oppo参数----------
-        conversionData.put("tid", params.get("tid"));
         conversionData.put("lbid", params.get("lbid"));
+        conversionData.put("pageId", params.get("pageId"));
     }
 }
 

+ 15 - 8
fs-service/src/main/java/com/fs/newAdv/integration/client/AbstractApiClient.java

@@ -11,7 +11,6 @@ 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;
@@ -39,21 +38,29 @@ public abstract class AbstractApiClient implements IApiClient {
     protected boolean executeWithLog(AdvertiserTypeEnum advertiserType, String apiUrl, Map<String, Object> params, ApiCall action) {
         long start = System.currentTimeMillis();
         boolean callStatus = false;
-        String responseBody = "";
+        JSONObject jsonObject = null;
         try {
             log.info("[{}] 调用开始, 参数: {}", apiUrl, params);
             HttpResponse result = action.call();
-            JSONObject jsonObject = JSONUtil.parseObj(result.body());
-            Integer code = (Integer) jsonObject.get("code");
-            if (ObjectUtil.isNotEmpty(code) && (code == 0 || code == 200)) {
+            jsonObject = JSONUtil.parseObj(result.body());
+            // 通用状态
+            Integer code = jsonObject.getInt("code");
+            // 百度状态
+            Integer status = -1;
+            JSONObject header = jsonObject.getJSONObject("header");
+            if (ObjectUtil.isNotEmpty(header)) {
+                status = header.getInt("status");
+            }
+            if ((ObjectUtil.isNotEmpty(code) && (code == 0 || code == 200 ))
+            || (ObjectUtil.isNotEmpty(status) && status == 0)
+            ) {
                 callStatus = true;
             }
-            responseBody = JSONUtil.toJsonStr(jsonObject);
-            log.info("[{}] 调用成功, 耗时: {} ms, 返回结果: {}", apiUrl, System.currentTimeMillis() - start, result);
+            log.info("[{}] 调用成功, 耗时: {} ms, 返回结果: {}", apiUrl, System.currentTimeMillis() - start, jsonObject);
         } catch (Exception e) {
             log.error("[{}] 调用失败, 耗时: {} ms, 错误信息: {}", apiUrl, System.currentTimeMillis() - start, e.getMessage(), e);
         }
-        saveApiCallLog(advertiserType, apiUrl, params, responseBody, callStatus, start);
+        saveApiCallLog(advertiserType, apiUrl, params, jsonObject != null ? JSONUtil.toJsonStr(jsonObject) : null, callStatus, start);
         return callStatus;
     }
 

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

@@ -85,7 +85,7 @@ public class BaiduApiClient extends AbstractApiClient implements IAccessTokenCli
         Map<String, Object> conversion = new HashMap<>();
 
         // 点击ID(必填)
-        String logidUrl = (String) conversionData.get("logidUrl");
+        String logidUrl = (String) conversionData.get("viewUrl");
         if (StrUtil.isBlank(logidUrl)) {
             throw new ThirdPartyException("落地页不能为空");
         }

+ 14 - 11
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OPPOApiClient.java

@@ -8,10 +8,13 @@ import com.fs.newAdv.domain.SiteStatistics;
 import com.fs.newAdv.enums.AdvertiserTypeEnum;
 import com.fs.newAdv.integration.client.AbstractApiClient;
 import com.fs.common.constant.SystemConstant;
+import com.google.common.hash.Hashing;
+import com.google.common.io.BaseEncoding;
 import lombok.extern.slf4j.Slf4j;
 import me.chanjar.weixin.common.util.crypto.SHA1;
 import org.springframework.stereotype.Component;
 
+import java.nio.charset.Charset;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -45,15 +48,16 @@ public class OPPOApiClient extends AbstractApiClient {
             // 构建请求参数
             Map<String, Object> requestBody = buildConversionParams(conversionData);
             Long timestamp = (Long) conversionData.get("timestamp");
-            String ownerId = (String) conversionData.get("ownerId");
+            String ownerId = (String) conversionData.get("adAccountId");
             String appId = (String) conversionData.get("appId");
-            String appKey = (String) conversionData.get("appKey");
-            String sign = SHA1.gen(appId + appKey + timestamp);
-            String token = Base64.encode(ownerId + "," + appId + "," + timestamp + "," + sign);
+            String appKey = (String) conversionData.get("appSecret");
+            String sign = Hashing.sha1().hashString(appId + appKey + timestamp, Charset.defaultCharset()).toString();
+            String token = BaseEncoding.base64().encode((ownerId + "," + appId + "," + timestamp + "," + sign).getBytes());
+            log.info("OPPO API请求参数:{}", requestBody);
             // 发送HTTP请求
             return HttpRequest.post(CONVERSION_API_URL)
                     .header("Content-Type", "application/json")
-                    .header("Authorization", "Bearer  " + token)
+                    .header("Authorization", "Bearer " + token)
                     .body(JSONUtil.toJsonStr(requestBody))
                     .timeout(SystemConstant.API_TIMEOUT)
                     .execute();
@@ -70,18 +74,17 @@ public class OPPOApiClient extends AbstractApiClient {
         Map<String, Object> params = new HashMap<>();
 
         // 落地页Id:投放广告到投放
-        params.put("pageId", conversionData.get("traceId"));
+        params.put("pageId", conversionData.get("pageId"));
         // 广告主id:对应广告主自提供
-        params.put("adAccountId", conversionData.get("adAccountId"));
+        params.put("ownerId", conversionData.get("adAccountId"));
         // 用户IP:广告主收集
-        // params.put("ip", conversionData.get("ip"));
-        params.put("ip", "192.168.1.1");
+        params.put("ip", conversionData.get("ip"));
         // traceId:播放时追加在url上
-        params.put("tid", conversionData.get("tid"));
+        params.put("tid", conversionData.get("traceId"));
         // 流量号:播放时追加在URL上
         params.put("lbid ", conversionData.get("lbid"));
         // 事件
-        params.put("transformType ", conversionData.get("eventType"));
+        params.put("transformType", conversionData.get("eventType"));
         return params;
     }
 

+ 12 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/OceanEngineApiClient.java

@@ -18,8 +18,11 @@ import com.fs.newAdv.vo.AccessTokenVo;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.client.utils.URIBuilder;
 import org.springframework.stereotype.Component;
+import org.springframework.web.util.UriComponentsBuilder;
 
 import java.math.BigDecimal;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
 import java.util.Arrays;
 import java.util.Collections;
@@ -63,9 +66,16 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
         return executeWithLog(AdvertiserTypeEnum.OCEANENGINE, CONVERSION_API_URL, conversionData, () -> {
             // 构建请求参数
             Map<String, Object> requestBody = buildConversionParams(conversionData);
+/*            UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(CONVERSION_API_URL)
+                    .queryParam("callback", requestBody.get("traceId")) // 核心参数,监测链接透传的内容
+                    .queryParam("event_type", requestBody.get("event_type"))
+                    .queryParam("conv_time", requestBody.get("conv_time"));
+            URI uri = builder.build().encode(StandardCharsets.UTF_8).toUri();
+            log.info("准备调用巨量引擎回传接口, URL: {}", uri);*/
+
             // 发送HTTP请求
             return HttpRequest.get(CONVERSION_API_URL)
-                    .form(JSONUtil.toJsonStr(requestBody))
+                    .form(requestBody)
                     .timeout(SystemConstant.API_TIMEOUT)
                     .execute();
         });
@@ -208,5 +218,6 @@ public class OceanEngineApiClient extends AbstractApiClient implements IAccessTo
                 .expireTime(LocalDateTime.now().plusSeconds(data.getLong("refresh_token_expires_in")))
                 .build();
     }
+
 }
 

+ 1 - 1
fs-service/src/main/java/com/fs/newAdv/integration/client/advertiser/VIVOApiClient.java

@@ -82,7 +82,7 @@ public class VIVOApiClient extends AbstractApiClient {
 
     @Override
     public AdvertiserTypeEnum getAdvertiserType() {
-        return AdvertiserTypeEnum.OPPO;
+        return AdvertiserTypeEnum.VIVO;
     }
 
     @Override

+ 12 - 0
fs-service/src/main/java/com/fs/newAdv/vo/ConversionParmVo.java

@@ -0,0 +1,12 @@
+package com.fs.newAdv.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 回传通用参数类
+ */
+@Data
+public class ConversionParmVo implements Serializable {
+}