gufengshou1 1 年間 前
コミット
e6fa8fac30
40 ファイル変更3745 行追加0 行削除
  1. 33 0
      .gitignore
  2. 33 0
      ad-engine-commons/.gitignore
  3. 99 0
      ad-engine-commons/pom.xml
  4. 14 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/base/Constant.java
  5. 15 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/JDBCXmlScanConfig.java
  6. 66 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/LoggerLevelRefresher.java
  7. 79 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/MqConfig.java
  8. 149 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/RedisTemplateConfig.java
  9. 79 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/enums/AppTypeEnum.java
  10. 202 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AdOwnRedisHelper.java
  11. 199 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AlgorithmRedisHelper.java
  12. 51 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/FastJson2JsonRedisSerializer.java
  13. 291 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/RedisHelper.java
  14. 167 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/RedisTemplateConfig.java
  15. 28 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/CommonCollectionUtils.java
  16. 30 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/DateUtils.java
  17. 136 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/HttpClientFactory.java
  18. 38 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/JSONUtils.java
  19. 48 0
      ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/TraceUtils.java
  20. 45 0
      ad-engine-server/pom.xml
  21. 25 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/Application.java
  22. 28 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonCollectionUtils.java
  23. 8 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonTypeToken.java
  24. 30 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/DateUtils.java
  25. 136 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/HttpClientFactory.java
  26. 38 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/JSONUtils.java
  27. 48 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/TraceUtils.java
  28. 42 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/web/ControllerAspect.java
  29. 94 0
      ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/web/RecommendController.java
  30. 181 0
      ad-engine-server/src/main/resources/application-dev.yml
  31. 155 0
      ad-engine-server/src/main/resources/application-pre.yml
  32. 157 0
      ad-engine-server/src/main/resources/application-prod.yml
  33. 150 0
      ad-engine-server/src/main/resources/application-test.yml
  34. 122 0
      ad-engine-server/src/main/resources/application.yml
  35. 115 0
      ad-engine-server/src/main/resources/dynamic-datasource-mybatis.xml
  36. 276 0
      ad-engine-server/src/main/resources/logback-spring.xml
  37. 13 0
      ad-engine-server/src/main/resources/mybatis-config.xml
  38. 27 0
      ad-engine-service/pom.xml
  39. 4 0
      ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/rank/RankService.java
  40. 294 0
      pom.xml

+ 33 - 0
.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 33 - 0
ad-engine-commons/.gitignore

@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/

+ 99 - 0
ad-engine-commons/pom.xml

@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ad-engine</artifactId>
+        <groupId>com.tzld.piaoquan</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ad-engine-commons</artifactId>
+    <version>1.0.0</version>
+
+    <dependencies>
+        <dependency>
+            <groupId>net.devh</groupId>
+            <artifactId>grpc-client-spring-boot-starter</artifactId>
+            <version>2.9.0.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>3.12.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.16.8</version>
+        </dependency>
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java-util</artifactId>
+            <version>3.6.0</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>protobuf-java</artifactId>
+                    <groupId>com.google.protobuf</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+    <build>
+        <extensions>
+            <extension>
+                <groupId>kr.motd.maven</groupId>
+                <artifactId>os-maven-plugin</artifactId>
+                <version>1.6.0</version>
+            </extension>
+        </extensions>
+        <plugins>
+            <plugin>
+                <groupId>org.xolstice.maven.plugins</groupId>
+                <artifactId>protobuf-maven-plugin</artifactId>
+                <version>0.6.1</version>
+                <configuration>
+                    <protocArtifact>com.google.protobuf:protoc:3.12.0:exe:${os.detected.classifier}</protocArtifact>
+                    <pluginId>grpc-java</pluginId>
+                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.34.1:exe:${os.detected.classifier}</pluginArtifact>
+                    <!--设置grpc生成代码到指定路径-->
+                    <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
+                    <!--生成代码前是否清空目录-->
+                    <clearOutputDirectory>false</clearOutputDirectory>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                            <goal>compile-custom</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!-- 设置多个源文件夹 -->
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>3.0.0</version>
+                <executions>
+                    <!-- 添加主源码目录 -->
+                    <execution>
+                        <id>add-source</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>add-source</goal>
+                        </goals>
+                        <configuration>
+                            <sources>
+                                <source>${project.basedir}/src/main/java</source>
+                            </sources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+        </plugins>
+    </build>
+</project>

+ 14 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/base/Constant.java

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.ad.engine.commons.base;
+
+/**
+ * 常量
+ *
+ * @author supeng
+ * @date 2020/08/19
+ */
+public class Constant {
+    /**
+     * traceID
+     */
+    public static final String LOG_TRACE_ID = "logTraceId";
+}

+ 15 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/JDBCXmlScanConfig.java

@@ -0,0 +1,15 @@
+package com.tzld.piaoquan.ad.engine.commons.config;
+
+/**
+ * <p>
+ * JDBC XML扫描开启
+ * </p>
+ *
+ * @author zhaoyuchun
+ * @date 2023/10/23
+ */
+/*@ImportResource(locations = {"classpath*:dynamic-datasource-mybatis.xml"})
+@Configuration*/
+public class JDBCXmlScanConfig {
+
+}

+ 66 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/LoggerLevelRefresher.java

@@ -0,0 +1,66 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright © 2022 xrv <xrg@live.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package com.tzld.piaoquan.ad.engine.commons.config;
+
+import com.ctrip.framework.apollo.model.ConfigChangeEvent;
+import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.logging.LogLevel;
+import org.springframework.boot.logging.LoggingSystem;
+import org.springframework.stereotype.Component;
+
+/**
+ * 结合配置中心动态刷新(logging.level.)日志级别
+ *
+ * @author ehlxr
+ * @since 2022-01-06 17:43.
+ */
+@Component
+public class LoggerLevelRefresher {
+    private static final Logger logger = LoggerFactory.getLogger(LoggerLevelRefresher.class);
+    private static final String LOGGER_TAG = "logging.level.";
+    private final LoggingSystem loggingSystem;
+
+    @Autowired
+    public LoggerLevelRefresher(LoggingSystem loggingSystem) {
+        this.loggingSystem = loggingSystem;
+    }
+
+    @SuppressWarnings("unused")
+    @ApolloConfigChangeListener(interestedKeyPrefixes = LOGGER_TAG)
+    private void onChange(ConfigChangeEvent changeEvent) {
+        for (String key : changeEvent.changedKeys()) {
+            String strLevel = changeEvent.getChange(key).getNewValue();
+            loggingSystem.setLogLevel(key.replaceAll(LOGGER_TAG, ""),
+                    LogLevel.valueOf(strLevel.toUpperCase()));
+
+            logger.info("logging changed: {}, oldValue: {}, newValue: {}",
+                    key, changeEvent.getChange(key).getOldValue(), strLevel);
+        }
+    }
+
+}

+ 79 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/MqConfig.java

@@ -0,0 +1,79 @@
+package com.tzld.piaoquan.ad.engine.commons.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.Properties;
+
+@Configuration
+public class MqConfig {
+
+    @Value("${rocketmq.accessKey}")
+    private String accessKey;
+    @Value("${rocketmq.secretKey}")
+    private String secretKey;
+    @Value("${rocketmq.nameSrvAddr}")
+    private String nameSrvAddr;
+    @Value("${rocketmq.topic}")
+    private String topic;
+    @Value("${rocketmq.groupId}")
+    private String groupId;
+    @Value("${rocketmq.tag}")
+    private String tag;
+
+    public Properties getMqPropertie() {
+        Properties properties = new Properties();
+        properties.setProperty("AccessKey", this.accessKey);
+        properties.setProperty("SecretKey", this.secretKey);
+        properties.setProperty("NAMESRV_ADDR", this.nameSrvAddr);
+        return properties;
+    }
+
+    public String getAccessKey() {
+        return accessKey;
+    }
+
+    public void setAccessKey(String accessKey) {
+        this.accessKey = accessKey;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public String getNameSrvAddr() {
+        return nameSrvAddr;
+    }
+
+    public void setNameSrvAddr(String nameSrvAddr) {
+        this.nameSrvAddr = nameSrvAddr;
+    }
+
+    public String getTopic() {
+        return topic;
+    }
+
+    public void setTopic(String topic) {
+        this.topic = topic;
+    }
+
+    public String getGroupId() {
+        return groupId;
+    }
+
+    public void setGroupId(String groupId) {
+        this.groupId = groupId;
+    }
+
+    public String getTag() {
+        return tag;
+    }
+
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+}

+ 149 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/config/RedisTemplateConfig.java

@@ -0,0 +1,149 @@
+package com.tzld.piaoquan.ad.engine.commons.config;
+
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import com.tzld.piaoquan.ad.engine.commons.redis.FastJson2JsonRedisSerializer;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * @author ehlxr
+ */
+@Configuration
+public class RedisTemplateConfig {
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
+    public GenericObjectPoolConfig<LettucePoolingClientConfiguration> redisPool() {
+        return new GenericObjectPoolConfig<>();
+    }
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis")
+    public RedisStandaloneConfiguration redisConfig() {
+        return new RedisStandaloneConfiguration();
+    }
+
+    @Bean("factory")
+    @Primary
+    public LettuceConnectionFactory factory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config, RedisStandaloneConfiguration redisConfig) {
+        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
+        return new LettuceConnectionFactory(redisConfig, lettuceClientConfiguration);
+    }
+
+    @Bean(name = "redisTemplate")
+    public RedisTemplate<String, String> getRedisTemplate(@Qualifier("factory") RedisConnectionFactory factory) {
+        return buildRedisTemplateByString(factory);
+    }
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis-ad")
+    public RedisStandaloneConfiguration adOwnRedisConfig() {
+        return new RedisStandaloneConfiguration();
+    }
+
+    @Bean("adOwnFactory")
+    public LettuceConnectionFactory pushCenterFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config, RedisStandaloneConfiguration adOwnRedisConfig) {
+        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
+        return new LettuceConnectionFactory(adOwnRedisConfig, lettuceClientConfiguration);
+    }
+
+    @Bean(name = "adOwnRedisTemplate")
+    public RedisTemplate<String, String> getPushCenterRedisTemplate(@Qualifier("adOwnFactory") RedisConnectionFactory pushCenterFactory) {
+        return buildRedisTemplateByString(pushCenterFactory);
+    }
+
+    /**
+     * 构建redisTemplate 使用string序列化
+     *
+     * @param factory
+     * @return
+     */
+    public RedisTemplate<String, String> buildRedisTemplateByString(RedisConnectionFactory factory) {
+        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // key的序列化类型 保证可读性
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.setValueSerializer(new StringRedisSerializer());
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+    /**
+     * 构建redisTemplate value使用fastjson序列化
+     *
+     * @param factory
+     * @return
+     */
+    public RedisTemplate<String, Object> buildRedisTemplateByFastJson(RedisConnectionFactory factory) {
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // key的序列化类型 保证可读性
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        //value的序列化类型 fastjson 保证效率
+        FastJson2JsonRedisSerializer fastJson2JsonRedisSerializer = fastJson2JsonRedisSerializer();
+        redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
+        return redisTemplate;
+    }
+
+    /**
+     * 构建redisTemplate value使用jackson序列化
+     *
+     * @param factory
+     * @return
+     */
+    public RedisTemplate<String, Object> buildRedisTemplateByJackson(RedisConnectionFactory factory) {
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // key的序列化类型 保证可读性
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        //value的序列化类型 jackson 保证效率
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
+        return redisTemplate;
+    }
+
+    /**
+     * Jackson 序列化
+     *
+     * @return
+     */
+    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+        return jackson2JsonRedisSerializer;
+    }
+
+    /**
+     * FastJson 序列化
+     *
+     * @return
+     */
+    public FastJson2JsonRedisSerializer<Object> fastJson2JsonRedisSerializer() {
+        return new FastJson2JsonRedisSerializer(Object.class);
+    }
+}

+ 79 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/enums/AppTypeEnum.java

