丁云鹏 1 jaar geleden
commit
bcc6183f91
38 gewijzigde bestanden met toevoegingen van 2460 en 0 verwijderingen
  1. 47 0
      .gitignore
  2. 101 0
      pom.xml
  3. 33 0
      recommend-server-client/.gitignore
  4. 93 0
      recommend-server-client/pom.xml
  5. 19 0
      recommend-server-runner/pom.xml
  6. 27 0
      recommend-server-runner/src/main/java/server/Application.java
  7. 64 0
      recommend-server-runner/src/main/resources/application-dev.yml
  8. 64 0
      recommend-server-runner/src/main/resources/application-pre.yml
  9. 64 0
      recommend-server-runner/src/main/resources/application-prod.yml
  10. 64 0
      recommend-server-runner/src/main/resources/application-test.yml
  11. 56 0
      recommend-server-runner/src/main/resources/application.yml
  12. 314 0
      recommend-server-runner/src/main/resources/logback-spring.xml
  13. 15 0
      recommend-server-service/pom.xml
  14. 11 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/CacheKeyConstant.java
  15. 40 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/CommonRequest.java
  16. 97 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/CommonResponse.java
  17. 14 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/Constant.java
  18. 81 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/AppTypeEnum.java
  19. 36 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/ExceptionEnum.java
  20. 36 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/PlatformEnum.java
  21. 90 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/exception/CommonException.java
  22. 56 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/exception/HttpServiceException.java
  23. 43 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/exception/TimeoutException.java
  24. 67 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/config/RedisTemplateConfig.java
  25. 54 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/config/SwaggerConfig.java
  26. 30 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/dao/generator/MybatisGeneratorMain.java
  27. 79 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/handle/GlobalExceptionHandle.java
  28. 21 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/handle/SentinelBlockExceptionHandler.java
  29. 40 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/interceptor/AbTestInterceptor.java
  30. 170 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/dto/BaseInfoDTO.java
  31. 27 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/dto/PageDTO.java
  32. 24 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/param/ExampleParam.java
  33. 23 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/vo/ExampleVO.java
  34. 14 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/ExampleService.java
  35. 104 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/impl/ExampleServiceImpl.java
  36. 90 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/HttpClientUtil.java
  37. 198 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/HttpPoolClient.java
  38. 54 0
      recommend-server-service/src/main/resources/mybatis-generator-config.xml

+ 47 - 0
.gitignore

@@ -0,0 +1,47 @@
+# ---> Java
+*.class
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.ear
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+
+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/

+ 101 - 0
pom.xml

@@ -0,0 +1,101 @@
+<?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>recommend-server</artifactId>
+    <version>1.0.0</version>
+    <name>recommend-server</name>
+    <description>recommend-server</description>
+    
+    <modules>
+        <module>recommend-server-service</module>
+        <module>recommend-server-client</module>
+        <module>recommend-server-runner</module>
+    </modules>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-commons</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </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>org.mybatis.generator</groupId>
+            <artifactId>mybatis-generator-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ctrip.framework.apollo</groupId>
+            <artifactId>apollo-client</artifactId>
+        </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>com.google.protobuf</groupId>
+            <artifactId>protobuf-java</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun.openservices</groupId>
+            <artifactId>aliyun-log-logback-appender</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 33 - 0
recommend-server-client/.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/

+ 93 - 0
recommend-server-client/pom.xml