@@ -0,0 +1,79 @@
+package com.tzld.piaoquan.ad.engine.commons.enums;
+
+/**
+ * AppType
+ * 目前只维护 0 1 4 13 4个应用
+ *
+ * @author supeng
+ * @date 2020/08/19
+ */
+public enum AppTypeEnum {
+    /**
+     * vlog小程序
+     */
+    VLOG(0, "VLOG"),
+    /**
+     * 票圈视频APP
+     */
+    QING_QU_APP(1, "轻趣视频APP"),
+    SMILE(2, "搞笑视频"),
+    LOVE_MOVIE(3, "爱电影"),
+    /**
+     * 票圈视频小程序
+     */
+    LOVE_LIVE(4, "爱生活"),
+    /**
+     * 长视频小程序
+     */
+    LONG_VIDEO(5, "长视频"),
+    SHORT_VIDEO(6, "短视频"),
+    SURPRISE(7, "惊奇视频"),
+    PC(8, "PC端"),
+    CIRCLE_APP(9, "票圈长视频APP"),
+    LONG_VIDEO_LITE(10, "票圈长视频lite"),
+    /**
+     * 票圈相册小程序
+     */
+    ALBUM(11, "票圈相册"),
+    H5(12, "H5端"),
+    /**
+     * 极速版APP
+     */
+    APP_SPEED(13, "APP极速"),
+    SMALL_SPEED(14, "小程序极速"),
+    WAN_NENG_VIDEO(17, "万能影视屋(票圈|信仰之路)"),
+    LAO_HAO_KAN_VIDEO(18, "老好看视频"),
+    ZUI_JING_QI(19, "票圈最惊奇"),
+    PIAO_QUAN_VIDEO_PLUS(21, "票圈视频+"),
+    JOURNEY(22, "票圈足迹"),
+    ADMIN_CRAWLER(888888, "后台-爬虫"),
+    OTHERS(999999, "其他的调用方,比如后台管理系统");
+
+    private Integer code;
+    private String desc;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    private AppTypeEnum(Integer code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public static AppTypeEnum valueOf(Integer code) {
+        if (code == null) {
+            return null;
+        }
+        for (AppTypeEnum appTypeEnum : AppTypeEnum.values()) {
+            if (appTypeEnum.getCode().intValue() == code.intValue()) {
+                return appTypeEnum;
+            }
+        }
+        return null;
+    }
+}

+ 202 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AdOwnRedisHelper.java

@@ -0,0 +1,202 @@
+package com.tzld.piaoquan.ad.engine.commons.redis;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+@Service
+public class AdOwnRedisHelper {
+
+    private final static Logger log = LoggerFactory.getLogger(AdOwnRedisHelper.class);
+
+    private final static Long AD_FILTER_DEFAULT_EXPIRE_TIME = 30L * 24 * 60 * 60; // 排除人群(广告、计划)默认设置30天,单位秒
+    private final static Long AD_FILTER_DELAY_QUEUE_EXPIRETIME = 5L * 60 * 1000; // 排除人群优化默认设置5分钟,单位毫秒
+    private final static Long AD_FILTER_DEFAULT_USER_BEHAVIOR_EXPIRETIME = 1L * 24 * 60 * 60; // 排除人群优化默认设置1天,单位秒
+    @Resource(name = "adOwnRedisTemplate")
+    private RedisTemplate<String, String> adOwnRedisTemplate;
+
+
+    public boolean contantinsKey(String key) {
+        return adOwnRedisTemplate.hasKey(key);
+    }
+
+    public String getString(String key) {
+        Object obj = adOwnRedisTemplate.opsForValue().get(key);
+        return Objects.isNull(obj) ? null : obj.toString();
+    }
+
+    public Long getLong(String key) {
+        long longVal = 0L;
+        Object obj = adOwnRedisTemplate.opsForValue().get(key);
+        if (Objects.nonNull(obj)) {
+            try {
+                longVal = Long.parseLong(obj.toString());
+            } catch (Exception e) {
+                e.printStackTrace();
+                return longVal;
+            }
+
+        }
+        return longVal;
+    }
+
+    public void setValueWithExpire(String key, String value, Date date) {
+        long expireTime;
+        if (date != null) {
+            expireTime = (date.getTime() - System.currentTimeMillis()) / 1000;
+            if (expireTime < 0) { // 过期时间有问题,或者小于当前时间
+                expireTime = AD_FILTER_DEFAULT_USER_BEHAVIOR_EXPIRETIME;
+            }
+        } else {
+            expireTime = AD_FILTER_DEFAULT_USER_BEHAVIOR_EXPIRETIME;
+        }
+        adOwnRedisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
+    }
+
+    public void setIncrementValue(String key, long value, Date date) {
+        Long expireTime;
+        if (date != null) {
+            expireTime = (date.getTime() - System.currentTimeMillis()) / 1000;
+            // 过期时间有问题,或者小于当前时间
+            if (expireTime < 0) {
+                expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+            }
+        } else { // date为null
+            expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+        }
+        // 只在第一次进行设置过期时间
+        if (!contantinsKey(key)) {
+            adOwnRedisTemplate.opsForValue().increment(key, value);
+            adOwnRedisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
+        } else {
+            adOwnRedisTemplate.opsForValue().increment(key, value);
+        }
+    }
+
+    public void setIncrementValue(String key, double value, Date date) {
+        Long expireTime;
+        if (date != null) {
+            expireTime = (date.getTime() - System.currentTimeMillis()) / 1000;
+            // 过期时间有问题,或者小于当前时间
+            if (expireTime < 0) {
+                expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+            }
+        } else { // date为null
+            expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+        }
+        // 只在第一次进行设置过期时间
+        if (!contantinsKey(key)) {
+            adOwnRedisTemplate.opsForValue().increment(key, value);
+            adOwnRedisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
+        } else {
+            adOwnRedisTemplate.opsForValue().increment(key, value);
+        }
+    }
+
+    public int getInteger(String key) {
+        Object obj = adOwnRedisTemplate.opsForValue().get(key);
+        if (Objects.isNull(obj)) {
+            return 0;
+        }
+        return Integer.valueOf(obj.toString());
+    }
+
+    public void putDealyQueueMsg(String key, String value) {
+        adOwnRedisTemplate.opsForZSet().add(key, value, System.currentTimeMillis() + AD_FILTER_DELAY_QUEUE_EXPIRETIME);
+    }
+
+    public Set<String> processDelayQueue(String key) {
+        long currentTimeMillis = System.currentTimeMillis();
+        Set<String> values = adOwnRedisTemplate.opsForZSet().rangeByScore(key, 0, currentTimeMillis);
+        if (!CollectionUtils.isEmpty(values)) {
+            adOwnRedisTemplate.opsForZSet().removeRangeByScore(key, 0, currentTimeMillis);
+        }
+        return values;
+    }
+
+    public void addVal(String key, String val) {
+        adOwnRedisTemplate.opsForValue().set(key, val);
+    }
+
+    public Long getKeyExpire(String key) {
+        return adOwnRedisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    public void expire(String key, Long time) {
+        adOwnRedisTemplate.expire(key, time, TimeUnit.SECONDS);
+    }
+
+    public Long countExistingKeys(List<String> keys) {
+        return adOwnRedisTemplate.countExistingKeys(keys);
+    }
+
+    public boolean del(String key) {
+        return adOwnRedisTemplate.delete(key);
+    }
+
+    public boolean set(String key, String value, long time) {
+        try {
+            if (time > 0) {
+                adOwnRedisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                adOwnRedisTemplate.opsForValue().set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * Redis 分布式锁
+     *
+     * @param key        锁键
+     * @param value      锁值,可以为随机数或者 UUID 等唯一标识符
+     * @param expireTime 锁过期时间,单位为秒
+     * @return true:获取锁成功,false:获取锁失败
+     */
+    public boolean tryLock(String key, String value, long expireTime) {
+        Boolean result = adOwnRedisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
+        if (result != null && result) {
+            // 获取锁成功
+            return true;
+        }
+        return false;
+    }
+
+    public void listLeftPush(String key, String value) {
+        adOwnRedisTemplate.opsForList().leftPush(key, value);
+
+    }
+
+    public String listRightPop(String key) {
+        return adOwnRedisTemplate.opsForList().rightPop(key);
+    }
+
+    public Double getDouble(String key) {
+        String val = adOwnRedisTemplate.opsForValue().get(key);
+        if (StringUtils.isNotBlank(val)) {
+            return Double.valueOf(val);
+        }
+        return null;
+    }
+
+    public String get(String key) {
+        String val = adOwnRedisTemplate.opsForValue().get(key);
+        if (StringUtils.isNotBlank(val)) {
+            return val;
+        }
+        return null;
+    }
+}

+ 199 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/AlgorithmRedisHelper.java

@@ -0,0 +1,199 @@
+package com.tzld.piaoquan.ad.engine.commons.redis;
+
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+public class AlgorithmRedisHelper {
+    private final static Logger log = LoggerFactory.getLogger(AdOwnRedisHelper.class);
+
+    private final static Long AD_FILTER_DEFAULT_EXPIRE_TIME = 30L * 24 * 60 * 60; // 排除人群(广告、计划)默认设置30天,单位秒
+    private final static Long AD_FILTER_DELAY_QUEUE_EXPIRETIME = 5L * 60 * 1000; // 排除人群优化默认设置5分钟,单位毫秒
+    private final static Long AD_FILTER_DEFAULT_USER_BEHAVIOR_EXPIRETIME = 1L * 24 * 60 * 60; // 排除人群优化默认设置1天,单位秒
+    @Resource(name = "adOwnRedisTemplate")
+    private RedisTemplate<String, String> redisTemplate;
+
+
+    public boolean contantinsKey(String key) {
+        return redisTemplate.hasKey(key);
+    }
+
+    public String getString(String key) {
+        Object obj = redisTemplate.opsForValue().get(key);
+        return Objects.isNull(obj) ? null : obj.toString();
+    }
+
+    public Long getLong(String key) {
+        long longVal = 0L;
+        Object obj = redisTemplate.opsForValue().get(key);
+        if (Objects.nonNull(obj)) {
+            try {
+                longVal = Long.parseLong(obj.toString());
+            } catch (Exception e) {
+                e.printStackTrace();
+                return longVal;
+            }
+
+        }
+        return longVal;
+    }
+
+    public void setValueWithExpire(String key, String value, Date date) {
+        long expireTime;
+        if (date != null) {
+            expireTime = (date.getTime() - System.currentTimeMillis()) / 1000;
+            if (expireTime < 0) { // 过期时间有问题,或者小于当前时间
+                expireTime = AD_FILTER_DEFAULT_USER_BEHAVIOR_EXPIRETIME;
+            }
+        } else {
+            expireTime = AD_FILTER_DEFAULT_USER_BEHAVIOR_EXPIRETIME;
+        }
+        redisTemplate.opsForValue().set(key, value, expireTime, TimeUnit.SECONDS);
+    }
+
+    public void setIncrementValue(String key, long value, Date date) {
+        Long expireTime;
+        if (date != null) {
+            expireTime = (date.getTime() - System.currentTimeMillis()) / 1000;
+            // 过期时间有问题,或者小于当前时间
+            if (expireTime < 0) {
+                expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+            }
+        } else { // date为null
+            expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+        }
+        // 只在第一次进行设置过期时间
+        if (!contantinsKey(key)) {
+            redisTemplate.opsForValue().increment(key, value);
+            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
+        } else {
+            redisTemplate.opsForValue().increment(key, value);
+        }
+    }
+
+    public void setIncrementValue(String key, double value, Date date) {
+        Long expireTime;
+        if (date != null) {
+            expireTime = (date.getTime() - System.currentTimeMillis()) / 1000;
+            // 过期时间有问题,或者小于当前时间
+            if (expireTime < 0) {
+                expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+            }
+        } else { // date为null
+            expireTime = AD_FILTER_DEFAULT_EXPIRE_TIME;
+        }
+        // 只在第一次进行设置过期时间
+        if (!contantinsKey(key)) {
+            redisTemplate.opsForValue().increment(key, value);
+            redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
+        } else {
+            redisTemplate.opsForValue().increment(key, value);
+        }
+    }
+
+    public int getInteger(String key) {
+        Object obj = redisTemplate.opsForValue().get(key);
+        if (Objects.isNull(obj)) {
+            return 0;
+        }
+        return Integer.valueOf(obj.toString());
+    }
+
+    public void putDealyQueueMsg(String key, String value) {
+        redisTemplate.opsForZSet().add(key, value, System.currentTimeMillis() + AD_FILTER_DELAY_QUEUE_EXPIRETIME);
+    }
+
+    public Set<String> processDelayQueue(String key) {
+        long currentTimeMillis = System.currentTimeMillis();
+        Set<String> values = redisTemplate.opsForZSet().rangeByScore(key, 0, currentTimeMillis);
+        if (!CollectionUtils.isEmpty(values)) {
+            redisTemplate.opsForZSet().removeRangeByScore(key, 0, currentTimeMillis);
+        }
+        return values;
+    }
+
+    public void addVal(String key, String val) {
+        redisTemplate.opsForValue().set(key, val);
+    }
+
+    public Long getKeyExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    public void expire(String key, Long time) {
+        redisTemplate.expire(key, time, TimeUnit.SECONDS);
+    }
+
+    public Long countExistingKeys(List<String> keys) {
+        return redisTemplate.countExistingKeys(keys);
+    }
+
+    public boolean del(String key) {
+        return redisTemplate.delete(key);
+    }
+
+    public boolean set(String key, String value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                redisTemplate.opsForValue().set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * Redis 分布式锁
+     *
+     * @param key        锁键
+     * @param value      锁值,可以为随机数或者 UUID 等唯一标识符
+     * @param expireTime 锁过期时间,单位为秒
+     * @return true:获取锁成功,false:获取锁失败
+     */
+    public boolean tryLock(String key, String value, long expireTime) {
+        Boolean result = redisTemplate.opsForValue().setIfAbsent(key, value, expireTime, TimeUnit.SECONDS);
+        if (result != null && result) {
+            // 获取锁成功
+            return true;
+        }
+        return false;
+    }
+
+    public void listLeftPush(String key, String value) {
+        redisTemplate.opsForList().leftPush(key, value);
+
+    }
+
+    public String listRightPop(String key) {
+        return redisTemplate.opsForList().rightPop(key);
+    }
+
+    public Double getDouble(String key) {
+        String val = redisTemplate.opsForValue().get(key);
+        if (StringUtils.isNotBlank(val)) {
+            return Double.valueOf(val);
+        }
+        return null;
+    }
+
+    public String get(String key) {
+        String val = redisTemplate.opsForValue().get(key);
+        if (StringUtils.isNotBlank(val)) {
+            return val;
+        }
+        return null;
+    }
+}

+ 51 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/FastJson2JsonRedisSerializer.java

@@ -0,0 +1,51 @@
+package com.tzld.piaoquan.ad.engine.commons.redis;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+
+import java.nio.charset.Charset;
+
+/**
+ * fastjson redis序列化
+ *
+ * @author supeng
+ * @date 2020/09/03
+ */
+public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
+
+    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+
+    private Class<T> clazz;
+
+    static {
+    	// 这行代码不加,从redis中取数据会反序列化失败
+    	ParserConfig.getGlobalInstance().setAutoTypeSupport(true); 
+    }
+    
+    public FastJson2JsonRedisSerializer(Class<T> clazz) {
+        super();
+        this.clazz = clazz;
+    }
+
+    @Override
+    public byte[] serialize(T t) throws SerializationException {
+        if (t == null) {
+            return new byte[0];
+        }
+        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
+    }
+
+    @Override
+    public T deserialize(byte[] bytes) throws SerializationException {
+        if (bytes == null || bytes.length <= 0) {
+            return null;
+        }
+        String str = new String(bytes, DEFAULT_CHARSET);
+
+        return JSON.parseObject(str, clazz);
+    }
+    
+}

+ 291 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/RedisHelper.java

@@ -0,0 +1,291 @@
+package com.tzld.piaoquan.ad.engine.commons.redis;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.connection.RedisStringCommands;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.types.Expiration;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author ehlxr
+ */
+@Component
+public class RedisHelper {
+    private static final Logger log = LoggerFactory.getLogger(RedisHelper.class);
+
+    /**
+     * 解锁 lua 脚本
+     */
+    // public static final String UNLOCK = "if (redis.call('get', KEYS[1]) == ARGV[1]) then" +
+    //         " return redis.call('del', KEYS[1]);" +
+    //         "else" +
+    //         " return 0;" +
+    //         "end";
+    /**
+     * 锁前缀
+     */
+    private static final String LOCK_PREFIX = "LOCK_";
+
+    /**
+     * 每次重试间隔时间 (毫秒)
+     */
+    // private static final int DEFAULT_RETRY_INTERVAL = 100;
+    private static RedisTemplate<String, String> redisTemplate;
+
+    /**
+     * 加锁
+     *
+     * @param timeout 毫秒
+     */
+    // public static Boolean lock(String key, String lockId, long timeout) {
+    //     return redisTemplate.opsForValue().setIfAbsent(LOCK_PREFIX + key, lockId, timeout, TimeUnit.MILLISECONDS);
+    // }
+
+    /**
+     * 重试加锁
+     *
+     * @param interval 重试间隔时间
+     */
+    // public static Boolean tryLock(String key, String lockId, long timeout, int interval) {
+    //     if (interval <= 0) {
+    //         interval = DEFAULT_RETRY_INTERVAL;
+    //     }
+    //     while (timeout >= 0) {
+    //         if (lock(key, lockId, timeout)) {
+    //             return true;
+    //         }
+    //         try {
+    //             TimeUnit.MILLISECONDS.sleep(interval);
+    //         } catch (Exception e) {
+    //             log.error("tryLock error key {} lockId {}", key, lockId, e);
+    //         }
+    //         timeout -= interval;
+    //     }
+    //     return false;
+    // }
+
+    // public static Boolean tryLock(String key, String lockId, long timeout) {
+    //     return tryLock(key, lockId, timeout, 0);
+    // }
+
+    /**
+     * 解锁
+     */
+    // public static Boolean unlock(String key, String lockId) {
+    //     String lockKey = LOCK_PREFIX + key;
+    //     DefaultRedisScript<Long> script = new DefaultRedisScript<>();
+    //     script.setResultType(Long.class);
+    //     script.setScriptSource(new StaticScriptSource(UNLOCK));
+    //
+    //     Object result = redisTemplate.execute(script, Collections.singletonList(lockKey), lockId);
+    //     if (Objects.isNull(result)) {
+    //         return null;
+    //     }
+    //     return Objects.equals(1L, Long.valueOf(result.toString()));
+    // }
+    @Autowired
+    public void setRedisTemplate(@Qualifier("redisTemplate") RedisTemplate<String, String> redisTemplate) {
+        RedisHelper.redisTemplate = redisTemplate;
+    }
+
+    public Object get(String key) {
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+    }
+
+    public boolean set(String key, String value, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    public boolean set(String key, String value) {
+        try {
+            redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    // public Long decr(String key, long delta) {
+    //     if (delta < 0) {
+    //         throw new RuntimeException("递减因子必须大于0");
+    //     }
+    //     return redisTemplate.opsForValue().increment(key, -delta);
+    // }
+
+    public Long incr(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    // public void expire(String key, long time) {
+    //     try {
+    //         if (time > 0) {
+    //             redisTemplate.expire(key, time, TimeUnit.SECONDS);
+    //         }
+    //     } catch (Exception e) {
+    //         e.printStackTrace();
+    //     }
+    // }
+
+    /**
+     * 根据value从一个set中查询,是否存在
+     *
+     * @param key   键
+     * @param value 值
+     * @return true 存在 false不存在
+     */
+    public Boolean sIsMember(String key, Object value) {
+        try {
+            return redisTemplate.opsForSet().isMember(key, value);
+        } catch (Exception e) {
+            log.error("set has key error", e);
+            return false;
+        }
+    }
+
+    /**
+     * 将数据放入set缓存
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     */
+    public void sSet(String key, String... values) {
+        try {
+            redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            log.error("set add is error", e);
+        }
+    }
+
+    // public void sRemove(String key, Object... values) {
+    //     try {
+    //         redisTemplate.opsForSet().remove(key, values);
+    //     } catch (Exception e) {
+    //         log.error("set remove is error", e);
+    //     }
+    // }
+
+    public void leftPushAll(String key, List<String> value) {
+        try {
+            redisTemplate.opsForList().leftPushAll(key, value);
+        } catch (Exception e) {
+            log.error("list left push all error", e);
+        }
+    }
+
+    /**
+     * 获取list缓存的内容
+     *
+     * @param key   键
+     * @param start 开始
+     * @param end   结束 0 到 -1代表所有值
+     */
+    public List<String> lGet(String key, long start, long end) {
+        try {
+            return redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            log.error("RedisUtils.lGet.is.error.key={},start={},end={}", key, start, end, e);
+            return null;
+        }
+    }
+
+    /**
+     * 获取list缓存的长度
+     */
+    public Long lGetListSize(String key) {
+        try {
+            return redisTemplate.opsForList().size(key);
+        } catch (Exception e) {
+            log.error("get list size error", e);
+            return 0L;
+        }
+    }
+
+    // public Map<String, String> getHashEntries(String key) {
+    //     try {
+    //         return redisTemplate.<String, String>opsForHash().entries(key);
+    //     } catch (Exception e) {
+    //         log.error("get hash entry error", e);
+    //         return null;
+    //     }
+    // }
+
+    /**
+     * 获取某个元素的分数
+     */
+    public Double zScore(String key, String value) {
+        return redisTemplate.opsForZSet().score(key, value);
+    }
+
+    // public Long zRemove(String value, String key) {
+    //     return redisTemplate.opsForZSet().remove(key, value);
+    // }
+
+    /**
+     * 批量添加
+     */
+    // public static void batchSet(Map<String, String> map) {
+    //     redisTemplate.opsForValue().multiSet(map);
+    // }
+
+    /**
+     * 批量添加 并且设置失效时间
+     */
+    public static int batchSetOrExpire(Map<String, String> map, Long seconds) {
+        RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
+        return redisTemplate.executePipelined((RedisCallback<String>) connection -> {
+            map.forEach((key, value) -> {
+                byte[] keySeria = serializer.serialize(key);
+                byte[] valueSeria = serializer.serialize(value);
+                if (keySeria == null || valueSeria == null) {
+                    return;
+                }
+                connection.set(keySeria, valueSeria, Expiration.seconds(seconds), RedisStringCommands.SetOption.UPSERT);
+            });
+            return null;
+        }, serializer).size();
+    }
+
+    public void put(String key, String value) {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    public void expire(String key, long day) {
+        redisTemplate.expire(key, day, TimeUnit.DAYS);
+    }
+
+    public boolean SetContain(String key, String value) {
+        return redisTemplate.opsForSet().isMember(key, value);
+    }
+
+    // public static List<String> batchGet(List<String> list) {
+    //     List<String> objectList = redisTemplate.opsForValue().multiGet(list);
+    //     return objectList;
+    // }
+
+    // public static void batchDelete(List<String> list) {
+    //     redisTemplate.delete(list);
+    // }
+}

+ 167 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/redis/RedisTemplateConfig.java

@@ -0,0 +1,167 @@
+package com.tzld.piaoquan.ad.engine.commons.redis;
+
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
+import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * @author ehlxr
+ */
+@Configuration
+public class RedisTemplateConfig {
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
+    public GenericObjectPoolConfig<LettucePoolingClientConfiguration> redisPool() {
+        return new GenericObjectPoolConfig<>();
+    }
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis")
+    public RedisStandaloneConfiguration redisConfig() {
+        return new RedisStandaloneConfiguration();
+    }
+
+    @Bean("factory")
+    @Primary
+    public LettuceConnectionFactory factory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config, RedisStandaloneConfiguration redisConfig) {
+        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
+        return new LettuceConnectionFactory(redisConfig, lettuceClientConfiguration);
+    }
+
+    @Bean(name = "redisTemplate")
+    public RedisTemplate<String, String> getRedisTemplate(@Qualifier("factory") RedisConnectionFactory factory) {
+        return buildRedisTemplateByString(factory);
+    }
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis-ad")
+    public RedisStandaloneConfiguration adOwnRedisConfig() {
+        return new RedisStandaloneConfiguration();
+    }
+
+    @Bean("adOwnFactory")
+    public LettuceConnectionFactory pushCenterFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config, RedisStandaloneConfiguration adOwnRedisConfig) {
+        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
+        return new LettuceConnectionFactory(adOwnRedisConfig, lettuceClientConfiguration);
+    }
+
+    @Bean(name = "adOwnRedisTemplate")
+    public RedisTemplate<String, String> getPushCenterRedisTemplate(@Qualifier("adOwnFactory") RedisConnectionFactory pushCenterFactory) {
+        return buildRedisTemplateByString(pushCenterFactory);
+    }
+
+    @Bean(name = "algorithmRedisTemplate")
+    public RedisTemplate<String, String> getAlgorithmRedisTemplate(@Qualifier("algorithmRedisFactory") RedisConnectionFactory algorithmRedisFactory) {
+        return buildRedisTemplateByString(algorithmRedisFactory);
+    }
+
+    @Bean
+    @ConfigurationProperties(prefix = "spring.redis-algorithm")
+    public RedisStandaloneConfiguration algorithmRedisConfig() {
+        return new RedisStandaloneConfiguration();
+    }
+
+    @Bean("algorithmRedisFactory")
+    public LettuceConnectionFactory algorithmRedisFactory(GenericObjectPoolConfig<LettucePoolingClientConfiguration> config, RedisStandaloneConfiguration algorithmRedisConfig) {
+        LettuceClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
+        return new LettuceConnectionFactory(algorithmRedisConfig, lettuceClientConfiguration);
+    }
+
+
+
+    /**
+     * 构建redisTemplate 使用string序列化
+     *
+     * @param factory
+     * @return
+     */
+    public RedisTemplate<String, String> buildRedisTemplateByString(RedisConnectionFactory factory) {
+        RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // key的序列化类型 保证可读性
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        redisTemplate.setValueSerializer(new StringRedisSerializer());
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
+        return redisTemplate;
+    }
+
+    /**
+     * 构建redisTemplate value使用fastjson序列化
+     *
+     * @param factory
+     * @return
+     */
+    public RedisTemplate<String, Object> buildRedisTemplateByFastJson(RedisConnectionFactory factory) {
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // key的序列化类型 保证可读性
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        //value的序列化类型 fastjson 保证效率
+        FastJson2JsonRedisSerializer fastJson2JsonRedisSerializer = fastJson2JsonRedisSerializer();
+        redisTemplate.setValueSerializer(fastJson2JsonRedisSerializer);
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(fastJson2JsonRedisSerializer);
+        return redisTemplate;
+    }
+
+    /**
+     * 构建redisTemplate value使用jackson序列化
+     *
+     * @param factory
+     * @return
+     */
+    public RedisTemplate<String, Object> buildRedisTemplateByJackson(RedisConnectionFactory factory) {
+        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
+        redisTemplate.setConnectionFactory(factory);
+        // key的序列化类型 保证可读性
+        redisTemplate.setKeySerializer(new StringRedisSerializer());
+        //value的序列化类型 jackson 保证效率
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = jackson2JsonRedisSerializer();
+        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
+        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
+        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
+        return redisTemplate;
+    }
+
+    /**
+     * Jackson 序列化
+     *
+     * @return
+     */
+    public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
+        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
+        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
+        return jackson2JsonRedisSerializer;
+    }
+
+    /**
+     * FastJson 序列化
+     *
+     * @return
+     */
+    public FastJson2JsonRedisSerializer<Object> fastJson2JsonRedisSerializer() {
+        return new FastJson2JsonRedisSerializer(Object.class);
+    }
+}

+ 28 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/CommonCollectionUtils.java

@@ -0,0 +1,28 @@
+package com.tzld.piaoquan.ad.engine.commons.util;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author dyp
+ */
+public class CommonCollectionUtils {
+    public static <T, R> List<R> toList(List<T> list, Function<T, R> map) {
+        if (CollectionUtils.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        return list.stream().map(map).collect(Collectors.toList());
+    }
+
+    public static <T, K, V> Map<K, V> toMap(List<T> list, Function<T, K> keyFunc, Function<T, V> valueFunc) {
+        if (CollectionUtils.isEmpty(list)) {
+            return Collections.emptyMap();
+        }
+        return list.stream().collect(Collectors.toMap(keyFunc::apply, valueFunc::apply));
+    }
+}

+ 30 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/DateUtils.java

@@ -0,0 +1,30 @@
+package com.tzld.piaoquan.ad.engine.commons.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * @author dyp
+ */
+public final class DateUtils {
+    public static String getCurrentDateStr(String format) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+        Date currentDate = new Date();
+        return dateFormat.format(currentDate);
+    }
+
+    public static int getCurrentHour() {
+        Calendar calendar = Calendar.getInstance();
+        return calendar.get(Calendar.HOUR_OF_DAY);
+    }
+
+    public static String getBeforeDaysDateStr(String format, int d) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(new Date());
+        calendar.add(Calendar.DAY_OF_MONTH, -d);
+        Date previousDate = calendar.getTime();
+        return dateFormat.format(previousDate);
+    }
+}

+ 136 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/HttpClientFactory.java

@@ -0,0 +1,136 @@
+package com.tzld.piaoquan.ad.engine.commons.util;
+
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContexts;
+import org.slf4j.MDC;
+
+import javax.net.ssl.SSLContext;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class HttpClientFactory {
+
+    private static final ScheduledExecutorService SCHEDULED_CLOSED_EXECUTOR = new ScheduledThreadPoolExecutor(1,
+            new BasicThreadFactory.Builder().namingPattern("http conn-closed-thread-%s").priority(Thread.NORM_PRIORITY).daemon(false).build(), (r, e) -> log.error(" monitor push reject task error={}", e.toString()));
+
+    private static final List<HttpClientConnectionManager> HTTP_CLIENT_CONNECTION_MANAGERS = Lists.newArrayList();
+
+    static {
+        SCHEDULED_CLOSED_EXECUTOR.schedule(() -> HTTP_CLIENT_CONNECTION_MANAGERS.forEach(HttpClientConnectionManager::closeExpiredConnections), 5, TimeUnit.SECONDS);
+    }
+
+    private static HttpRequestInterceptor getInterceptor() {
+        HttpRequestInterceptor requestInterceptor = (request, context) -> {
+            try {
+                String missSpanId = MDC.get("missSpanId");
+                String missTraceId = MDC.get("request-id");
+                if (missTraceId != null && !"".equals(missTraceId.trim())) {
+                    request.setHeader("request-id", missTraceId);
+                }
+                if (missSpanId != null && !"".equals(missSpanId.trim())) {
+                    request.setHeader("missSpanId", missSpanId);
+                }
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+            }
+        };
+        return requestInterceptor;
+    }
+
+//    public String request(HttpRequestBase request) {
+//
+//        HttpEntity entity = null;
+//        try {
+//            log.info("request={}", JSONUtils.toJson(request));
+//            CloseableHttpResponse chr = request((HttpUriRequest) request);
+//            log.info("response={}", JSONUtils.toJson(chr));
+//            if (chr == null
+//                    || chr.getStatusLine() == null
+//                    || chr.getStatusLine().getStatusCode() != 200) {
+//                log.error("request failed http status exception!");
+//                return Strings.EMPTY;
+//            }
+//            entity = chr.getEntity();
+//            if (entity == null) {
+//                return Strings.EMPTY;
+//            }
+//            String content = EntityUtils.toString(entity, "UTF-8");
+//            log.info("response entity={}", JSONUtils.toJson(content));
+//        } catch (Exception e) {
+//            log.error("request error url={}", request.getURI().getPath(), e);
+//        } finally {
+//            if (request != null) {
+//                request.abort();
+//            }
+//            EntityUtils.consumeQuietly(entity);
+//        }
+//    }
+//
+//
+//    public CloseableHttpResponse request(HttpUriRequest request) {
+//        try {
+//            CloseableHttpResponse execute = closeableHttpClient.execute(request);
+//            return execute;
+//        } catch (Exception e) {
+//            log.error(String.format("http timeout request url = %s .", request.getURI().getPath()));
+//            throw new RuntimeException(e);
+//        }
+//    }
+
+    /**
+     * @param connectTimeout 连接超时时间 ms
+     * @param socketTimeout  读超时时间(等待数据超时时间)ms
+     * @param maxPerRoute    每个路由的最大连接数
+     * @param maxTotal       最大连接数
+     * @param retryCount     重试次数
+     * @return httpclient instance
+     */
+    public static CloseableHttpClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal,
+                                                int retryCount, int connectionWaitTimeout) {
+        try {
+            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).setConnectionRequestTimeout(connectionWaitTimeout).build();
+            CloseableHttpClient client = HttpClientBuilder.create()
+                    .setDefaultRequestConfig(requestConfig)
+                    .setConnectionManager(createConnectionManager(maxPerRoute, maxTotal))
+                    .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, false)).addInterceptorFirst(getInterceptor()).build();
+            return client;
+        } catch (Throwable e) {
+            log.error("create HttpPoolClient exception", e);
+            throw new RuntimeException("create HttpPoolClient exception");
+        }
+    }
+
+    private static PoolingHttpClientConnectionManager createConnectionManager(int maxPerRoute, int maxTotal) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build();
+        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
+                .register("http", PlainConnectionSocketFactory.getSocketFactory())
+                .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
+        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
+        cm.setDefaultMaxPerRoute(maxPerRoute);
+        cm.setMaxTotal(maxTotal);
+        HTTP_CLIENT_CONNECTION_MANAGERS.add(cm);
+        return cm;
+    }
+
+}

+ 38 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/JSONUtils.java

@@ -0,0 +1,38 @@
+package com.tzld.piaoquan.ad.engine.commons.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+@Slf4j
+public class JSONUtils {
+
+
+    public static String toJson(Object obj) {
+        if (obj == null) {
+            return "";
+        }
+        try {
+            return new Gson().toJson(obj);
+        } catch (Exception e) {
+            log.error("toJson exception", e);
+            return "";
+        }
+    }
+
+    public static <T> T fromJson(String value, TypeToken<T> typeToken, T defaultValue) {
+
+        if (StringUtils.isBlank(value)) {
+            return defaultValue;
+        }
+        try {
+            return JSONObject.parseObject(value, typeToken.getType());
+        } catch (Exception e) {
+            log.error("parseObject error! value=[{}]", value, e);
+        }
+        return defaultValue;
+    }
+
+}

+ 48 - 0
ad-engine-commons/src/main/java/com/tzld/piaoquan/ad/engine/commons/util/TraceUtils.java

@@ -0,0 +1,48 @@
+package com.tzld.piaoquan.ad.engine.commons.util;
+
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.MDC;
+
+import java.net.InetAddress;
+
+/**
+ * @author dyp
+ */
+public class TraceUtils {
+    public static final String TRACE_ID_KEY = "traceId";
+    public static final String DEFAULT_TRACE_ID = "default_trace_id";
+
+    public static void setMDC() {
+        MDC.put(TraceUtils.TRACE_ID_KEY, genTraceId());
+    }
+
+    public static void removeMDC() {
+        MDC.remove(TraceUtils.TRACE_ID_KEY);
+    }
+
+    public static String genTraceId() {
+        StringBuilder traceIdBuilder = new StringBuilder();
+        InetAddress address = InetAddress.getLoopbackAddress();
+        if (address == null) {
+            return DEFAULT_TRACE_ID;
+        }
+        String addressStr = address.getHostAddress();
+        if (StringUtils.isBlank(addressStr)) {
+            return DEFAULT_TRACE_ID;
+        }
+        String[] addressArr = addressStr.split("\\.");
+        if (addressArr.length != 4) {
+            return DEFAULT_TRACE_ID;
+        }
+
+        traceIdBuilder.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[0])), 2, '0'))
+                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[1])), 2, '0'))
+                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[2])), 2, '0'))
+                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[3])), 2, '0'))
+                .append(System.currentTimeMillis())
+                .append(RandomStringUtils.randomAlphabetic(4))
+                .append(Thread.currentThread().getId());
+        return traceIdBuilder.toString();
+    }
+}

+ 45 - 0
ad-engine-server/pom.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.tzld.piaoquan</groupId>
+        <artifactId>ad-engine</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <artifactId>ad-engine-server</artifactId>
+    <name>ad-engine-server</name>
+    <description>ad-engine-server</description>
+    <dependencies>
+        <dependency>
+            <groupId>com.tzld.piaoquan</groupId>
+            <artifactId>ad-engine-service</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <!-- 固定包名 避免随着版本变动 -->
+        <finalName>ad-engine</finalName>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <includes>
+                    <include>**/*.yml</include>
+                    <include>**/*.yaml</include>
+                    <include>**/*.xml</include>
+                    <include>**/*.properties</include>
+                </includes>
+                <filtering>false</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+
+    </build>
+
+</project>

+ 25 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/Application.java

@@ -0,0 +1,25 @@
+package com.tzld.piaoquan.ad.engine.server;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+/**
+ * https://github.com/grpc-swagger/grpc-swagger/blob/master/README_CN.md
+ */
+@SpringBootApplication
+@ComponentScan({
+        "com.tzld.piaoquan.recommend.server.service",
+        "com.tzld.piaoquan.recommend.server.grpcservice",
+        "com.tzld.piaoquan.recommend.server.config",
+        "com.tzld.piaoquan.recommend.server.web"
+})
+@EnableEurekaClient
+@EnableAspectJAutoProxy
+public class Application {
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+    }
+}