@@ -0,0 +1,93 @@
+<?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>recommend-server</artifactId>
+        <groupId>com.tzld.piaoquan</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>recommend-server-client</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <grpc.version>1.9.2</grpc.version>
+        <grpc.netty.version>1.9.2</grpc.netty.version>
+        <jackson.version>5.3.9</jackson.version>
+
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-netty</artifactId>
+            <version>${grpc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-protobuf</artifactId>
+            <version>${grpc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-stub</artifactId>
+            <version>${grpc.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-common</artifactId>
+            <version>4.1.50.Final</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>${jackson.version}</version>
+        </dependency>
+    </dependencies>
+    <build>
+        <extensions>
+            <extension>
+                <groupId>kr.motd.maven</groupId>
+                <artifactId>os-maven-plugin</artifactId>
+                <version>${os.plugin.version}</version>
+            </extension>
+        </extensions>
+        <plugins>
+            <plugin>
+                <groupId>org.xolstice.maven.plugins</groupId>
+                <artifactId>protobuf-maven-plugin</artifactId>
+                <version>${protobuf.plugin.version}</version>
+                <configuration>
+                    <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
+                    </protocArtifact>
+                    <pluginId>grpc-java</pluginId>
+                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
+                    </pluginArtifact>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>compile</goal>
+                            <goal>compile-custom</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 19 - 0
recommend-server-runner/pom.xml

@@ -0,0 +1,19 @@
+<?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>recommend-server</artifactId>
+        <groupId>com.tzld.piaoquan</groupId>
+        <version>1.0.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>recommend-server-runner</artifactId>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+    </properties>
+
+</project>

+ 27 - 0
recommend-server-runner/src/main/java/server/Application.java

@@ -0,0 +1,27 @@
+package server;
+
+import com.tzld.piaoquan.recommend.sort.interceptor.AbTestInterceptor;
+import org.mybatis.spring.annotation.MapperScan;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.ServletComponentScan;
+import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
+import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+@SpringBootApplication
+@MapperScan("com.tzld.piaoquan.recommend.sort.dao")
+@ServletComponentScan("com.tzld.piaoquan.recommend.sort.controller")
+@EnableEurekaClient
+public class Application implements WebMvcConfigurer {
+    private static final Logger LOGGER = LoggerFactory.getLogger(Application.class);
+
+    public static void main(String[] args) {
+        SpringApplication.run(Application.class, args);
+        LOGGER.info("piaoquan SpringBoot Start Success");
+    }
+}

+ 64 - 0
recommend-server-runner/src/main/resources/application-dev.yml

@@ -0,0 +1,64 @@
+server:
+  port: 8080
+
+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拉取服务注册信息的间隔时间
+    serviceUrl:
+      defaultZone: http://deveureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 10
+      maximum-pool-size: 20
+      connection-test-query: SELECT 1
+#  cloud:
+#    sentinel:
+#      transport:
+#        dashboard: http://devsentinel-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
+
+xxl:
+  job:
+    admin:
+      addresses: http://127.0.0.1/xxl-job-admin
+    accessToken:
+    executor:
+      appname: ${spring.application.name}
+      address:
+      ip:
+      port: 9999
+      logpath: /datalog/weblog/${spring.application.name}/xxl-job/
+      logretentiondays: 30
+
+apollo:
+  meta: http://devapolloconfig-internal.piaoquantv.com
+
+aliyun:
+  log:
+    endpoint: cn-hangzhou.log.aliyuncs.com
+    accessKeyId: LTAIP6x1l3DXfSxm
+    accessKeySecret: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    project: ms-recommend-sort-test

+ 64 - 0
recommend-server-runner/src/main/resources/application-pre.yml

@@ -0,0 +1,64 @@
+server:
+  port: 8080
+
+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拉取服务注册信息的间隔时间
+    serviceUrl:
+      defaultZone: http://preeureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 10
+      maximum-pool-size: 20
+      connection-test-query: SELECT 1
+#  cloud:
+#    sentinel:
+#      transport:
+#        dashboard: http://presentinel-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
+
+xxl:
+  job:
+    admin:
+      addresses: http://127.0.0.1/xxl-job-admin
+    accessToken:
+    executor:
+      appname: ${spring.application.name}
+      address:
+      ip:
+      port: 9999
+      logpath: /datalog/weblog/${spring.application.name}/xxl-job/
+      logretentiondays: 30
+
+apollo:
+  meta: http://preapolloconfig-internal.piaoquantv.com
+
+aliyun:
+  log:
+    endpoint: cn-hangzhou-intranet.log.aliyuncs.com
+    accessKeyId: LTAIP6x1l3DXfSxm
+    accessKeySecret: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    project: ms-recommend-sort

+ 64 - 0
recommend-server-runner/src/main/resources/application-prod.yml

@@ -0,0 +1,64 @@
+server:
+  port: 8080
+
+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拉取服务注册信息的间隔时间
+    serviceUrl:
+      defaultZone: http://eureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 10
+      maximum-pool-size: 20
+      connection-test-query: SELECT 1
+#  cloud:
+#    sentinel:
+#      transport:
+#        dashboard: http://sentinel-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
+
+xxl:
+  job:
+    admin:
+      addresses: http://192.168.201.25:8182/xxl-job-admin
+    accessToken:
+    executor:
+      appname: ${spring.application.name}
+      address:
+      ip:
+      port: 9999
+      logpath: /datalog/weblog/${spring.application.name}/xxl-job/
+      logretentiondays: 30
+
+apollo:
+  meta: http://apolloconfig-internal.piaoquantv.com
+
+aliyun:
+  log:
+    endpoint: cn-hangzhou-intranet.log.aliyuncs.com
+    accessKeyId: LTAIP6x1l3DXfSxm
+    accessKeySecret: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    project: ms-recommend-sort

+ 64 - 0
recommend-server-runner/src/main/resources/application-test.yml

@@ -0,0 +1,64 @@
+server:
+  port: 8080
+
+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拉取服务注册信息的间隔时间
+    serviceUrl:
+      defaultZone: http://testeureka-internal.piaoquantv.com/eureka/
+
+spring:
+  datasource:
+    driver-class-name: com.mysql.jdbc.Driver
+    url: jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
+    username: wx2016_longvideo
+    password: wx2016_longvideoP@assword1234
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 10
+      maximum-pool-size: 20
+      connection-test-query: SELECT 1
+#  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
+
+xxl:
+  job:
+    admin:
+      addresses: http://xxl-job-test-internal.piaoquantv.com/xxl-job-admin
+    accessToken:
+    executor:
+      appname: ${spring.application.name}
+      address:
+      ip:
+      port: 9999
+      logpath: /datalog/weblog/${spring.application.name}/xxl-job/
+      logretentiondays: 30
+
+apollo:
+  meta: http://testapolloconfig-internal.piaoquantv.com
+
+aliyun:
+  log:
+    endpoint: cn-hangzhou-intranet.log.aliyuncs.com
+    accessKeyId: LTAIP6x1l3DXfSxm
+    accessKeySecret: KbTaM9ars4OX3PMS6Xm7rtxGr1FLon
+    project: ms-recommend-sort-test

+ 56 - 0
recommend-server-runner/src/main/resources/application.yml

@@ -0,0 +1,56 @@
+spring:
+  profiles:
+    active: dev
+  application:
+    name: recommend-sort
+#  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
+
+server:
+  tomcat:
+    threads:
+      max: 1000
+    uri-encoding: UTF-8
+    accept-count: 1000
+    connection-timeout: 30000
+  servlet:
+    context-path: /recommend-sort
+    session:
+      timeout: 60
+pagehelper:
+  helper-dialect: mysql
+
+mybatis:
+  type-aliases-package: com.tzld.piaoquan.recommend.sort.model.po
+  mapper-locations: classpath:mapper/**/*.xml
+
+logging:
+  file:
+    path: /datalog/weblog/${spring.application.name}/
+
+app:
+  id: recommend-sort
+apollo:
+  bootstrap:
+    enabled: true
+    namespaces: application
+  cacheDir: /datalog/apollo-cache-dir
+
+feign:
+  client:
+    config:
+      default:
+        connectTimeout: 2000
+        readTimeout: 10000

+ 314 - 0
recommend-server-runner/src/main/resources/logback-spring.xml

@@ -0,0 +1,314 @@
+<?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">
+
+    <!--为了防止进程退出时,内存中的数据丢失,请加上此选项-->
+    <shutdownHook class="ch.qos.logback.core.hook.DelayingShutdownHook"/>
+
+    <!-- 日志上下文名称 -->
+    <contextName>logback</contextName>
+
+    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义变量后,可以使“${}”来使用变量。 -->
+    <!-- 日志输出格式 -->
+    <property name="LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}\\(%L\\) - %msg%n" />
+
+    <!-- spring property使用方式 -->
+    <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"/>
+
+    <!-- 彩色日志 -->
+    <!-- 彩色日志依赖的渲染类 -->
+    <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(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}\\(%L\\)){cyan} %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>info</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}/log_debug.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>${LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset> <!-- 设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志归档 -->
+            <fileNamePattern>${LOG_PATH}/debug/log-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}/log_info.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>${LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 每天日志归档路径以及格式 -->
+            <fileNamePattern>${LOG_PATH}/info/log-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}/log_warn.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>${LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/warn/log-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}/log_error.log</file>
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>${LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${LOG_PATH}/error/log-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="loghubAppenderInfo" class="com.aliyun.openservices.log.logback.LoghubAppender">
+        <!--必选项-->
+        <!-- 账号及网络配置 -->
+        <endpoint>${aliyun_log_endpoint}</endpoint>
+        <accessKeyId>${aliyun_log_accessKeyId}</accessKeyId>
+        <accessKeySecret>${aliyun_log_accessKeySecret}</accessKeySecret>
+        <!-- sls 项目配置 -->
+        <project>${aliyun_log_project}</project>
+        <logStore>info-log</logStore>
+        <!--必选项 (end)-->
+        <!-- 可选项 -->
+        <topic></topic>
+        <source></source>
+        <!-- 可选项 详见 '参数说明'-->
+        <totalSizeInBytes>104857600</totalSizeInBytes>
+        <maxBlockMs>0</maxBlockMs>
+        <ioThreadCount>16</ioThreadCount>
+        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes>
+        <batchCountThreshold>4096</batchCountThreshold>
+        <lingerMs>2000</lingerMs>
+        <retries>10</retries>
+        <baseRetryBackoffMs>100</baseRetryBackoffMs>
+        <maxRetryBackoffMs>50000</maxRetryBackoffMs>
+        <!-- 可选项 通过配置 encoder 的 pattern 自定义 log 的格式 -->
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>${LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>INFO</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="loghubAppenderWarn" class="com.aliyun.openservices.log.logback.LoghubAppender">
+        <!--必选项-->
+        <!-- 账号及网络配置 -->
+        <endpoint>${aliyun_log_endpoint}</endpoint>
+        <accessKeyId>${aliyun_log_accessKeyId}</accessKeyId>
+        <accessKeySecret>${aliyun_log_accessKeySecret}</accessKeySecret>
+        <!-- sls 项目配置 -->
+        <project>${aliyun_log_project}</project>
+        <logStore>warn-log</logStore>
+        <!--必选项 (end)-->
+        <!-- 可选项 -->
+        <topic></topic>
+        <source></source>
+        <!-- 可选项 详见 '参数说明'-->
+        <totalSizeInBytes>104857600</totalSizeInBytes>
+        <maxBlockMs>0</maxBlockMs>
+        <ioThreadCount>16</ioThreadCount>
+        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes>
+        <batchCountThreshold>4096</batchCountThreshold>
+        <lingerMs>2000</lingerMs>
+        <retries>10</retries>
+        <baseRetryBackoffMs>100</baseRetryBackoffMs>
+        <maxRetryBackoffMs>50000</maxRetryBackoffMs>
+        <!-- 可选项 通过配置 encoder 的 pattern 自定义 log 的格式 -->
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>${LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>WARN</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+
+    <appender name="loghubAppenderError" class="com.aliyun.openservices.log.logback.LoghubAppender">
+        <!--必选项-->
+        <!-- 账号及网络配置 -->
+        <endpoint>${aliyun_log_endpoint}</endpoint>
+        <accessKeyId>${aliyun_log_accessKeyId}</accessKeyId>
+        <accessKeySecret>${aliyun_log_accessKeySecret}</accessKeySecret>
+        <!-- sls 项目配置 -->
+        <project>${aliyun_log_project}</project>
+        <logStore>error-log</logStore>
+        <!--必选项 (end)-->
+        <!-- 可选项 -->
+        <topic></topic>
+        <source></source>
+        <!-- 可选项 详见 '参数说明'-->
+        <totalSizeInBytes>104857600</totalSizeInBytes>
+        <maxBlockMs>0</maxBlockMs>
+        <ioThreadCount>16</ioThreadCount>
+        <batchSizeThresholdInBytes>524288</batchSizeThresholdInBytes>
+        <batchCountThreshold>4096</batchCountThreshold>
+        <lingerMs>2000</lingerMs>
+        <retries>10</retries>
+        <baseRetryBackoffMs>100</baseRetryBackoffMs>
+        <maxRetryBackoffMs>50000</maxRetryBackoffMs>
+        <!-- 可选项 通过配置 encoder 的 pattern 自定义 log 的格式 -->
+        <!--日志文件输出格式-->
+        <encoder>
+            <pattern>${LOG_PATTERN}</pattern>
+            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </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下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
+     -->
+
+    <!--
+        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
+        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
+        不能设置为INHERITED或者同义词NULL。默认是DEBUG
+        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
+    -->
+
+    <springProfile name="dev">
+        <logger name="com.tzld.piaoquan.recommend.sort" level="info"/>
+    </springProfile>
+    <springProfile name="test">
+        <logger name="com.tzld.piaoquan.recommend.sort" level="info"/>
+    </springProfile>
+    <springProfile name="pre">
+        <logger name="com.tzld.piaoquan.recommend.sort" level="info"/>
+    </springProfile>
+    <springProfile name="stress">
+        <logger name="com.tzld.piaoquan.recommend.sort" level="info"/>
+    </springProfile>
+    <springProfile name="prod">
+        <logger name="com.tzld.piaoquan.recommend.sort" level="info"/>
+    </springProfile>
+
+    <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="loghubAppenderInfo" />
+        <appender-ref ref="loghubAppenderWarn" />
+        <appender-ref ref="loghubAppenderError" />
+    </root>
+
+</configuration>

+ 15 - 0
recommend-server-service/pom.xml

@@ -0,0 +1,15 @@
+<?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>recommend-server</artifactId>
+        <version>1.0.0</version>
+    </parent>
+    <artifactId>recommend-server-service</artifactId>
+    <name>recommend-server-service</name>
+    <description>recommend-server-service</description>
+
+</project>

+ 11 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/CacheKeyConstant.java

@@ -0,0 +1,11 @@
+package com.tzld.piaoquan.recommend.sort.common.base;
+
+/**
+ * 缓存Key
+ *
+ * @author supeng
+ * @date 2020/08/31
+ */
+public class CacheKeyConstant {
+
+}

+ 40 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/CommonRequest.java

@@ -0,0 +1,40 @@
+package com.tzld.piaoquan.recommend.sort.common.base;
+
+import com.tzld.piaoquan.recommend.sort.model.dto.BaseInfoDTO;
+
+/**
+ * 请求参数
+ *
+ * @author supeng
+ */
+public class CommonRequest<T> {
+    /**
+     * 基础信息
+     */
+    BaseInfoDTO baseInfo;
+    /**
+     * 请求参数
+     */
+    T params;
+
+    public BaseInfoDTO getBaseInfo() {
+        return baseInfo;
+    }
+
+    public void setBaseInfo(BaseInfoDTO baseInfo) {
+        this.baseInfo = baseInfo;
+    }
+
+    public T getParams() {
+        return params;
+    }
+
+    public void setParams(T params) {
+        this.params = params;
+    }
+
+    @Override
+    public String toString() {
+        return "CommonRequest{" + "baseInfo=" + baseInfo + ", params=" + params + '}';
+    }
+}

+ 97 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/CommonResponse.java

@@ -0,0 +1,97 @@
+package com.tzld.piaoquan.recommend.sort.common.base;
+
+import com.tzld.piaoquan.recommend.sort.common.enums.ExceptionEnum;
+
+/**
+ * Common Response
+ */
+public class CommonResponse<T> {
+
+    private static final int SUCCESS_CODE = 0;
+    private static final String SUCCESS_MSG = "success";
+
+    /** 返回状态码,0 表示业务成功 */
+    private int code = 0;
+    /** 返回消息 */
+    private String msg = "success";
+    /** 业务成功时返回数据 */
+    private T data;
+    /** 重定向 */
+    private String redirect;
+
+    public boolean isSuccess() {
+        return this.code == SUCCESS_CODE;
+    }
+
+    public static <T> CommonResponse<T> success() {
+        CommonResponse<T> commonResponse = new CommonResponse<>();
+        commonResponse.setCode(SUCCESS_CODE);
+        commonResponse.setMsg(SUCCESS_MSG);
+        return commonResponse;
+    }
+
+    public static <T> CommonResponse<T> success(T data) {
+        CommonResponse<T> commonResponse = new CommonResponse<>();
+        commonResponse.setCode(SUCCESS_CODE);
+        commonResponse.setMsg(SUCCESS_MSG);
+        commonResponse.setData(data);
+        return commonResponse;
+    }
+
+    public static <T> CommonResponse<T> create() {
+        return create(SUCCESS_CODE, SUCCESS_MSG, null);
+    }
+    
+    public static <T> CommonResponse<T> create(T data) {
+        return create(SUCCESS_CODE, SUCCESS_MSG, data);
+    }
+
+    public static <T> CommonResponse<T> create(int code, String msg) {
+        return create(code, msg, null);
+    }
+
+    public static <T> CommonResponse<T> create(ExceptionEnum exceptionEnum) {
+        return create(exceptionEnum.getCode(), exceptionEnum.getMsg(), null);
+    }
+
+    public static <T> CommonResponse<T> create(int code, String msg, T data) {
+        CommonResponse<T> commonResponse = new CommonResponse<>();
+        commonResponse.setCode(code);
+        commonResponse.setMsg(msg);
+        commonResponse.setData(data);
+        return commonResponse;
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public T getData() {
+        return data;
+    }
+
+    public void setData(T data) {
+        this.data = data;
+    }
+
+    public String getRedirect() {
+        return redirect;
+    }
+
+    public void setRedirect(String redirect) {
+        this.redirect = redirect;
+    }
+
+}

+ 14 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/base/Constant.java

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

+ 81 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/AppTypeEnum.java

@@ -0,0 +1,81 @@
+package com.tzld.piaoquan.recommend.sort.common.enums;
+
+/**
+ * AppType
+ * 目前只维护 0 1 4 13 4个应用
+ * @author supeng
+ * @date 2020/08/19
+ */
+public enum AppTypeEnum {
+    /**
+     * vlog小程序
+     */
+    VLOG(0, "VLOG"),
+    /**
+     * 票圈视频APP
+     */
+    QINGQUAPP(1, "轻趣视频APP"),
+    SMILE(2, "搞笑视频"),
+    LOVEMOVIE(3, "爱电影"),
+    /**
+     * 票圈视频小程序
+     */
+    LOVELIVE(4, "爱生活"),
+    /**
+     * 长视频小程序
+     */
+    LONGVIDEO(5, "长视频"),
+    SHORTVIDEO(6, "短视频"),
+    SURPRISE(7, "惊奇视频"),
+    PC(8,"PC端"),
+    CIRCLEAPP(9,"票圈长视频APP"),
+    LONGVIDEOLITE(10,"票圈长视频lite"),
+    /**
+     * 票圈相册小程序
+     */
+    ALBUM(11,"票圈相册"),
+    H5(12,"H5端"),
+    /**
+     * 极速版APP
+     */
+    APPSPEED(13,"APP极速"),
+    SMALLSPEED(14,"小程序极速"),
+    ADMIN_CRAWLER(888888,"后台-爬虫"),
+    OTHERS(999999,"其他的调用方,比如后台管理系统");
+
+    private Integer code;
+    private String desc;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = 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;
+    }
+}

+ 36 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/ExceptionEnum.java

@@ -0,0 +1,36 @@
+package com.tzld.piaoquan.recommend.sort.common.enums;
+
+/**
+ * 异常
+ *
+ * @author supeng
+ * @date 2020/08/31
+ */
+public enum ExceptionEnum {
+
+    SYSTEM_ERROR(-111, "系统错误"),
+    DATA_ERROR(-222, "数据异常,请联系管理员"),
+    USER_IS_UNVALID(2, "用户操作鉴权不通过"),
+    PARAM_ERROR(3, "参数不对"),
+    FLOW_CONTROL(-777, "接口被限流"),
+    TOKEN_NOTEXIST(-994, "访问凭证不存在"),
+	
+	;
+
+    private int code;
+    private String msg;
+
+    public int getCode() {
+        return code;
+    }
+
+
+    public String getMsg() {
+        return msg;
+    }
+
+    ExceptionEnum(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+}

+ 36 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/PlatformEnum.java

@@ -0,0 +1,36 @@
+package com.tzld.piaoquan.recommend.sort.common.enums;
+
+/**
+ * 平台
+ *
+ * @author supeng
+ * @date 2020/08/28
+ */
+public enum PlatformEnum {
+    ANDROID("android", "安卓"),
+    IOS("ios", "IOS");
+
+    String value;
+    String desc;
+
+    PlatformEnum(String value, String desc) {
+        this.value = value;
+        this.desc = desc;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public String getDesc() {
+        return desc;
+    }
+
+    public void setDesc(String desc) {
+        this.desc = desc;
+    }
+}

+ 90 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/exception/CommonException.java

@@ -0,0 +1,90 @@
+package com.tzld.piaoquan.recommend.sort.common.exception;
+
+import com.tzld.piaoquan.recommend.sort.common.enums.ExceptionEnum;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 异常
+ *
+ * @author supeng
+ * @date 2020/08/28
+ */
+public class CommonException extends RuntimeException {
+
+    /**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(CommonException.class);
+    /**
+     * 异常
+     */
+    private ExceptionEnum exceptionEnum;
+    /**
+     * 错误码
+     */
+    private int code;
+    /**
+     * 异常信息
+     */
+    private String msg;
+    
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public CommonException(Throwable throwable) {
+        super(throwable);
+    }
+
+    public CommonException(int code, String msg) {
+        super(msg);
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public CommonException(ExceptionEnum exceptionEnum) {
+        super(exceptionEnum.getMsg());
+        this.exceptionEnum = exceptionEnum;
+        this.code = exceptionEnum.getCode();
+        this.msg = exceptionEnum.getMsg();
+    }
+
+
+    public CommonException(int code, String msg, Throwable throwable) {
+        super(msg, throwable);
+        this.code = code;
+        this.msg = msg;
+    }
+
+    public CommonException(ExceptionEnum exceptionEnum, Throwable throwable) {
+        super(exceptionEnum.getMsg(), throwable);
+        this.exceptionEnum = exceptionEnum;
+        this.code = exceptionEnum.getCode();
+        this.msg = exceptionEnum.getMsg();
+    }
+
+
+    @Override
+    public void printStackTrace() {
+        if (exceptionEnum != null) {
+            LOGGER.info("exception code = {}, msg = {}", exceptionEnum.getCode(), exceptionEnum.getMsg());
+        }
+        LOGGER.info("exception code = {}, msg = {}", code, msg);
+    }
+}

+ 56 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/exception/HttpServiceException.java

@@ -0,0 +1,56 @@
+package com.tzld.piaoquan.recommend.sort.common.exception;
+
+/**
+ *
+ */
+public class HttpServiceException extends RuntimeException {
+
+    private int code;
+    private String message;
+
+    public int getCode() {
+        return code;
+    }
+
+    public void setCode(int code) {
+        this.code = code;
+    }
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public HttpServiceException(int code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public HttpServiceException(String message, int code, String message1) {
+        super(message);
+        this.code = code;
+        this.message = message1;
+    }
+
+    public HttpServiceException(String message, Throwable cause, int code, String message1) {
+        super(message, cause);
+        this.code = code;
+        this.message = message1;
+    }
+
+    public HttpServiceException(Throwable cause, int code, String message) {
+        super(cause);
+        this.code = code;
+        this.message = message;
+    }
+
+    public HttpServiceException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, int code, String message1) {
+        super(message, cause, enableSuppression, writableStackTrace);
+        this.code = code;
+        this.message = message1;
+    }
+}

+ 43 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/exception/TimeoutException.java

@@ -0,0 +1,43 @@
+package com.tzld.piaoquan.recommend.sort.common.exception;
+
+
+public class TimeoutException extends RuntimeException {
+
+    private String message;
+
+    @Override
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public TimeoutException() {
+    }
+
+    public TimeoutException(String message) {
+        this.message = message;
+    }
+
+    public TimeoutException(String message, String message1) {
+        super(message);
+        this.message = message1;
+    }
+
+    public TimeoutException(String message, Throwable cause, String message1) {
+        super(message, cause);
+        this.message = message1;
+    }
+
+    public TimeoutException(Throwable cause, String message) {
+        super(cause);
+        this.message = message;
+    }
+
+    public TimeoutException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace, String message1) {
+        super(message, cause, enableSuppression, writableStackTrace);
+        this.message = message1;
+    }
+}

+ 67 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/config/RedisTemplateConfig.java

@@ -0,0 +1,67 @@
+package com.tzld.piaoquan.recommend.sort.config;
+
+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.StringRedisSerializer;
+
+/**
+ * @author supeng
+ * @date 2020/11/10
+ */
+@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);
+    }
+
+    /**
+     * 构建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;
+    }
+
+}

+ 54 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/config/SwaggerConfig.java

@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.tzld.piaoquan.recommend.sort.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+/**
+ * swagger2 配置
+ * @author supeng
+ */
+@Configuration
+@Profile({"dev","test","pre"})
+public class SwaggerConfig {
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                .select()
+                .apis(RequestHandlerSelectors.basePackage("com.tzld.piaoquan.recommend.sort.controller"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    private ApiInfo apiInfo() {
+        return new ApiInfoBuilder()
+                .title("recommend-sort server swagger api")
+                .description("recommend-sort server swagger api")
+                .version("1.0")
+                .build();
+    }
+}

+ 30 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/dao/generator/MybatisGeneratorMain.java

@@ -0,0 +1,30 @@
+package com.tzld.piaoquan.recommend.sort.dao.generator;
+
+import java.io.File;
+import java.io.IOException;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.mybatis.generator.api.MyBatisGenerator;
+import org.mybatis.generator.config.Configuration;
+import org.mybatis.generator.config.xml.ConfigurationParser;
+import org.mybatis.generator.exception.InvalidConfigurationException;
+import org.mybatis.generator.exception.XMLParserException;
+import org.mybatis.generator.internal.DefaultShellCallback;
+
+public class MybatisGeneratorMain {
+
+	public static void main(String[] args)
+			throws SQLException, IOException, InterruptedException, InvalidConfigurationException, XMLParserException {
+		List<String> warnings = new ArrayList<String>();
+		boolean overwrite = true;
+		File configFile = new File(MybatisGeneratorMain.class.getResource("/mybatis-generator-config.xml").getFile());
+		ConfigurationParser cp = new ConfigurationParser(warnings);
+		Configuration config = cp.parseConfiguration(configFile);
+		DefaultShellCallback callback = new DefaultShellCallback(overwrite);
+		MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
+		myBatisGenerator.generate(null);
+		System.out.println("genreate finish");
+	}
+}

+ 79 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/handle/GlobalExceptionHandle.java

@@ -0,0 +1,79 @@
+package com.tzld.piaoquan.recommend.sort.handle;
+
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.CollectionUtils;
+import org.springframework.validation.BindException;
+import org.springframework.validation.ObjectError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import com.tzld.piaoquan.recommend.sort.common.base.CommonResponse;
+import com.tzld.piaoquan.recommend.sort.common.enums.ExceptionEnum;
+import com.tzld.piaoquan.recommend.sort.common.exception.CommonException;
+
+/**
+ * 全局异常处理器
+ * 
+ * @author liuzhiheng
+ * @date 2020年11月20日 上午11:04:48
+ * @version 1.0
+ */
+
+@RestControllerAdvice
+public class GlobalExceptionHandle {
+
+    private static Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandle.class);
+
+    @ExceptionHandler
+    public Object handleException(HttpServletRequest req, Exception exception) throws Exception {
+        String uri = req.getRequestURI();
+        CommonResponse<Object> response = new CommonResponse<Object>();
+        // 业务异常
+        if (exception instanceof CommonException) {
+            CommonException e = (CommonException) exception;
+            response.setCode(e.getCode());
+            response.setMsg(e.getMsg());
+            LOGGER.warn("uri:" + uri + "\n" + "CustomException log.", exception);
+        } else if (exception instanceof MethodArgumentNotValidException) {
+            // 参数校验异常
+            MethodArgumentNotValidException e = (MethodArgumentNotValidException) exception;
+            List<ObjectError> errorList = e.getBindingResult().getAllErrors();
+            StringBuilder errorMsg = new StringBuilder();
+            errorMsg.append("|");
+            if (!CollectionUtils.isEmpty(errorList)) {
+                for (ObjectError objectError : errorList) {
+                    errorMsg.append(objectError.getDefaultMessage()).append("|");
+                }
+            }
+            response.setCode(ExceptionEnum.PARAM_ERROR.getCode());
+            response.setMsg(errorMsg.toString());
+            LOGGER.warn("uri:" + uri + "\n" + "MethodArgumentNotValidException log.", exception);
+        } else if (exception instanceof BindException) {
+            // 参数绑定异常
+            BindException e = (BindException) exception;
+            List<ObjectError> errorList = e.getBindingResult().getAllErrors();
+            StringBuilder errorMsg = new StringBuilder();
+            errorMsg.append("|");
+            if (!CollectionUtils.isEmpty(errorList)) {
+                for (ObjectError objectError : errorList) {
+                    errorMsg.append(objectError.getDefaultMessage()).append("|");
+                }
+            }
+            response.setCode(ExceptionEnum.PARAM_ERROR.getCode());
+            response.setMsg(errorMsg.toString());
+            LOGGER.warn("uri:" + uri + "\n" + "BindException log.", exception);
+        } else {
+            response.setCode(ExceptionEnum.SYSTEM_ERROR.getCode());
+            response.setMsg(ExceptionEnum.SYSTEM_ERROR.getMsg());
+            LOGGER.error("uri:" + uri + "\n" + "unknow exception log.", exception);
+        }
+        return response;
+    }
+
+}

+ 21 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/handle/SentinelBlockExceptionHandler.java

@@ -0,0 +1,21 @@
+package com.tzld.piaoquan.recommend.sort.handle;
+
+import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
+import com.alibaba.csp.sentinel.slots.block.BlockException;
+import com.tzld.piaoquan.recommend.sort.common.enums.ExceptionEnum;
+import com.tzld.piaoquan.recommend.sort.common.exception.CommonException;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+@Component
+public class SentinelBlockExceptionHandler implements BlockExceptionHandler {
+
+    @Override
+    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
+                       BlockException e) throws Exception {
+        throw new CommonException(ExceptionEnum.FLOW_CONTROL);
+    }
+}
+

+ 40 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/interceptor/AbTestInterceptor.java

@@ -0,0 +1,40 @@
+package com.tzld.piaoquan.recommend.sort.interceptor;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * AbTest 拦截器
+ *
+ * @author supeng
+ * @date 2020/08/26
+ */
+@Component
+public class AbTestInterceptor implements HandlerInterceptor {
+    private static final Logger LOGGER = LoggerFactory.getLogger(AbTestInterceptor.class);
+
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        String uri = request.getRequestURI();
+        LOGGER.info("uri = {}", uri);
+        //TODO
+        return true;
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
+
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
+
+    }
+}

+ 170 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/dto/BaseInfoDTO.java

@@ -0,0 +1,170 @@
+package com.tzld.piaoquan.recommend.sort.model.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 基础信息
+ *
+ * @author supeng
+ * @date 2020/08/28
+ */
+public class BaseInfoDTO {
+    /// 用户信息
+    @ApiModelProperty(value = "公共参数-token值")
+    private String token;
+    @ApiModelProperty(value = "公共参数-登录用户ID")
+    private Long loginUid;
+
+    /// 应用信息
+    @ApiModelProperty(value = "公共参数-应用版本号")
+    private Integer appVersionCode;
+    @ApiModelProperty(value = "公共参数-产品代号")
+    private Integer appType;
+
+    /// 设备信息
+    @ApiModelProperty(value = "公共参数-手机设备的唯一码")
+    private String machineCode;
+    @ApiModelProperty(value = "公共参数-ios,android")
+    private String platform;
+    @ApiModelProperty(value = "公共参数-系统版本(例:ios10.1)")
+    private String systemVersion;
+    @ApiModelProperty(value = "公共参数-手机信息")
+    private String machineInfo;
+    @ApiModelProperty(value = "公共参数-网络类型 WI-FI 5G 4G 3G 2G")
+    private String networkType;
+    @ApiModelProperty(value = "公共参数-客户端ip")
+    private String clientIp;
+
+    // pageSource相关的参数
+    @ApiModelProperty(value = "公共参数-页面来源")
+    private String pageSource;
+
+    // 某次操作相关的参数
+    @ApiModelProperty(value = "公共参数-前端请求时间")
+    private Long clientTimestamp;
+    @ApiModelProperty(value = "公共参数-sessionId")
+    private String sessionId;
+    @ApiModelProperty(value = "公共参数-requestId,每次请求客户端生成唯一ID,不超过64位")
+    private String requestId;
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public Long getLoginUid() {
+        return loginUid;
+    }
+
+    public void setLoginUid(Long loginUid) {
+        this.loginUid = loginUid;
+    }
+
+    public Integer getAppVersionCode() {
+        return appVersionCode;
+    }
+
+    public void setAppVersionCode(Integer appVersionCode) {
+        this.appVersionCode = appVersionCode;
+    }
+
+    public Integer getAppType() {
+        return appType;
+    }
+
+    public void setAppType(Integer appType) {
+        this.appType = appType;
+    }
+
+    public String getMachineCode() {
+        return machineCode;
+    }
+
+    public void setMachineCode(String machineCode) {
+        this.machineCode = machineCode;
+    }
+
+    public String getPlatform() {
+        return platform;
+    }
+
+    public void setPlatform(String platform) {
+        this.platform = platform;
+    }
+
+    public String getSystemVersion() {
+        return systemVersion;
+    }
+
+    public void setSystemVersion(String systemVersion) {
+        this.systemVersion = systemVersion;
+    }
+
+    public String getMachineInfo() {
+        return machineInfo;
+    }
+
+    public void setMachineInfo(String machineInfo) {
+        this.machineInfo = machineInfo;
+    }
+
+    public String getNetworkType() {
+        return networkType;
+    }
+
+    public void setNetworkType(String networkType) {
+        this.networkType = networkType;
+    }
+
+    public String getClientIp() {
+        return clientIp;
+    }
+
+    public void setClientIp(String clientIp) {
+        this.clientIp = clientIp;
+    }
+
+    public String getPageSource() {
+        return pageSource;
+    }
+
+    public void setPageSource(String pageSource) {
+        this.pageSource = pageSource;
+    }
+
+    public Long getClientTimestamp() {
+        return clientTimestamp;
+    }
+
+    public void setClientTimestamp(Long clientTimestamp) {
+        this.clientTimestamp = clientTimestamp;
+    }
+
+    public String getSessionId() {
+        return sessionId;
+    }
+
+    public void setSessionId(String sessionId) {
+        this.sessionId = sessionId;
+    }
+
+    public String getRequestId() {
+        return requestId;
+    }
+
+    public void setRequestId(String requestId) {
+        this.requestId = requestId;
+    }
+
+    @Override
+    public String toString() {
+        return String.format(
+            "BaseInfoDTO [token=%s, appVersionCode=%s, appType=%s, machineCode=%s, platform=%s, systemVersion=%s, machineInfo=%s, networkType=%s, clientIp=%s, pageSource=%s, clientTimestamp=%s, sessionId=%s, requestId=%s]",
+            token, appVersionCode, appType, machineCode, platform, systemVersion, machineInfo, networkType, clientIp,
+            pageSource, clientTimestamp, sessionId, requestId);
+    }
+
+}

+ 27 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/dto/PageDTO.java

@@ -0,0 +1,27 @@
+package com.tzld.piaoquan.recommend.sort.model.dto;
+
+/**
+ * @author supeng
+ * @date 2020/09/01
+ */
+public class PageDTO {
+
+    private int pageNum;
+    private int pageSize;
+
+    public int getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(int pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public int getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(int pageSize) {
+        this.pageSize = pageSize;
+    }
+}

+ 24 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/param/ExampleParam.java

@@ -0,0 +1,24 @@
+package com.tzld.piaoquan.recommend.sort.model.param;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 请求业务参数
+ * 
+ * @author liuzhiheng
+ * @date 2021年2月2日 下午3:00:14
+ * @version 1.0
+ */
+public class ExampleParam {
+	@ApiModelProperty(value = "name")
+	private String name;
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+}

+ 23 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/vo/ExampleVO.java

@@ -0,0 +1,23 @@
+package com.tzld.piaoquan.recommend.sort.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+
+/**
+ * 返回参数vo
+ *
+ * @author supeng
+ * @date 2020/08/31
+ */
+public class ExampleVO {
+	@ApiModelProperty(value = "greeting")
+	private String greeting;
+
+	public String getGreeting() {
+		return greeting;
+	}
+
+	public void setGreeting(String greeting) {
+		this.greeting = greeting;
+	}
+
+}

+ 14 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/ExampleService.java

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.recommend.sort.service;
+
+import com.tzld.piaoquan.recommend.sort.model.vo.ExampleVO;
+
+/**
+ *
+ * @author supeng
+ * @date 2020/08/31
+ */
+public interface ExampleService {
+
+	ExampleVO greeting(String name);
+
+}

+ 104 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/impl/ExampleServiceImpl.java

@@ -0,0 +1,104 @@
+package com.tzld.piaoquan.recommend.sort.service.impl;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.tzld.piaoquan.recommend.sort.service.ExampleService;
+import com.tzld.piaoquan.recommend.sort.util.HttpClientUtil;
+import com.tzld.piaoquan.recommend.sort.util.HttpPoolClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import com.tzld.piaoquan.recommend.sort.model.vo.ExampleVO;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import java.util.List;
+import java.util.concurrent.*;
+
+@Service
+public class ExampleServiceImpl implements ExampleService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(ExampleServiceImpl.class);
+
+    private static final HttpPoolClient httpPoolClient = HttpClientUtil.useDefault();
+
+    /**
+     * 线程池队列大小
+     */
+    private static final int QUEUE_MAX_SIZE = 100000;
+    /**
+     * 线程命名
+     */
+    private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("example-service-pool-%d").build();
+    /**
+     * 线程池
+     */
+    private static ExecutorService pool;
+
+    @PostConstruct
+    public void init() {
+        //init thread pool
+        pool = new ThreadPoolExecutor(32, 32,
+                0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(QUEUE_MAX_SIZE), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
+    }
+
+    @PreDestroy
+    public void destroy() {
+        //gracefully shutdown
+        pool.shutdown();
+    }
+
+    @Override
+    public ExampleVO greeting(String name) {
+        LOGGER.info("name:{}", name);
+        ExampleVO vo = new ExampleVO();
+        vo.setGreeting("hello, " + name);
+        //20路召回
+        CountDownLatch countDownLatch = new CountDownLatch(20);
+        List<Long> videoIds = new CopyOnWriteArrayList<>();
+        //召回1
+        pool.execute(() -> {
+            try {
+                //TODO
+//                videoIds.addAll();
+            } catch (Exception e) {
+                LOGGER.error("recall 1 error", e);
+            } finally {
+                countDownLatch.countDown();
+            }
+        });
+        //召回2
+        pool.execute(() -> {
+            try {
+                //TODO
+//                videoIds.addAll();
+            } catch (Exception e) {
+                LOGGER.error("recall 2 error", e);
+            } finally {
+                countDownLatch.countDown();
+            }
+        });
+        //召回3
+        pool.execute(() -> {
+            try {
+                //TODO
+//                videoIds.addAll();
+            } catch (Exception e) {
+                LOGGER.error("recall 3 error", e);
+            } finally {
+                countDownLatch.countDown();
+            }
+        });
+
+        //...
+
+        try {
+            countDownLatch.await(1000, TimeUnit.MICROSECONDS);
+        } catch (InterruptedException e) {
+            LOGGER.error("recall error", e);
+        }
+
+        return vo;
+    }
+
+}

+ 90 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/HttpClientUtil.java

@@ -0,0 +1,90 @@
+package com.tzld.piaoquan.recommend.sort.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * http util
+ *
+ * @author supeng
+ */
+public class HttpClientUtil {
+
+    private static final String DEFAULT_SHARED_KEY = "DEFAULT_SHARED_KEY";
+
+    /**
+     * 链接建立的超时时间 ms
+     */
+    private static final int DEFAULT_CONNECTION_TIMEOUT = 3000;
+    /**
+     * 响应超时时间 ms
+     */
+    private static final int DEFAULT_SOCKET_TIMEOUT = 3000;
+
+    /**
+     * 每个路由的最大连接数
+     */
+    private static final int DEFAULT_DEFAULT_MAX_PER_ROUTE = 50;
+
+    /**
+     * 最大连接数
+     */
+    private static final int DEFAULT_DEFAULT_MAX_TOTAL = 200;
+
+    /**
+     * 重试次数,默认0
+     */
+    private static final int DEFAULT_RETRY_COUNT = 0;
+
+    /**
+     * 从connection pool中获得一个connection的超时时间 ms
+     */
+    private static final int DEFAULT_CONNECTION_WAIT_TIMEOUT = 300;
+
+    private static final Map<String, HttpPoolClient> CREATED_HTTP_CLIENTS = new HashMap<>();
+
+    private static final Lock LOCK = new ReentrantLock();
+
+    private HttpClientUtil() {
+    }
+
+    public static HttpPoolClient useDefault() {
+        return createCached(DEFAULT_SHARED_KEY);
+    }
+
+
+    public static HttpPoolClient createCached(String cachedKey) {
+        HttpPoolClient httpPoolClient = CREATED_HTTP_CLIENTS.get(cachedKey);
+        if (httpPoolClient != null) {
+            return httpPoolClient;
+        }
+        LOCK.lock();
+        try {
+            httpPoolClient = CREATED_HTTP_CLIENTS.get(cachedKey);
+            if (httpPoolClient == null) {
+                httpPoolClient = create(DEFAULT_CONNECTION_TIMEOUT, DEFAULT_SOCKET_TIMEOUT, DEFAULT_DEFAULT_MAX_PER_ROUTE, DEFAULT_DEFAULT_MAX_TOTAL, DEFAULT_RETRY_COUNT, DEFAULT_CONNECTION_WAIT_TIMEOUT);
+                CREATED_HTTP_CLIENTS.put(cachedKey, httpPoolClient);
+            }
+        } finally {
+            LOCK.unlock();
+        }
+        return httpPoolClient;
+    }
+
+    /**
+     * 创建httpclient
+     *
+     * @param connectTimeout        连接超时时间 ms
+     * @param socketTimeout         读超时时间(等待数据超时时间)ms
+     * @param maxPerRoute           每个路由的最大连接数
+     * @param maxTotal              最大连接数
+     * @param retryCount            重试次数
+     * @param connectionWaitTimeout 连接等待超市时间 ms
+     * @return httpclient instance
+     */
+    public static HttpPoolClient create(int connectTimeout, int socketTimeout, int maxPerRoute, int maxTotal, int retryCount, int connectionWaitTimeout) {
+        return HttpPoolClient.create(connectTimeout, socketTimeout, maxPerRoute, maxTotal, retryCount, connectionWaitTimeout);
+    }
+}

+ 198 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/util/HttpPoolClient.java

@@ -0,0 +1,198 @@
+package com.tzld.piaoquan.recommend.sort.util;
+
+import com.google.common.collect.Lists;
+import com.tzld.piaoquan.recommend.sort.common.exception.HttpServiceException;
+import com.tzld.piaoquan.recommend.sort.common.exception.TimeoutException;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpRequestInterceptor;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.*;
+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.entity.StringEntity;
+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.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import javax.net.ssl.SSLContext;
+import java.net.SocketTimeoutException;
+import java.nio.charset.Charset;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * http client
+ * @author supeng
+ */
+public class HttpPoolClient {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(HttpPoolClient.class);
+
+    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) -> LOGGER.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 CloseableHttpClient closeableHttpClient;
+
+    private HttpPoolClient(CloseableHttpClient closeableHttpClient) {
+        this.closeableHttpClient = closeableHttpClient;
+    }
+
+    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) {
+                LOGGER.error(e.getMessage(), e);
+            }
+        };
+        return requestInterceptor;
+    }
+
+
+    public Optional<String> get(String url) {
+        HttpGet httpGet = new HttpGet(url);
+        return request(httpGet);
+    }
+
+    public Optional<String> post(String url) {
+        HttpPost httpPost = new HttpPost(url);
+        return request(httpPost);
+    }
+
+
+    public Optional<String> postJson(String url, String json) {
+        HttpPost httpPost = new HttpPost(url);
+        if (StringUtils.isBlank(json)) {
+            return request(httpPost);
+        }
+        StringEntity entity = new StringEntity(json, Charset.forName("UTF-8"));
+        entity.setContentEncoding("UTF-8");
+        entity.setContentType("application/json");
+        httpPost.setEntity(entity);
+        return request(httpPost);
+    }
+
+    public Optional<String> request(HttpRequestBase request) {
+
+        if (LOGGER.isDebugEnabled()) {
+            String path = request.getURI().toString();
+            LOGGER.debug("http request url = {} ", path);
+        }
+        HttpEntity entity = null;
+        try {
+            CloseableHttpResponse response = request((HttpUriRequest) request);
+            if (response == null) {
+                throw new RuntimeException("call api exception no response");
+            }
+            entity = response.getEntity();
+            String content = null;
+            if (entity != null) {
+                content = EntityUtils.toString(entity, "UTF-8");
+            }
+            int httpStatus = response.getStatusLine().getStatusCode();
+            if (httpStatus == HttpStatus.SC_OK) {
+                return Optional.ofNullable(content);
+            }
+            String path = request.getURI().toString();
+            LOGGER.error("http call api {} fail response status {} content {}", path, httpStatus, content);
+            throw new HttpServiceException(httpStatus, content);
+        } catch (Exception e) {
+            if (e instanceof TimeoutException) {
+                throw (TimeoutException) e;
+            }
+            if (e instanceof HttpServiceException) {
+                throw (HttpServiceException) e;
+            }
+            throw new RuntimeException(e.getMessage(), 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) {
+            String path = request.getURI().toString();
+            if (e instanceof SocketTimeoutException) {
+                LOGGER.error(String.format("http timeout request url = %s .", path));
+                throw new TimeoutException();
+            } else {
+            }
+            throw new RuntimeException(String.format("http exception request url = %s ", path), e);
+        }
+    }
+
+    /**
+     * @param connectTimeout 连接超时时间 ms
+     * @param socketTimeout  读超时时间(等待数据超时时间)ms
+     * @param maxPerRoute    每个路由的最大连接数
+     * @param maxTotal       最大连接数
+     * @param retryCount     重试次数
+     * @return httpclient instance
+     */
+    protected static HttpPoolClient 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 new HttpPoolClient(client);
+        } catch (Throwable e) {
+            LOGGER.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;
+    }
+
+}