+ 28 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonCollectionUtils.java

@@ -0,0 +1,28 @@
+package com.tzld.piaoquan.ad.engine.server.util;
+
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author dyp
+ */
+public class CommonCollectionUtils {
+    public static <T, R> List<R> toList(List<T> list, Function<T, R> map) {
+        if (CollectionUtils.isEmpty(list)) {
+            return Collections.emptyList();
+        }
+        return list.stream().map(map).collect(Collectors.toList());
+    }
+
+    public static <T, K, V> Map<K, V> toMap(List<T> list, Function<T, K> keyFunc, Function<T, V> valueFunc) {
+        if (CollectionUtils.isEmpty(list)) {
+            return Collections.emptyMap();
+        }
+        return list.stream().collect(Collectors.toMap(keyFunc::apply, valueFunc::apply));
+    }
+}

+ 8 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/CommonTypeToken.java

@@ -0,0 +1,8 @@
+package com.tzld.piaoquan.ad.engine.server.util;
+
+import com.google.common.reflect.TypeToken;
+
+/**
+ * @author dyp
+ */
+

+ 30 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/DateUtils.java

@@ -0,0 +1,30 @@
+package com.tzld.piaoquan.ad.engine.server.util;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * @author dyp
+ */
+public final class DateUtils {
+    public static String getCurrentDateStr(String format) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+        Date currentDate = new Date();
+        return dateFormat.format(currentDate);
+    }
+
+    public static int getCurrentHour() {
+        Calendar calendar = Calendar.getInstance();
+        return calendar.get(Calendar.HOUR_OF_DAY);
+    }
+
+    public static String getBeforeDaysDateStr(String format, int d) {
+        SimpleDateFormat dateFormat = new SimpleDateFormat(format);
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(new Date());
+        calendar.add(Calendar.DAY_OF_MONTH, -d);
+        Date previousDate = calendar.getTime();
+        return dateFormat.format(previousDate);
+    }
+}

+ 136 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/HttpClientFactory.java