+ 54 - 0
recommend-server-service/src/main/resources/mybatis-generator-config.xml

@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE generatorConfiguration
+        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
+        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
+<!-- 配置生成器 -->
+<generatorConfiguration>
+    <context id="mysql" defaultModelType="flat">
+        <property name="autoDelimitKeywords" value="true"/>
+        <!-- 生成的Java文件的编码 -->
+        <property name="javaFileEncoding" value="UTF-8"/>
+        <!-- 格式化java代码 -->
+        <property name="javaFormatter" value="org.mybatis.generator.api.dom.DefaultJavaFormatter"/>
+        <!-- 格式化XML代码 -->
+        <property name="xmlFormatter" value="org.mybatis.generator.api.dom.DefaultXmlFormatter"/>
+        <!-- beginningDelimiter和endingDelimiter:指明数据库的用于标记数据库对象名的符号,比如ORACLE就是双引号,MYSQL默认是`反引号; -->
+        <property name="beginningDelimiter" value="`"/>
+        <property name="endingDelimiter" value="`"/>
+
+        <plugin type="org.mybatis.generator.plugins.ToStringPlugin"></plugin>
+        <plugin type="org.mybatis.generator.plugins.UnmergeableXmlMappersPlugin" />
+
+        <commentGenerator>
+            <property name="addRemarkComments" value="true"/>
+        </commentGenerator>
+
+        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
+                        connectionURL="jdbc:mysql://rm-bp1k5853td1r25g3n690.mysql.rds.aliyuncs.com:3306/longvideo?useUnicode=true&amp;characterEncoding=utf-8&amp;zeroDateTimeBehavior=convertToNull&amp;useSSL=false"
+                        userId="wx2016_longvideo" password="wx2016_longvideoP@assword1234">
+        </jdbcConnection>
+
+        <javaTypeResolver type="org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl">
+            <property name="forceBigDecimals" value="false"/>
+        </javaTypeResolver>
+
+
+
+        <javaModelGenerator targetPackage="com.tzld.piaoquan.recommend.server.model.po" targetProject="src/main/java">
+            <property name="constructorBased" value="false"/>
+            <property name="enableSubPackages" value="true"/>
+            <property name="immutable" value="false"/>
+        </javaModelGenerator>
+
+        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
+            <property name="enableSubPackages" value="true"/>
+        </sqlMapGenerator>
+
+        <javaClientGenerator targetPackage="com.tzld.piaoquan.recommend.server.dao.mapper" type="XMLMAPPER" targetProject="src/main/java">
+            <property name="enableSubPackages" value="true"/>
+        </javaClientGenerator>
+
+        <table tableName="wx_ab_laboratory_white" domainObjectName="WxAbLaboratoryWhite" alias=""/>
+    </context>
+
+</generatorConfiguration>