@@ -0,0 +1,136 @@
+package com.tzld.piaoquan.ad.engine.server.util;
+
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.SSLContexts;
+import org.slf4j.MDC;
+
+import javax.net.ssl.SSLContext;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+@Slf4j
+public class HttpClientFactory {
+
+    private static final ScheduledExecutorService SCHEDULED_CLOSED_EXECUTOR = new ScheduledThreadPoolExecutor(1,
+            new BasicThreadFactory.Builder().namingPattern("http conn-closed-thread-%s").priority(Thread.NORM_PRIORITY).daemon(false).build(), (r, e) -> log.error(" monitor push reject task error={}", e.toString()));
+
+    private static final List<HttpClientConnectionManager> HTTP_CLIENT_CONNECTION_MANAGERS = Lists.newArrayList();
+
+    static {
+        SCHEDULED_CLOSED_EXECUTOR.schedule(() -> HTTP_CLIENT_CONNECTION_MANAGERS.forEach(HttpClientConnectionManager::closeExpiredConnections), 5, TimeUnit.SECONDS);
+    }
+
+    private static HttpRequestInterceptor getInterceptor() {
+        HttpRequestInterceptor requestInterceptor = (request, context) -> {
+            try {
+                String missSpanId = MDC.get("missSpanId");
+                String missTraceId = MDC.get("request-id");
+                if (missTraceId != null && !"".equals(missTraceId.trim())) {
+                    request.setHeader("request-id", missTraceId);
+                }
+                if (missSpanId != null && !"".equals(missSpanId.trim())) {
+                    request.setHeader("missSpanId", missSpanId);
+                }
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+            }
+        };
+        return requestInterceptor;
+    }
+
+//    public String request(HttpRequestBase request) {
+//
+//        HttpEntity entity = null;
+//        try {
+//            log.info("request={}", JSONUtils.toJson(request));
+//            CloseableHttpResponse chr = request((HttpUriRequest) request);
+//            log.info("response={}", JSONUtils.toJson(chr));
+//            if (chr == null
+//                    || chr.getStatusLine() == null
+//                    || chr.getStatusLine().getStatusCode() != 200) {
+//                log.error("request failed http status exception!");
+//                return Strings.EMPTY;
+//            }
+//            entity = chr.getEntity();
+//            if (entity == null) {
+//                return Strings.EMPTY;
+//            }
+//            String content = EntityUtils.toString(entity, "UTF-8");
+//            log.info("response entity={}", JSONUtils.toJson(content));
+//        } catch (Exception e) {
+//            log.error("request error url={}", request.getURI().getPath(), e);
+//        } finally {
+//            if (request != null) {
+//                request.abort();
+//            }
+//            EntityUtils.consumeQuietly(entity);
+//        }
+//    }
+//
+//
+//    public CloseableHttpResponse request(HttpUriRequest request) {
+//        try {
+//            CloseableHttpResponse execute = closeableHttpClient.execute(request);
+//            return execute;
+//        } catch (Exception e) {
+//            log.error(String.format("http timeout request url = %s .", request.getURI().getPath()));
+//            throw new RuntimeException(e);
+//        }
+//    }
+
+    /**
+     * @param connectTimeout 连接超时时间 ms
+     * @param socketTimeout  读超时时间(等待数据超时时间)ms
+     * @param maxPerRoute    每个路由的最大连接数
+     * @param maxTotal       最大连接数
+     * @param retryCount     重试次数
+     * @return httpclient instance
+     */
+    public static CloseableHttpClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal,
+                                                int retryCount, int connectionWaitTimeout) {
+        try {
+            RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).setConnectionRequestTimeout(connectionWaitTimeout).build();
+            CloseableHttpClient client = HttpClientBuilder.create()
+                    .setDefaultRequestConfig(requestConfig)
+                    .setConnectionManager(createConnectionManager(maxPerRoute, maxTotal))
+                    .setRetryHandler(new DefaultHttpRequestRetryHandler(retryCount, false)).addInterceptorFirst(getInterceptor()).build();
+            return client;
+        } catch (Throwable e) {
+            log.error("create HttpPoolClient exception", e);
+            throw new RuntimeException("create HttpPoolClient exception");
+        }
+    }
+
+    private static PoolingHttpClientConnectionManager createConnectionManager(int maxPerRoute, int maxTotal) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
+        SSLContext sslContext = SSLContexts.custom().loadTrustMaterial((chain, authType) -> true).build();
+        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
+                .register("http", PlainConnectionSocketFactory.getSocketFactory())
+                .register("https", new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE)).build();
+        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
+        cm.setDefaultMaxPerRoute(maxPerRoute);
+        cm.setMaxTotal(maxTotal);
+        HTTP_CLIENT_CONNECTION_MANAGERS.add(cm);
+        return cm;
+    }
+
+}

+ 38 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/JSONUtils.java

@@ -0,0 +1,38 @@
+package com.tzld.piaoquan.ad.engine.server.util;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+@Slf4j
+public class JSONUtils {
+
+
+    public static String toJson(Object obj) {
+        if (obj == null) {
+            return "";
+        }
+        try {
+            return new Gson().toJson(obj);
+        } catch (Exception e) {
+            log.error("toJson exception", e);
+            return "";
+        }
+    }
+
+    public static <T> T fromJson(String value, TypeToken<T> typeToken, T defaultValue) {
+
+        if (StringUtils.isBlank(value)) {
+            return defaultValue;
+        }
+        try {
+            return JSONObject.parseObject(value, typeToken.getType());
+        } catch (Exception e) {
+            log.error("parseObject error! value=[{}]", value, e);
+        }
+        return defaultValue;
+    }
+
+}

+ 48 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/util/TraceUtils.java

@@ -0,0 +1,48 @@
+package com.tzld.piaoquan.ad.engine.server.util;
+
+import org.apache.commons.lang.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.MDC;
+
+import java.net.InetAddress;
+
+/**
+ * @author dyp
+ */
+public class TraceUtils {
+    public static final String TRACE_ID_KEY = "traceId";
+    public static final String DEFAULT_TRACE_ID = "default_trace_id";
+
+    public static void setMDC() {
+        MDC.put(TraceUtils.TRACE_ID_KEY, genTraceId());
+    }
+
+    public static void removeMDC() {
+        MDC.remove(TraceUtils.TRACE_ID_KEY);
+    }
+
+    public static String genTraceId() {
+        StringBuilder traceIdBuilder = new StringBuilder();
+        InetAddress address = InetAddress.getLoopbackAddress();
+        if (address == null) {
+            return DEFAULT_TRACE_ID;
+        }
+        String addressStr = address.getHostAddress();
+        if (StringUtils.isBlank(addressStr)) {
+            return DEFAULT_TRACE_ID;
+        }
+        String[] addressArr = addressStr.split("\\.");
+        if (addressArr.length != 4) {
+            return DEFAULT_TRACE_ID;
+        }
+
+        traceIdBuilder.append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[0])), 2, '0'))
+                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[1])), 2, '0'))
+                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[2])), 2, '0'))
+                .append(StringUtils.leftPad(Integer.toHexString(Integer.valueOf(addressArr[3])), 2, '0'))
+                .append(System.currentTimeMillis())
+                .append(RandomStringUtils.randomAlphabetic(4))
+                .append(Thread.currentThread().getId());
+        return traceIdBuilder.toString();
+    }
+}

+ 42 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/web/ControllerAspect.java

@@ -0,0 +1,42 @@
+package com.tzld.piaoquan.ad.engine.server.web;
+
+import com.google.common.base.Stopwatch;
+import com.tzld.piaoquan.ad.engine.server.util.TraceUtils;
+import com.tzld.piaoquan.ad.engine.server.util.JSONUtils;
+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.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author dyp
+ */
+@Aspect
+@Component
+@Slf4j
+public class ControllerAspect {
+
+    @Around("execution(* com.tzld.piaoquan.recommend.server.web.*Controller.*(..))")
+    public Object around(ProceedingJoinPoint pjp) throws Throwable {
+        TraceUtils.setMDC();
+
+        String className = pjp.getTarget().getClass().getSimpleName();
+        MethodSignature signature = (MethodSignature) pjp.getSignature();
+        Stopwatch stopwatch = Stopwatch.createStarted();
+        log.info("request className=[{}], method=[{}], param=[{}]", className, signature.getName(),
+                JSONUtils.toJson(pjp.getArgs()));
+        Object result = pjp.proceed();
+        if (result != null && result instanceof String) {
+            log.info("response result=[{}] cost=[{}]", result, stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
+        } else {
+            log.info("response result=[{}] cost=[{}]", JSONUtils.toJson(result), stopwatch.stop().elapsed(TimeUnit.MILLISECONDS));
+        }
+
+        TraceUtils.removeMDC();
+        return result;
+    }
+}

+ 94 - 0
ad-engine-server/src/main/java/com/tzld/piaoquan/ad/engine/server/web/RecommendController.java

@@ -0,0 +1,94 @@
+package com.tzld.piaoquan.ad.engine.server.web;
+
+import com.google.common.base.Strings;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.tzld.piaoquan.recommend.server.client.ProtobufUtils;
+import com.tzld.piaoquan.recommend.server.client.RecommendHttpRequest;
+import com.tzld.piaoquan.recommend.server.gen.recommend.RecommendRequest;
+import com.tzld.piaoquan.recommend.server.gen.recommend.RecommendResponse;
+import com.tzld.piaoquan.ad.engine.server.service.RecommendService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author dyp
+ */
+@RestController
+@Slf4j
+public class RecommendController {
+    @Autowired
+    private RecommendService recommendService;
+
+    @Bean
+    public ProtobufHttpMessageConverter protobufHttpMessageConverter() {
+        return new ProtobufHttpMessageConverter();
+    }
+
+    @RequestMapping("/homepage/recommend")
+    public String homepageRecommend(@RequestBody RecommendHttpRequest httpRequest) {
+        MDC.put("appType", String.valueOf(httpRequest.getAppType()));
+        RecommendResponse response = recommendService.homepageRecommend(generate(httpRequest));
+        String result = "";
+        try {
+            result = ProtobufUtils.toJson(response);
+        } catch (InvalidProtocolBufferException e) {
+            log.error("homepageRecommend ProtobufUtils.toJson", e);
+        }
+        return result;
+    }
+
+    @RequestMapping("/relevant/recommend")
+    public String relevantRecommend(@RequestBody RecommendHttpRequest httpRequest) {
+        MDC.put("appType", String.valueOf(httpRequest.getAppType()));
+
+        RecommendResponse response = recommendService.relevantRecommend(generate(httpRequest));
+        String result = "";
+        try {
+            result = ProtobufUtils.toJson(response);
+        } catch (InvalidProtocolBufferException e) {
+            log.error("relevantRecommend ProtobufUtils.toJson", e);
+        }
+        return result;
+    }
+
+    private RecommendRequest generate(RecommendHttpRequest httpRequest) {
+        if (httpRequest == null) {
+            return null;
+        }
+        RecommendRequest.Builder builder = RecommendRequest.newBuilder();
+
+        builder.setRequestId(Strings.nullToEmpty(httpRequest.getRequestId()))
+                .setMid(Strings.nullToEmpty(httpRequest.getMid()))
+                .setUid(Strings.nullToEmpty(httpRequest.getUid()))
+                .setSize(httpRequest.getSize())
+                .setAppType(httpRequest.getAppType())
+                .setCityCode(Strings.nullToEmpty(httpRequest.getCityCode()))
+                .setProvinceCode(Strings.nullToEmpty(httpRequest.getProvinceCode()))
+                .setVersionAuditStatus(httpRequest.getVersionAuditStatus())
+                .setRecommendTraceId(Strings.nullToEmpty(httpRequest.getRecommendTraceId()))
+                .setVideoId(httpRequest.getVideoId());
+
+        if (CollectionUtils.isNotEmpty(httpRequest.getAbExpCodes())) {
+            builder.addAllAbExpCode(httpRequest.getAbExpCodes());
+        }
+        if (MapUtils.isNotEmpty(httpRequest.getEventIdMap())) {
+            builder.putAllEventId(httpRequest.getEventIdMap());
+        }
+
+        return builder.build();
+    }
+
+    @GetMapping("/ok")
+    public String ok() {
+        return "ok";
+    }
+}

+ 181 - 0
ad-engine-server/src/main/resources/application-dev.yml

@@ -0,0 +1,181 @@
+server:
+  port: 8081
+
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: http://deveureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    jdbcUrl: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+  cloud:
+    sentinel:
+      transport:
+        dashboard: http://devsentinel-dashboard-internal.piaoquantv.com
+  adplatform:
+      jdbcUrl: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/adplatform?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+      #jdbcUrl: jdbc:mysql://rm-bp12k5fuh5zyx31d2.mysql.rds.aliyuncs.com:3306/adplatform?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+      username: wx2016_longvideo
+      password: wx2016_longvideoP@assword1234
+      #username: wx2023_ad
+      #password: wx2023_adP@assword1234
+
+  redis:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 8
+        max-wait: -1
+        max-idle: 8
+        min-idle: 0
+  redis-ad:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+  redis-algorithm:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
+  data:
+    mongodb:
+      uri:  mongodb://lv:lv2018@s-bp1cdbd0158506b4.mongodb.rds.aliyuncs.com:3717,s-bp1e404868527334.mongodb.rds.aliyuncs.com:3717/longvideo
+      adplatform-uri:  mongodb://lv:lv2018@s-bp1cdbd0158506b4.mongodb.rds.aliyuncs.com:3717,s-bp1e404868527334.mongodb.rds.aliyuncs.com:3717/longvideo
+      #adplatform-uri: mongodb://bigdata:Qingqu2019&@s-bp12258b064c3ef4.mongodb.rds.aliyuncs.com:3717,s-bp15728065fa22a4.mongodb.rds.aliyuncs.com:3717/longvideo
+
+  mail:
+    # 配置 SMTP 服务器地址
+    host: smtp.exmail.qq.com
+    # 发送者邮箱,已开通POP3/SMTP服务的邮箱,也就是你自己的
+    username: ad@new.piaoquantv.com
+    # 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
+    password: 5SCW5ndT4FP6XSmQ
+    # 发送人昵称
+    nickname: 票圈视频
+    # 端口号465或587(QQ邮箱发送邮件仅支持587端口协议)
+    port: 587
+    # 默认的邮件编码为UTF-8
+    default-encoding: UTF-8
+    # 配置SSL 加密工厂
+    properties:
+      mail:
+        smtp:
+          auth: true
+          socketFactoryClass: javax.net.ssl.SSLSocketFactory
+        #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
+        debug: true
+
+
+aliyun:
+  log:
+    project: ad-engine-test
+rocketmq:
+  accessKey: 736nKkR5Gaq0NAgU
+  secretKey: qGj5jxeXB87652MV
+  nameSrvAddr: rmq-cn-g4t3eq6k90g-vpc.cn-hangzhou.rmq.aliyuncs.com:8080
+  topic: topic_message_ad_user_behavior
+  groupId: GID_MESSAGE_AD_USER_BEHAVIOR
+  platform:
+    package:
+      topic: topic_message_platform_ad_package_test
+      groupId: GID_MESSAGE_PLATFORM_AD_PACKAGE_TEST
+  tag: '*'
+
+
+apollo:
+  meta: http://devapolloconfig-internal.piaoquantv.com
+
+springfox:
+  documentation:
+    swagger-ui:
+      enabled: true
+
+logging:
+  level:
+    org:
+      springframework:
+        data:
+          mongodb:
+            core:
+              MongoTemplate: DEBUG
+    com:
+      ctrip:
+        framework:
+          apollo:
+            internals:
+              RemoteConfigLongPollService: warn
+      tzld:
+        piaoquan:
+          ad: debug
+
+# 本地测试使用
+api-gateway:
+  feign:
+    url: https://testapi.piaoquantv.com
+
+longvideo:
+  feign:
+    url: videotest-internal.yishihui.com
+
+feign:
+  client:
+    config:
+      default:
+        # NONE 没有日志(默认)
+        # BASIC 只记录请求方法和 URL 以及响应状态码和执行时间
+        # HEADERS 记录基本信息以及请求和响应头
+        # FULL 记录请求和响应的头、正文和元数据
+        logger-level: FULL
+        connect-timeout: 20000
+        read-timeout: 20000
+
+feishu:
+  message:
+    # 飞书群组预警机器人 ID,不指定发送到 默认消息预警群组
+    bot-id: b5223f18-ff82-4cd4-9ae1-e88094da2cc6
+
+xxl:
+  job:
+    admin:
+      addresses: http://xxl-job-test-internal.piaoquantv.com/xxl-job-admin
+
+ms:
+  base:
+    getByIpUrl: http://testapi-internal.piaoquantv.com/base-service/region/getByIp
+
+oss:
+  adplatform:
+    accessKey: LTAIP6x1l3DXfSxm
+    secretKey: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    ossEndPoint: oss-cn-hangzhou.aliyuncs.com
+    videoEndPoint: slicevideo.yishihui.com
+    expiration: 3600
+    projectName: adplatform
+    cdnDomain: http://rescdn.yishihui.com/
+    imgDomain: http://rescdn.yishihui.com/
+    videoDomain: http://rescdn.yishihui.com/
+    lvvideoDomain: https://lvupload.piaoquantv.com/
+    pubBucket: public:art-pubbucket,publicVideo:art-pubbucket
+    priBucket: private:art-pribucket,privateVideo:art-privideo,privateVideoIn:art-privideo-in
+    priEndPoint: pricdn.yishihui.com
+    needPress: true
+    internal:
+      endPoint: oss-cn-hangzhou.aliyuncs.com
+    transcode:
+      TemplateId: 2a5bf5963c9347df8eaddf662fbaf357
+      PipelineId: abe6a0b9b9334858913eb416974485d2
+      Location: oss-cn-hangzhou
+      bucket: art-pubbucket

+ 155 - 0
ad-engine-server/src/main/resources/application-pre.yml

@@ -0,0 +1,155 @@
+server:
+  port: 8080
+
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: http://preeureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    jdbcUrl: jdbc:mysql://rm-bp1jjv3jv98133plv285-vpc-rw.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+  servlet:
+    multipart:
+      max-file-size: 500MB
+      max-request-size: 500MB
+
+  cloud:
+    sentinel:
+      transport:
+        dashboard: http://presentinel-dashboard-internal.piaoquantv.com
+  adplatform:
+    jdbcUrl: jdbc:mysql://rm-bp12k5fuh5zyx31d2.mysql.rds.aliyuncs.com:3306/adplatform?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+    username: wx2023_ad
+    password: wx2023_adP@assword1234
+
+  redis:
+    hostName: r-bp1oyhyx4mxgs6klyt561.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    lettuce:
+      pool:
+        max-active: 50 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0`
+
+  redis-ad:
+    hostName: r-bp1o145ofbhe3r1wma.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 50 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0`
+  redis-algorithm:
+    hostName: r-bp1fogs2mflr1ybfot.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+  data:
+    mongodb:
+      uri: mongodb://lv:lv2018@s-bp14ce206f81b754.mongodb.rds.aliyuncs.com:3717,s-bp137073555e7bc4.mongodb.rds.aliyuncs.com:3717/longvideo
+      adplatform-uri: mongodb://bigdata:Qingqu2019&@s-bp12258b064c3ef4.mongodb.rds.aliyuncs.com:3717,s-bp15728065fa22a4.mongodb.rds.aliyuncs.com:3717/adplatform
+  mail:
+    # 配置 SMTP 服务器地址
+    host: smtp.exmail.qq.com
+    # 发送者邮箱,已开通POP3/SMTP服务的邮箱,也就是你自己的
+    username: ad@new.piaoquantv.com
+    # 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
+    password: 5SCW5ndT4FP6XSmQ
+    # 发送人昵称
+    nickname: 票圈视频
+    # 端口号465或587(QQ邮箱发送邮件仅支持587端口协议)
+    port: 587
+    # 默认的邮件编码为UTF-8
+    default-encoding: UTF-8
+    # 配置SSL 加密工厂
+    properties:
+      mail:
+        smtp:
+          auth: true
+          socketFactoryClass: javax.net.ssl.SSLSocketFactory
+        #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
+        debug: true
+
+aliyun:
+  log:
+    project: ad-engine-pre
+
+rocketmq:
+  accessKey: 736nKkR5Gaq0NAgU
+  secretKey: qGj5jxeXB87652MV
+  nameSrvAddr: rmq-cn-g4t3eq6k90g-vpc.cn-hangzhou.rmq.aliyuncs.com:8080
+  topic: topic_message_ad_user_behavior_pre
+  groupId: GID_MESSAGE_AD_USER_BEHAVIOR_PRE
+  platform:
+    package:
+      topic: topic_message_platform_ad_package_pre
+      groupId: GID_MESSAGE_PLATFORM_AD_PACKAGE_PRE
+  tag: '*'
+
+apollo:
+  meta: http://preapolloconfig-internal.piaoquantv.com
+
+springfox:
+  documentation:
+    swagger-ui:
+      enabled: false
+
+xxl:
+  job:
+    admin:
+      addresses: http://xxl-job-pre-internal.piaoquantv.com/xxl-job-admin
+
+longvideo:
+  feign:
+    url: videopre-internal.piaoquantv.com
+
+feign:
+  client:
+    config:
+      default:
+        # NONE 没有日志(默认)
+        # BASIC 只记录请求方法和 URL 以及响应状态码和执行时间
+        # HEADERS 记录基本信息以及请求和响应头
+        # FULL 记录请求和响应的头、正文和元数据
+        logger-level: NONE
+        connect-timeout: 20000
+        read-timeout: 20000
+
+ms:
+  base:
+    getByIpUrl: http://preapi-internal.piaoquantv.com/base-service/region/getByIp
+
+oss:
+  adplatform:
+    accessKey: LTAIP6x1l3DXfSxm
+    secretKey: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    ossEndPoint: oss-cn-hangzhou.aliyuncs.com
+    videoEndPoint: slicevideo.yishihui.com
+    expiration: 3600
+    projectName: adplatform
+    cdnDomain: http://rescdn.yishihui.com/
+    imgDomain: http://rescdn.yishihui.com/
+    videoDomain: http://rescdn.yishihui.com/
+    lvvideoDomain: https://lvupload.piaoquantv.com/
+    pubBucket: public:art-pubbucket,publicVideo:art-pubbucket
+    priBucket: private:art-pribucket,privateVideo:art-privideo,privateVideoIn:art-privideo-in
+    priEndPoint: pricdn.yishihui.com
+    needPress: true
+    internal:
+      endPoint: oss-cn-hangzhou.aliyuncs.com
+    transcode:
+      TemplateId: 2a5bf5963c9347df8eaddf662fbaf357
+      PipelineId: abe6a0b9b9334858913eb416974485d2
+      Location: oss-cn-hangzhou
+      bucket: art-pubbucket

+ 157 - 0
ad-engine-server/src/main/resources/application-prod.yml

@@ -0,0 +1,157 @@
+server:
+  port: 8080
+
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: http://eureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    jdbcUrl: jdbc:mysql://rm-bp1jjv3jv98133plv285-vpc-rw.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+  servlet:
+    multipart:
+      max-file-size: 500MB
+      max-request-size: 500MB
+
+  cloud:
+    sentinel:
+      transport:
+        dashboard: http://sentinel-dashboard-internal.piaoquantv.com
+
+  adplatform:
+    jdbcUrl: jdbc:mysql://rm-bp12k5fuh5zyx31d2.mysql.rds.aliyuncs.com:3306/adplatform?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+    username: wx2023_ad
+    password: wx2023_adP@assword1234
+
+  redis:
+    hostName: r-bp1oyhyx4mxgs6klyt561.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    lettuce:
+      pool:
+        max-active: 200 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
+  redis-ad:
+    hostName: r-bp1o145ofbhe3r1wma.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+  redis-algorithm:
+    hostName: r-bp1fogs2mflr1ybfot.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+
+  data:
+    mongodb:
+      uri: mongodb://lv:lv2018@s-bp14ce206f81b754.mongodb.rds.aliyuncs.com:3717,s-bp137073555e7bc4.mongodb.rds.aliyuncs.com:3717/longvideo
+      adplatform-uri: mongodb://bigdata:Qingqu2019&@s-bp12258b064c3ef4.mongodb.rds.aliyuncs.com:3717,s-bp15728065fa22a4.mongodb.rds.aliyuncs.com:3717/adplatform
+  mail:
+    # 配置 SMTP 服务器地址
+    host: smtp.exmail.qq.com
+    # 发送者邮箱,已开通POP3/SMTP服务的邮箱,也就是你自己的
+    username: ad@new.piaoquantv.com
+    # 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
+    password: 5SCW5ndT4FP6XSmQ
+    # 发送人昵称
+    nickname: 票圈视频
+    # 端口号465或587(QQ邮箱发送邮件仅支持587端口协议)
+    port: 587
+    # 默认的邮件编码为UTF-8
+    default-encoding: UTF-8
+    # 配置SSL 加密工厂
+    properties:
+      mail:
+        smtp:
+          auth: true
+          socketFactoryClass: javax.net.ssl.SSLSocketFactory
+        #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
+        debug: true
+
+rocketmq:
+  accessKey: 736nKkR5Gaq0NAgU
+  secretKey: qGj5jxeXB87652MV
+  nameSrvAddr: rmq-cn-g4t3eq6k90g-vpc.cn-hangzhou.rmq.aliyuncs.com:8080
+  topic: topic_message_ad_user_behavior_prod
+  groupId: GID_MESSAGE_AD_USER_BEHAVIOR_PROD
+  platform:
+    package:
+      topic: topic_message_platform_ad_package_prod
+      groupId: GID_MESSAGE_PLATFORM_AD_PACKAGE_PROD
+  tag: '*'
+
+aliyun:
+  log:
+    project: ad-engine
+
+apollo:
+  meta: http://apolloconfig-internal.piaoquantv.com
+
+springfox:
+  documentation:
+    swagger-ui:
+      enabled: false
+
+xxl:
+  job:
+    admin:
+      addresses: http://xxl-job-internal.piaoquantv.com/xxl-job-admin
+
+longvideo:
+  feign:
+    url: longvideoapi-internal.piaoquantv.com
+
+feign:
+  client:
+    config:
+      default:
+        # NONE 没有日志(默认)
+        # BASIC 只记录请求方法和 URL 以及响应状态码和执行时间
+        # HEADERS 记录基本信息以及请求和响应头
+        # FULL 记录请求和响应的头、正文和元数据
+        logger-level: NONE
+        connect-timeout: 20000
+        read-timeout: 20000
+
+ms:
+  base:
+    getByIpUrl: http://api-internal.piaoquantv.com/base-service/region/getByIp
+
+oss:
+  adplatform:
+    accessKey: LTAIP6x1l3DXfSxm
+    secretKey: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    ossEndPoint: oss-cn-hangzhou.aliyuncs.com
+    videoEndPoint: slicevideo.yishihui.com
+    expiration: 3600
+    projectName: adplatform
+    cdnDomain: http://rescdn.yishihui.com/
+    imgDomain: http://rescdn.yishihui.com/
+    videoDomain: http://rescdn.yishihui.com/
+    lvvideoDomain: https://lvupload.piaoquantv.com/
+    pubBucket: public:art-pubbucket,publicVideo:art-pubbucket
+    priBucket: private:art-pribucket,privateVideo:art-privideo,privateVideoIn:art-privideo-in
+    priEndPoint: pricdn.yishihui.com
+    needPress: true
+    internal:
+      endPoint: oss-cn-hangzhou.aliyuncs.com
+    transcode:
+      TemplateId: 2a5bf5963c9347df8eaddf662fbaf357
+      PipelineId: abe6a0b9b9334858913eb416974485d2
+      Location: oss-cn-hangzhou
+      bucket: art-pubbucket

+ 150 - 0
ad-engine-server/src/main/resources/application-test.yml

@@ -0,0 +1,150 @@
+server:
+  port: 8080
+
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: http://testeureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    jdbcUrl: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+  adplatform:
+    jdbcUrl: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/adplatform?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowMultiQueries=true
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+  servlet:
+    multipart:
+      max-file-size: 500MB
+      max-request-size: 500MB
+
+  cloud:
+    sentinel:
+      transport:
+        dashboard: http://testsentinel-dashboard-internal.piaoquantv.com
+  redis:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 8
+        max-wait: -1
+        max-idle: 8
+        min-idle: 0
+  redis-ad:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+  redis-algorithm:
+    hostName: r-bp1ps6my7lzg8rdhwx682.redis.rds.aliyuncs.com
+    port: 6379
+    password: Wqsd@2019
+    timeout: 1000
+    lettuce:
+      pool:
+        max-active: 1000 # 连接池最大连接数(使用负值表示没有限制) 默认 8
+        max-idle: 20 # 连接池中的最大空闲连接 默认 8
+        min-idle: 10 # 连接池中的最小空闲连接 默认 0
+  data:
+    mongodb:
+      uri: mongodb://lv:lv2018@s-bp1cdbd0158506b4.mongodb.rds.aliyuncs.com:3717,s-bp1e404868527334.mongodb.rds.aliyuncs.com:3717/longvideo
+      adplatform-uri: mongodb://bigdata:Qingqu2019&@s-bp12258b064c3ef4.mongodb.rds.aliyuncs.com:3717,s-bp15728065fa22a4.mongodb.rds.aliyuncs.com:3717/adplatform_test
+  mail:
+    # 配置 SMTP 服务器地址
+    host: smtp.exmail.qq.com
+    # 发送者邮箱,已开通POP3/SMTP服务的邮箱,也就是你自己的
+    username: ad@new.piaoquantv.com
+    # 配置密码,注意不是真正的密码,而是刚刚申请到的授权码
+    password: 5SCW5ndT4FP6XSmQ
+    # 发送人昵称
+    nickname: 票圈视频
+    # 端口号465或587(QQ邮箱发送邮件仅支持587端口协议)
+    port: 587
+    # 默认的邮件编码为UTF-8
+    default-encoding: UTF-8
+    # 配置SSL 加密工厂
+    properties:
+      mail:
+        smtp:
+          auth: true
+          socketFactoryClass: javax.net.ssl.SSLSocketFactory
+        #表示开启 DEBUG 模式,这样,邮件发送过程的日志会在控制台打印出来,方便排查错误
+        debug: true
+
+rocketmq:
+  accessKey: 736nKkR5Gaq0NAgU
+  secretKey: qGj5jxeXB87652MV
+  nameSrvAddr: rmq-cn-g4t3eq6k90g-vpc.cn-hangzhou.rmq.aliyuncs.com:8080
+  topic: topic_message_ad_user_behavior_test
+  groupId: GID_MESSAGE_AD_USER_BEHAVIOR_TEST
+  platform:
+    package:
+      topic: topic_message_platform_ad_package_test
+      groupId: GID_MESSAGE_PLATFORM_AD_PACKAGE_TEST
+  tag: '*'
+
+aliyun:
+  log:
+    project: ad-engine
+
+apollo:
+  meta: http://testapolloconfig-internal.piaoquantv.com
+
+springfox:
+  documentation:
+    swagger-ui:
+      enabled: true
+
+xxl:
+  job:
+    admin:
+      addresses: http://xxl-job-test-internal.piaoquantv.com/xxl-job-admin
+
+longvideo:
+  feign:
+    url: videotest-internal.yishihui.com
+
+feign:
+  client:
+    config:
+      default:
+        # NONE 没有日志(默认)
+        # BASIC 只记录请求方法和 URL 以及响应状态码和执行时间
+        # HEADERS 记录基本信息以及请求和响应头
+        # FULL 记录请求和响应的头、正文和元数据
+        logger-level: FULL
+        connect-timeout: 20000
+        read-timeout: 20000
+
+ms:
+  base:
+    getByIpUrl: http://testapi-internal.piaoquantv.com/base-service/region/getByIp
+
+oss:
+  adplatform:
+    accessKey: LTAIP6x1l3DXfSxm
+    secretKey: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    ossEndPoint: oss-cn-hangzhou.aliyuncs.com
+    videoEndPoint: slicevideo.yishihui.com
+    expiration: 3600
+    projectName: adplatform
+    cdnDomain: http://rescdn.yishihui.com/
+    imgDomain: http://rescdn.yishihui.com/
+    videoDomain: http://rescdn.yishihui.com/
+    lvvideoDomain: https://lvupload.piaoquantv.com/
+    pubBucket: public:art-pubbucket,publicVideo:art-pubbucket
+    priBucket: private:art-pribucket,privateVideo:art-privideo,privateVideoIn:art-privideo-in
+    priEndPoint: pricdn.yishihui.com
+    needPress: true
+    internal:
+      endPoint: oss-cn-hangzhou.aliyuncs.com
+    transcode:
+      TemplateId: 2a5bf5963c9347df8eaddf662fbaf357
+      PipelineId: abe6a0b9b9334858913eb416974485d2
+      Location: oss-cn-hangzhou
+      bucket: art-pubbucket

+ 122 - 0
ad-engine-server/src/main/resources/application.yml

@@ -0,0 +1,122 @@
+eureka:
+  instance:
+    prefer-ip-address: true #是否优先使用IP地址作为主机名的标识,默认false
+    instance-id: ${spring.cloud.client.ip-address}:${spring.application.name}:${server.port} #注册到eureka上的唯一实例ID
+    lease-renewal-interval-in-seconds: 10 #表示eureka client发送心跳给server端的频率,默认30
+    lease-expiration-duration-in-seconds: 30 #表示eureka server至上一次收到client的心跳之后,等待下一次心跳的超时时间,在这个时间内若没收到下一次心跳,则将移除该instance,默认90
+  client:
+    registry-fetch-interval-seconds: 5  #定时从Eureka Server拉取服务注册信息的间隔时间
+
+spring:
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 10
+      maximum-pool-size: 60
+      connection-test-query: SELECT 1
+  cloud:
+    sentinel:
+      eager: true
+      transport:
+        port: 8719
+      log:
+        dir: ${datalog}/sentinel
+      datasource:
+        ds1:
+          apollo:
+            namespace-name: application
+            flow-rules-key: sentinel.flowRules
+            default-flow-rule-value: [ ]
+            rule-type: flow
+
+  profiles:
+    active: dev
+  application:
+    name: ad
+  jackson:
+    default-property-inclusion: non_null
+  servlet:
+    multipart:
+      max-file-size: 500MB
+      max-request-size: 500MB
+project:
+  name: ad-engine
+
+server:
+  tomcat:
+    threads:
+      max: 1000
+    uri-encoding: UTF-8
+    accept-count: 1000
+    connection-timeout: 30000
+  servlet:
+    context-path: /ad
+    session:
+      timeout: 60
+pagehelper:
+  helper-dialect: mysql
+
+#apollo config
+app:
+  id: ad
+
+apollo:
+  bootstrap:
+    enabled: true
+    namespaces: application
+    eagerLoad:
+      enabled: true
+  cacheDir: ${datalog}/apollo-cache-dir
+
+mybatis:
+  type-aliases-package: com.tzld.piaoquan.ad.model.po
+  mapper-locations: classpath:mapper/*.xml, classpath:mapper/ext/*.xml
+  configuration:
+    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
+
+#datalog: /datalog
+datalog: /Users/gufengshou/Documents/yiqi_project
+
+logging:
+  file:
+    path: ${datalog}/weblog/${project.name}
+
+aliyun:
+  log:
+    endpoint: cn-hangzhou.log.aliyuncs.com
+    accessKeyId: LTAIP6x1l3DXfSxm
+    accessKeySecret: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    logstore:
+      request: request-log
+      info: info-log
+      error: error-log
+      landingTypeFilter: landingpagetype-filter-error-log
+      adPackageData: ad-package-data
+    topic:
+    threadpool:
+      corePoolSize: 100
+      maxPoolSize: 100
+      keepAliveSeconds: 200
+      queueCapacity: 100000
+
+feishu:
+  message:
+    # 飞书群组预警机器人 ID,不指定发送到 默认消息预警群组
+    bot-id: a73cd47d-70b8-4b73-a207-a133021af176
+    # 要提醒用户的手机号(多个值用 “,” 隔开)
+    at-mobiles: 18612832316
+    # 飞书预警服务器地址
+    server-url: http://alert-feishu.piaoquantv.com/feishu/sendText
+
+
+xxl:
+  job:
+    accessToken:
+    executor:
+      address:
+      appname: ms-${spring.application.name}
+      ip:
+      logpath: ${datalog}/xxl-job/
+      logretentiondays: 30
+      port: 9999

+ 115 - 0
ad-engine-server/src/main/resources/dynamic-datasource-mybatis.xml

@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                        http://www.springframework.org/schema/beans/spring-beans.xsd
+                        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
+
+
+
+    <bean id="dataSourceAdplatform" class="com.alibaba.druid.pool.DruidDataSource"
+        init-method="init" destroy-method="close">
+
+        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
+        <property name="url" value="${spring.adplatform.jdbcUrl}" />
+        <property name="username" value="wx2016_longvideo" />
+        <property name="password" value="wx2016_longvideoP@assword1234" />
+        <property name="maxActive" value="20" />
+        <property name="initialSize" value="1" />
+        <property name="maxWait" value="60000" />
+        <property name="minIdle" value="3" />
+        <property name="connectionProperties" value="config.decrypt=true;clientEncoding=UTF-8" />
+        <property name="connectionInitSqls" value="set names utf8mb4;" />
+        <property name="filters" value="stat" />
+        <property name="timeBetweenEvictionRunsMillis" value="600000" />
+        <property name="minEvictableIdleTimeMillis" value="300000" />
+        <property name="validationQuery" value="select 1" />
+        <property name="testWhileIdle" value="true" />
+        <property name="testOnBorrow" value="false" />
+        <property name="testOnReturn" value="false" />
+        <property name="maxOpenPreparedStatements" value="20" />
+        <property name="removeAbandoned" value="true" />
+        <property name="removeAbandonedTimeout" value="1800" />
+        <property name="logAbandoned" value="true" />
+    </bean>
+
+    <bean id="dataSourceOriginal" class="com.alibaba.druid.pool.DruidDataSource"
+          init-method="init" destroy-method="close">
+
+        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
+        <property name="url" value="${spring.datasource.jdbcUrl}" />
+        <property name="username" value="${spring.datasource.username}" />
+        <property name="password" value="${spring.datasource.password}" />
+        <property name="maxActive" value="20" />
+        <property name="initialSize" value="1" />
+        <property name="maxWait" value="60000" />
+        <property name="minIdle" value="3" />
+        <property name="connectionProperties" value="config.decrypt=true;clientEncoding=UTF-8" />
+        <property name="connectionInitSqls" value="set names utf8mb4;" />
+        <property name="filters" value="stat" />
+        <property name="timeBetweenEvictionRunsMillis" value="600000" />
+        <property name="minEvictableIdleTimeMillis" value="300000" />
+        <property name="validationQuery" value="select 1" />
+        <property name="testWhileIdle" value="true" />
+        <property name="testOnBorrow" value="false" />
+        <property name="testOnReturn" value="false" />
+        <property name="maxOpenPreparedStatements" value="20" />
+        <property name="removeAbandoned" value="true" />
+        <property name="removeAbandonedTimeout" value="1800" />
+        <property name="logAbandoned" value="true" />
+    </bean>
+
+    <!--动态数据源的配置-->
+    <bean id="dynamicDataSource" class=" com.tzld.piaoquan.ad.datasource.DynamicDataSource">
+        <property name="targetDataSources">
+            <map key-type="java.lang.String">
+                <entry key="dataSourceAdplatform"  value-ref="dataSourceAdplatform" />
+                <entry key="dataSourceOriginal"  value-ref="dataSourceOriginal" />
+            </map>
+        </property>
+    </bean>
+    
+    <bean id="dataSourceChangeAspect" class="com.tzld.piaoquan.ad.datasource.DataSourceAspect">
+        <property name="defaultDataSource" value="dataSourceOriginal"></property>
+        <property name="targetDataSources">
+            <map key-type="java.lang.String">
+                <entry key="dataSourceAdplatform" value="dataSourceAdplatform"/>
+                <entry key="dataSourceOriginal" value="dataSourceOriginal"/>
+            </map>
+        </property>
+    </bean>
+
+    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
+        <property name="dataSource" ref="dynamicDataSource" />
+        <property name="configLocation" value="classpath:mybatis-config.xml" />
+        <property name="mapperLocations" value="classpath:mapper/**/*.xml" />
+    </bean>
+
+    <!-- 指定Mapper接口所在的包 -->
+    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
+        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
+        <property name="basePackage" value="com.tzld.piaoquan.ad.dao.mapper" />
+    </bean>
+
+
+    <!-- 指定事务-->
+    <bean id="transactionManager"  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
+        <property name="dataSource" ref="dynamicDataSource" />
+    </bean>
+
+    <!-- 一定要在事务之前切换数据源,不然则会失效-->
+    <aop:config>
+        <aop:pointcut id="serviceAop"  expression="execution(* com.tzld.piaoquan.ad.service..*.*(..))" />
+        <aop:aspect ref="dataSourceChangeAspect" order="0">
+            <aop:before method="doBefore" pointcut-ref="serviceAop"/>
+            <aop:after-returning method="doAfterReturning" pointcut-ref="serviceAop"/>
+        </aop:aspect>
+    </aop:config>
+
+    <!--配置事务模板对象     编程式事务 模板-->
+    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
+        <property name="transactionManager" ref="transactionManager"/>
+    </bean>
+
+</beans>

+ 276 - 0
ad-engine-server/src/main/resources/logback-spring.xml

@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,如果设置为WARN,则低于WARN的信息都不会输出 -->
+<!-- scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true -->
+<!-- scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
+<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
+<configuration scan="true" scanPeriod="10 seconds">
+    <!--<include resource="org/springframework/boot/logging/logback/base.xml"/>-->
+
+    <contextName>logback</contextName>
+    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
+    <!-- <property name="LOG_PATH"  value="${logging.file.path}" />-->
+
+    <springProperty name="LOG_PATH" source="logging.file.path"/>
+    <springProperty name="ALIYUN_LOG_ENDPOINT" source="aliyun.log.endpoint"/>
+    <springProperty name="ALIYUN_LOG_ACCESSKEYID" source="aliyun.log.accessKeyId"/>
+    <springProperty name="ALIYUN_LOG_ACCESSKEYSECRET" source="aliyun.log.accessKeySecret"/>
+    <springProperty name="ALIYUN_LOG_PROJECT" source="aliyun.log.project"/>
+    <springProperty name="ALIYUN_LOG_LOGSTORE_INFO" source="aliyun.log.logstore.info"/>
+    <springProperty name="ALIYUN_LOG_LOGSTORE_ERROR" source="aliyun.log.logstore.error"/>
+
+    <!-- 彩色日志 -->
+    <!-- 彩色日志依赖的渲染类 -->
+    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
+    <conversionRule conversionWord="wex"
+                    converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
+    <conversionRule conversionWord="wEx"
+                    converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
+    <!-- 彩色日志格式 -->
+    <property name="CONSOLE_LOG_PATTERN"
+              value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%X{logTraceId}]){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>
+    <!--<property name="CONSOLE_LOG_PATTERN"-->
+    <!--          value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr([%X{√logTraceId}]){magenta} %clr(-&#45;&#45;){faint} %clr([%15.15t]){faint} %clr(at %class.%method){cyan} \\(%file:%line\\) %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>-->
+
+    <!--输出到控制台-->
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>debug</level>
+        </filter>
+        <encoder>
+            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
+            <!-- 设置字符集 -->
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+
+    <!--输出到文件-->
+    <!-- 时间滚动输出 level为 DEBUG 日志 -->
+    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/debug.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{logTraceId}] %logger{50} [%L] - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志归档 -->
+            <fileNamePattern>${LOG_PATH}/debug/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录debug级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>debug</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 时间滚动输出 level为 INFO 日志 -->
+    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/info.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{logTraceId}] %logger{50} [%L] - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 每天日志归档路径以及格式 -->
+            <fileNamePattern>${LOG_PATH}/info/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录info级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>info</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 时间滚动输出 level为 WARN 日志 -->
+    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/warn.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{logTraceId}] %logger{50} [%L] - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/warn/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录warn级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>warn</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <!-- 时间滚动输出 level为 ERROR 日志 -->
+    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- 正在记录的日志文件的路径及文件名 -->
+        <file>${LOG_PATH}/error.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{logTraceId}] %logger{50} [%L] - %msg%n</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/error/%d{yyyy-MM-dd}.%i.log</fileNamePattern>
+            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
+                <maxFileSize>100MB</maxFileSize>
+            </timeBasedFileNamingAndTriggeringPolicy>
+            <!--日志文件保留天数-->
+            <maxHistory>15</maxHistory>
+        </rollingPolicy>
+        <!-- 此日志文件只记录ERROR级别的 -->
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="ALIYUN_LOG_INFO" class="com.aliyun.openservices.log.logback.LoghubAppender">
+        <endpoint>${ALIYUN_LOG_ENDPOINT}</endpoint>
+        <accessKeyId>${ALIYUN_LOG_ACCESSKEYID}</accessKeyId>
+        <accessKeySecret>${ALIYUN_LOG_ACCESSKEYSECRET}</accessKeySecret>
+        <project>${ALIYUN_LOG_PROJECT}</project>
+        <logStore>${ALIYUN_LOG_LOGSTORE_INFO}</logStore>
+
+        <totalSizeInBytes>104857600</totalSizeInBytes>
+        <maxBlockMs>0</maxBlockMs>
+        <ioThreadCount>8</ioThreadCount>
+        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes>
+        <batchCountThreshold>4096</batchCountThreshold>
+        <lingerMs>2000</lingerMs>
+        <retries>10</retries>
+        <baseRetryBackoffMs>100</baseRetryBackoffMs>
+        <maxRetryBackoffMs>50000</maxRetryBackoffMs>
+
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{logTraceId}] %logger{50} [%L] - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+
+        <timeFormat>yyyy-MM-dd'T'HH:mmZ</timeFormat>
+        <timeZone>Asia/Shanghai</timeZone>
+
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+        </filter>
+
+        <mdcFields>logTraceId</mdcFields>
+    </appender>
+
+    <appender name="ALIYUN_LOG_ERROR" class="com.aliyun.openservices.log.logback.LoghubAppender">
+        <endpoint>${ALIYUN_LOG_ENDPOINT}</endpoint>
+        <accessKeyId>${ALIYUN_LOG_ACCESSKEYID}</accessKeyId>
+        <accessKeySecret>${ALIYUN_LOG_ACCESSKEYSECRET}</accessKeySecret>
+        <project>${ALIYUN_LOG_PROJECT}</project>
+        <logStore>${ALIYUN_LOG_LOGSTORE_ERROR}</logStore>
+
+        <totalSizeInBytes>104857600</totalSizeInBytes>
+        <maxBlockMs>0</maxBlockMs>
+        <ioThreadCount>8</ioThreadCount>
+        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes>
+        <batchCountThreshold>4096</batchCountThreshold>
+        <lingerMs>2000</lingerMs>
+        <retries>10</retries>
+        <baseRetryBackoffMs>100</baseRetryBackoffMs>
+        <maxRetryBackoffMs>50000</maxRetryBackoffMs>
+
+        <encoder>
+            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{logTraceId}] %logger{50} [%L] - %msg%n</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+
+        <timeFormat>yyyy-MM-dd'T'HH:mmZ</timeFormat>
+        <timeZone>Asia/Shanghai</timeZone>
+
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>ERROR</level>
+        </filter>
+
+        <mdcFields>logTraceId</mdcFields>
+    </appender>
+
+    <!--
+        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。
+        <logger>仅有一个name属性,一个可选的level和一个可选的addtivity属性。
+        name:用来指定受此logger约束的某一个包或者具体的某一个类。
+        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
+              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
+              如果未设置此属性,那么当前logger将会继承上级的级别。
+        addtivity:是否向上级logger传递打印信息。默认是true。
+    -->
+    <!--<logger name="org.springframework.web" level="info"/>-->
+    <!--<logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>-->
+
+    <!--
+        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
+        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
+        第二种就是单独给dao下目录配置 <logger> 指定 level 属性为 debug,这样配置sql语句会打印,其他还是正常info级别:
+     -->
+
+    <!--<springProfile name="dev">-->
+    <!--    <logger name="com.tzld.piaoquan.ad" level="debug"/>-->
+    <!--    <logger name="com.ctrip.framework.apollo.internals.RemoteConfigLongPollService" level="error"/>-->
+    <!--</springProfile>-->
+    <!--<springProfile name="test">-->
+    <!--    <logger name="com.tzld.piaoquan.ad" level="info"/>-->
+    <!--</springProfile>-->
+    <!--<springProfile name="pre">-->
+    <!--    <logger name="com.tzld.piaoquan.ad" level="info"/>-->
+    <!--</springProfile>-->
+    <!--<springProfile name="stress">-->
+    <!--    <logger name="com.tzld.piaoquan.ad" level="info"/>-->
+    <!--</springProfile>-->
+    <!--<springProfile name="prod">-->
+    <!--    <logger name="com.tzld.piaoquan.ad" level="info"/>-->
+    <!--</springProfile>-->
+    <!--<logger name="com.netflix.discovery.shared.resolver.aws.ConfigClusterResolver" level="warn"/>-->
+
+    <!-- 可用来获取 StatusManager 中的状态 -->
+    <!--<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener"/>-->
+    <!-- 解决 aliyun loghub debug模式下循环发送的问题 -->
+    <logger name="org.apache.http.impl.conn.Wire" level="WARN"/>
+    <!--aliyun loghub 为了防止进程退出时,内存中的数据丢失,请加上此选项-->
+    <shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
+
+    <!--
+        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
+        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
+        不能设置为INHERITED或者同义词NULL。默认是DEBUG
+        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
+    -->
+    <root level="info">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="DEBUG_FILE"/>
+        <appender-ref ref="INFO_FILE"/>
+        <appender-ref ref="WARN_FILE"/>
+        <appender-ref ref="ERROR_FILE"/>
+        <appender-ref ref="ALIYUN_LOG_INFO"/>
+        <appender-ref ref="ALIYUN_LOG_ERROR"/>
+    </root>
+</configuration>

+ 13 - 0
ad-engine-server/src/main/resources/mybatis-config.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
+        "http://mybatis.org/dtd/mybatis-3-config.dtd">
+<configuration>
+    <properties>
+        <property name="dialect" value="mysql"/>
+    </properties>
+    <settings>
+        <!--<setting name="logImpl" value="LOG4J"/>-->
+        <setting name="mapUnderscoreToCamelCase" value="true" />
+        <!--<setting name="logImpl" value="STDOUT_LOGGING" />-->
+    </settings>
+</configuration>

+ 27 - 0
ad-engine-service/pom.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.tzld.piaoquan</groupId>
+        <artifactId>ad-engine</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>ad-engine-service</artifactId>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.tzld.piaoquan</groupId>
+            <artifactId>ad-engine-commons</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+    </dependencies>
+</project>

+ 4 - 0
ad-engine-service/src/main/java/com/tzld/piaoquan/ad/engine/service/rank/RankService.java

@@ -0,0 +1,4 @@
+package com.tzld.piaoquan.ad.engine.service.rank;
+
+public interface RankService {
+}

+ 294 - 0
pom.xml

@@ -0,0 +1,294 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>pom</packaging>
+    <parent>
+        <groupId>com.tzld.commons</groupId>
+        <artifactId>supom</artifactId>
+        <version>1.0.9</version>
+    </parent>
+    <groupId>com.tzld.piaoquan</groupId>
+    <artifactId>ad-engine</artifactId>
+    <version>1.0.0</version>
+    <name>ad-engine</name>
+    <description>ad-engine</description>
+    
+    <modules>
+        <module>ad-engine-server</module>
+        <module>ad-engine-commons</module>
+        <module>ad-engine-service</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mybatis.generator</groupId>
+            <artifactId>mybatis-generator-core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-boot-starter</artifactId>
+            <version>3.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger2</artifactId>
+            <version>3.0.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-swagger-ui</artifactId>
+            <version>3.0.0</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpmime</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.ctrip.framework.apollo</groupId>
+            <artifactId>apollo-client</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.tzld.commons</groupId>
+            <artifactId>aliyun-log-spring-boot-starter</artifactId>
+            <version>2.0.0</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>aliyun-log</artifactId>
+                    <groupId>com.aliyun.openservices</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun.openservices</groupId>
+            <artifactId>aliyun-log-logback-appender</artifactId>
+            <version>0.1.18</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.piaoquantv.commons</groupId>
+            <artifactId>feishu-message-starter</artifactId>
+            <version>0.0.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.csp</groupId>
+            <artifactId>sentinel-datasource-apollo</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-openfeign</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>31.1-jre</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.xuxueli</groupId>
+            <artifactId>xxl-job-core</artifactId>
+        </dependency>
+
+        <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+            <version>3.14.9</version>
+        </dependency>
+
+        <!-- lombok -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.12</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun.openservices</groupId>
+            <artifactId>ons-client</artifactId>
+            <version>${aliyun.rocketmq.version}</version>
+        </dependency>
+        <!-- druid数据源 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.1.23</version>
+        </dependency>
+        <!--<dependency>-->
+        <!--<groupId>com.googlecode.aviator</groupId>-->
+        <!--<artifactId>aviator</artifactId>-->
+        <!--</dependency>-->
+        <dependency>
+            <groupId>com.stuuudy.commons</groupId>
+            <artifactId>commons-external</artifactId>
+            <version>1.0-SNAPSHOT</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>jedis</artifactId>
+                    <groupId>redis.clients</groupId>
+                </exclusion>
+                <!-- aliyun-long-0.6.8 不兼容 aliyun-log-logback-appender-->
+                <exclusion>
+                    <artifactId>aliyun-log</artifactId>
+                    <groupId>com.aliyun.openservices</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+            <version>4.3.3</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-vod</artifactId>
+            <version>2.15.8</version>
+        </dependency>
+
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-vod-upload</artifactId>
+            <version>1.4.14</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun.openservices</groupId>
+            <artifactId>ons-client</artifactId>
+            <version>1.8.4.Final</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>ice20201109</artifactId>
+            <version>1.0.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-auth</artifactId>
+            <version>0.1.11-beta</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>alibabacloud-dysmsapi20170525</artifactId>
+            <version>2.0.23</version>
+            <scope>compile</scope>
+        </dependency>
+        <!-- Spring Mail依赖(发送邮件) -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <!-- FreeMarker模板 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-freemarker</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+            <version>0.9.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!--easyexcel-->
+    </dependencies>
+
+</project>