Просмотр исходного кода

Merge branch 'feature_20260706_multi_tab' of algorithm/recommend-server into master

zhaohaipeng 1 неделя назад
Родитель
Сommit
adf977e873
31 измененных файлов с 5068 добавлено и 33 удалено
  1. 5 1
      recommend-server-client/pom.xml
  2. 15 2
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/common/Common.java
  3. 979 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/common/TabProto.java
  4. 57 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/common/TabProtoOrBuilder.java
  5. 23 22
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/Recommend.java
  6. 188 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequest.java
  7. 15 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequestOrBuilder.java
  8. 72 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/Tab.java
  9. 1936 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabRequest.java
  10. 152 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabRequestOrBuilder.java
  11. 958 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabResponse.java
  12. 48 0
      recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabResponseOrBuilder.java
  13. 8 0
      recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/common.proto
  14. 1 0
      recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/recommend.proto
  15. 27 0
      recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/tab.proto
  16. 1 1
      recommend-server-service/pom.xml
  17. 23 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/TabSource.java
  18. 35 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/common/enums/TabType.java
  19. 2 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/RecommendParam.java
  20. 14 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/Tab.java
  21. 28 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/TabParam.java
  22. 22 4
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java
  23. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankParam.java
  24. 15 1
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankRouter.java
  25. 10 2
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java
  26. 62 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankSequenceStrategy.java
  27. 3 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallParam.java
  28. 16 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallService.java
  29. 88 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/PersonalizationTabRovnRecallStrategy.java
  30. 228 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/tab/TabService.java
  31. 34 0
      recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/web/TabController.java

+ 5 - 1
recommend-server-client/pom.xml

@@ -10,7 +10,11 @@
     <modelVersion>4.0.0</modelVersion>
 
     <artifactId>recommend-server-client</artifactId>
-    <version>1.1.13</version>
+    <version>1.1.14</version>
+
+    <!-- <properties> -->
+    <!--     <os.detected.classifier>osx-x86_64</os.detected.classifier> -->
+    <!-- </properties> -->
 
     <dependencies>
         <dependency>

+ 15 - 2
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/common/Common.java

@@ -19,6 +19,11 @@ public final class Common {
   static final 
     com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
       internal_static_Result_fieldAccessorTable;
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_TabProto_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_TabProto_fieldAccessorTable;
 
   public static com.google.protobuf.Descriptors.FileDescriptor
       getDescriptor() {
@@ -30,8 +35,10 @@ public final class Common {
     java.lang.String[] descriptorData = {
       "\n/com/tzld/piaoquan/recommend/server/com" +
       "mon.proto\"\'\n\006Result\022\014\n\004code\030\001 \001(\005\022\017\n\007mes" +
-      "sage\030\002 \001(\tB1\n-com.tzld.piaoquan.recommen" +
-      "d.server.gen.commonP\001b\006proto3"
+      "sage\030\002 \001(\t\"D\n\010TabProto\022\013\n\003key\030\001 \001(\t\022\r\n\005t" +
+      "itle\030\002 \001(\t\022\014\n\004type\030\003 \001(\t\022\016\n\006source\030\004 \001(\t" +
+      "B1\n-com.tzld.piaoquan.recommend.server.g" +
+      "en.commonP\001b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -43,6 +50,12 @@ public final class Common {
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_Result_descriptor,
         new java.lang.String[] { "Code", "Message", });
+    internal_static_TabProto_descriptor =
+      getDescriptor().getMessageTypes().get(1);
+    internal_static_TabProto_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_TabProto_descriptor,
+        new java.lang.String[] { "Key", "Title", "Type", "Source", });
   }
 
   // @@protoc_insertion_point(outer_class_scope)

+ 979 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/common/TabProto.java

@@ -0,0 +1,979 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/server/common.proto
+
+package com.tzld.piaoquan.recommend.server.gen.common;
+
+/**
+ * <pre>
+ * Tab标签信息
+ * </pre>
+ *
+ * Protobuf type {@code TabProto}
+ */
+public final class TabProto extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:TabProto)
+    TabProtoOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use TabProto.newBuilder() to construct.
+  private TabProto(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private TabProto() {
+    key_ = "";
+    title_ = "";
+    type_ = "";
+    source_ = "";
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new TabProto();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private TabProto(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 10: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            key_ = s;
+            break;
+          }
+          case 18: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            title_ = s;
+            break;
+          }
+          case 26: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            type_ = s;
+            break;
+          }
+          case 34: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            source_ = s;
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.server.gen.common.Common.internal_static_TabProto_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.server.gen.common.Common.internal_static_TabProto_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.server.gen.common.TabProto.class, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder.class);
+  }
+
+  public static final int KEY_FIELD_NUMBER = 1;
+  private volatile java.lang.Object key_;
+  /**
+   * <code>string key = 1;</code>
+   * @return The key.
+   */
+  @java.lang.Override
+  public java.lang.String getKey() {
+    java.lang.Object ref = key_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      key_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string key = 1;</code>
+   * @return The bytes for key.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getKeyBytes() {
+    java.lang.Object ref = key_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      key_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int TITLE_FIELD_NUMBER = 2;
+  private volatile java.lang.Object title_;
+  /**
+   * <code>string title = 2;</code>
+   * @return The title.
+   */
+  @java.lang.Override
+  public java.lang.String getTitle() {
+    java.lang.Object ref = title_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      title_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string title = 2;</code>
+   * @return The bytes for title.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getTitleBytes() {
+    java.lang.Object ref = title_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      title_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int TYPE_FIELD_NUMBER = 3;
+  private volatile java.lang.Object type_;
+  /**
+   * <code>string type = 3;</code>
+   * @return The type.
+   */
+  @java.lang.Override
+  public java.lang.String getType() {
+    java.lang.Object ref = type_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      type_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string type = 3;</code>
+   * @return The bytes for type.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getTypeBytes() {
+    java.lang.Object ref = type_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      type_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int SOURCE_FIELD_NUMBER = 4;
+  private volatile java.lang.Object source_;
+  /**
+   * <code>string source = 4;</code>
+   * @return The source.
+   */
+  @java.lang.Override
+  public java.lang.String getSource() {
+    java.lang.Object ref = source_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      source_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string source = 4;</code>
+   * @return The bytes for source.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getSourceBytes() {
+    java.lang.Object ref = source_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      source_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (!getKeyBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 1, key_);
+    }
+    if (!getTitleBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 2, title_);
+    }
+    if (!getTypeBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 3, type_);
+    }
+    if (!getSourceBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 4, source_);
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (!getKeyBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, key_);
+    }
+    if (!getTitleBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, title_);
+    }
+    if (!getTypeBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, type_);
+    }
+    if (!getSourceBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(4, source_);
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.server.gen.common.TabProto)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.server.gen.common.TabProto other = (com.tzld.piaoquan.recommend.server.gen.common.TabProto) obj;
+
+    if (!getKey()
+        .equals(other.getKey())) return false;
+    if (!getTitle()
+        .equals(other.getTitle())) return false;
+    if (!getType()
+        .equals(other.getType())) return false;
+    if (!getSource()
+        .equals(other.getSource())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + KEY_FIELD_NUMBER;
+    hash = (53 * hash) + getKey().hashCode();
+    hash = (37 * hash) + TITLE_FIELD_NUMBER;
+    hash = (53 * hash) + getTitle().hashCode();
+    hash = (37 * hash) + TYPE_FIELD_NUMBER;
+    hash = (53 * hash) + getType().hashCode();
+    hash = (37 * hash) + SOURCE_FIELD_NUMBER;
+    hash = (53 * hash) + getSource().hashCode();
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.server.gen.common.TabProto prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * <pre>
+   * Tab标签信息
+   * </pre>
+   *
+   * Protobuf type {@code TabProto}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:TabProto)
+      com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.server.gen.common.Common.internal_static_TabProto_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.server.gen.common.Common.internal_static_TabProto_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.server.gen.common.TabProto.class, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.server.gen.common.TabProto.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      key_ = "";
+
+      title_ = "";
+
+      type_ = "";
+
+      source_ = "";
+
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.server.gen.common.Common.internal_static_TabProto_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.server.gen.common.TabProto.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto build() {
+      com.tzld.piaoquan.recommend.server.gen.common.TabProto result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto buildPartial() {
+      com.tzld.piaoquan.recommend.server.gen.common.TabProto result = new com.tzld.piaoquan.recommend.server.gen.common.TabProto(this);
+      result.key_ = key_;
+      result.title_ = title_;
+      result.type_ = type_;
+      result.source_ = source_;
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.server.gen.common.TabProto) {
+        return mergeFrom((com.tzld.piaoquan.recommend.server.gen.common.TabProto)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.server.gen.common.TabProto other) {
+      if (other == com.tzld.piaoquan.recommend.server.gen.common.TabProto.getDefaultInstance()) return this;
+      if (!other.getKey().isEmpty()) {
+        key_ = other.key_;
+        onChanged();
+      }
+      if (!other.getTitle().isEmpty()) {
+        title_ = other.title_;
+        onChanged();
+      }
+      if (!other.getType().isEmpty()) {
+        type_ = other.type_;
+        onChanged();
+      }
+      if (!other.getSource().isEmpty()) {
+        source_ = other.source_;
+        onChanged();
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.server.gen.common.TabProto parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.server.gen.common.TabProto) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+
+    private java.lang.Object key_ = "";
+    /**
+     * <code>string key = 1;</code>
+     * @return The key.
+     */
+    public java.lang.String getKey() {
+      java.lang.Object ref = key_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        key_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string key = 1;</code>
+     * @return The bytes for key.
+     */
+    public com.google.protobuf.ByteString
+        getKeyBytes() {
+      java.lang.Object ref = key_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        key_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string key = 1;</code>
+     * @param value The key to set.
+     * @return This builder for chaining.
+     */
+    public Builder setKey(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      key_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string key = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearKey() {
+      
+      key_ = getDefaultInstance().getKey();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string key = 1;</code>
+     * @param value The bytes for key to set.
+     * @return This builder for chaining.
+     */
+    public Builder setKeyBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      key_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object title_ = "";
+    /**
+     * <code>string title = 2;</code>
+     * @return The title.
+     */
+    public java.lang.String getTitle() {
+      java.lang.Object ref = title_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        title_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string title = 2;</code>
+     * @return The bytes for title.
+     */
+    public com.google.protobuf.ByteString
+        getTitleBytes() {
+      java.lang.Object ref = title_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        title_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string title = 2;</code>
+     * @param value The title to set.
+     * @return This builder for chaining.
+     */
+    public Builder setTitle(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      title_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string title = 2;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearTitle() {
+      
+      title_ = getDefaultInstance().getTitle();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string title = 2;</code>
+     * @param value The bytes for title to set.
+     * @return This builder for chaining.
+     */
+    public Builder setTitleBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      title_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object type_ = "";
+    /**
+     * <code>string type = 3;</code>
+     * @return The type.
+     */
+    public java.lang.String getType() {
+      java.lang.Object ref = type_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        type_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string type = 3;</code>
+     * @return The bytes for type.
+     */
+    public com.google.protobuf.ByteString
+        getTypeBytes() {
+      java.lang.Object ref = type_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        type_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string type = 3;</code>
+     * @param value The type to set.
+     * @return This builder for chaining.
+     */
+    public Builder setType(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      type_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string type = 3;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearType() {
+      
+      type_ = getDefaultInstance().getType();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string type = 3;</code>
+     * @param value The bytes for type to set.
+     * @return This builder for chaining.
+     */
+    public Builder setTypeBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      type_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object source_ = "";
+    /**
+     * <code>string source = 4;</code>
+     * @return The source.
+     */
+    public java.lang.String getSource() {
+      java.lang.Object ref = source_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        source_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string source = 4;</code>
+     * @return The bytes for source.
+     */
+    public com.google.protobuf.ByteString
+        getSourceBytes() {
+      java.lang.Object ref = source_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        source_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string source = 4;</code>
+     * @param value The source to set.
+     * @return This builder for chaining.
+     */
+    public Builder setSource(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      source_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string source = 4;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearSource() {
+      
+      source_ = getDefaultInstance().getSource();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string source = 4;</code>
+     * @param value The bytes for source to set.
+     * @return This builder for chaining.
+     */
+    public Builder setSourceBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      source_ = value;
+      onChanged();
+      return this;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:TabProto)
+  }
+
+  // @@protoc_insertion_point(class_scope:TabProto)
+  private static final com.tzld.piaoquan.recommend.server.gen.common.TabProto DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.server.gen.common.TabProto();
+  }
+
+  public static com.tzld.piaoquan.recommend.server.gen.common.TabProto getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<TabProto>
+      PARSER = new com.google.protobuf.AbstractParser<TabProto>() {
+    @java.lang.Override
+    public TabProto parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new TabProto(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<TabProto> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<TabProto> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.common.TabProto getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 57 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/common/TabProtoOrBuilder.java

@@ -0,0 +1,57 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/server/common.proto
+
+package com.tzld.piaoquan.recommend.server.gen.common;
+
+public interface TabProtoOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:TabProto)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>string key = 1;</code>
+   * @return The key.
+   */
+  java.lang.String getKey();
+  /**
+   * <code>string key = 1;</code>
+   * @return The bytes for key.
+   */
+  com.google.protobuf.ByteString
+      getKeyBytes();
+
+  /**
+   * <code>string title = 2;</code>
+   * @return The title.
+   */
+  java.lang.String getTitle();
+  /**
+   * <code>string title = 2;</code>
+   * @return The bytes for title.
+   */
+  com.google.protobuf.ByteString
+      getTitleBytes();
+
+  /**
+   * <code>string type = 3;</code>
+   * @return The type.
+   */
+  java.lang.String getType();
+  /**
+   * <code>string type = 3;</code>
+   * @return The bytes for type.
+   */
+  com.google.protobuf.ByteString
+      getTypeBytes();
+
+  /**
+   * <code>string source = 4;</code>
+   * @return The source.
+   */
+  java.lang.String getSource();
+  /**
+   * <code>string source = 4;</code>
+   * @return The bytes for source.
+   */
+  com.google.protobuf.ByteString
+      getSourceBytes();
+}

+ 23 - 22
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/Recommend.java

@@ -61,7 +61,7 @@ public final class Recommend {
       "\n2com/tzld/piaoquan/recommend/server/rec" +
       "ommend.proto\032\031google/protobuf/any.proto\032" +
       "/com/tzld/piaoquan/recommend/server/comm" +
-      "on.proto\"\241\006\n\020RecommendRequest\022\022\n\nrequest" +
+      "on.proto\"\271\006\n\020RecommendRequest\022\022\n\nrequest" +
       "_id\030\001 \001(\t\022\013\n\003mid\030\002 \001(\t\022\013\n\003uid\030\003 \001(\t\022\014\n\004s" +
       "ize\030\004 \001(\005\022\020\n\010app_type\030\005 \001(\005\022\021\n\tcity_code" +
       "\030\006 \001(\t\022\025\n\rprovince_code\030\007 \001(\t\022\023\n\013ab_exp_" +
@@ -80,26 +80,27 @@ public final class Recommend {
       "_list\030\034 \003(\0132\025.VideoActionInfoProto\022\030\n\020re" +
       "quest_video_id\030\035 \001(\003\022\033\n\023current_page_sou" +
       "rce\030\036 \001(\t\022\017\n\007openGId\030\037 \001(\t\022\020\n\010union_id\030 " +
-      " \001(\t\032.\n\014EventIdEntry\022\013\n\003key\030\001 \001(\t\022\r\n\005val" +
-      "ue\030\002 \001(\t:\0028\001\"\177\n\020MachineInfoProto\022\r\n\005bran" +
-      "d\030\001 \001(\t\022\r\n\005model\030\002 \001(\t\022\020\n\010platform\030\003 \001(\t" +
-      "\022\023\n\013sdk_version\030\004 \001(\t\022\016\n\006system\030\005 \001(\t\022\026\n" +
-      "\016wechat_version\030\006 \001(\t\"H\n\021RecommendRespon" +
-      "se\022\027\n\006result\030\001 \001(\0132\007.Result\022\032\n\005video\030\002 \003" +
-      "(\0132\013.VideoProto\"\336\001\n\nVideoProto\022\020\n\010video_" +
-      "id\030\001 \001(\003\022\021\n\trov_score\030\002 \001(\001\022\021\n\tpush_from" +
-      "\030\003 \001(\t\022\017\n\007ab_code\030\004 \001(\t\022\022\n\nsort_score\030\005 " +
-      "\001(\001\022\020\n\010position\030\006 \001(\005\022\021\n\tflow_pool\030\007 \001(\t" +
-      "\022\027\n\017is_in_flow_pool\030\010 \001(\005\022\014\n\004rand\030\t \001(\001\022" +
-      "\'\n\017push_from_index\030\n \003(\0132\016.PushFromIndex" +
-      "\"1\n\rPushFromIndex\022\021\n\tpush_from\030\001 \001(\t\022\r\n\005" +
-      "index\030\002 \003(\t\"4\n\024VideoActionInfoProto\022\020\n\010v" +
-      "ideo_id\030\001 \001(\003\022\n\n\002ts\030\002 \001(\0032\212\001\n\020RecommendS" +
-      "ervice\022:\n\021HomepageRecommend\022\021.RecommendR" +
-      "equest\032\022.RecommendResponse\022:\n\021RelevantRe" +
-      "commend\022\021.RecommendRequest\032\022.RecommendRe" +
-      "sponseB7\n0com.tzld.piaoquan.recommend.se" +
-      "rver.gen.recommendP\001\210\001\001b\006proto3"
+      " \001(\t\022\026\n\003tab\030! \001(\0132\t.TabProto\032.\n\014EventIdE" +
+      "ntry\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t:\0028\001\"\177\n\020" +
+      "MachineInfoProto\022\r\n\005brand\030\001 \001(\t\022\r\n\005model" +
+      "\030\002 \001(\t\022\020\n\010platform\030\003 \001(\t\022\023\n\013sdk_version\030" +
+      "\004 \001(\t\022\016\n\006system\030\005 \001(\t\022\026\n\016wechat_version\030" +
+      "\006 \001(\t\"H\n\021RecommendResponse\022\027\n\006result\030\001 \001" +
+      "(\0132\007.Result\022\032\n\005video\030\002 \003(\0132\013.VideoProto\"" +
+      "\336\001\n\nVideoProto\022\020\n\010video_id\030\001 \001(\003\022\021\n\trov_" +
+      "score\030\002 \001(\001\022\021\n\tpush_from\030\003 \001(\t\022\017\n\007ab_cod" +
+      "e\030\004 \001(\t\022\022\n\nsort_score\030\005 \001(\001\022\020\n\010position\030" +
+      "\006 \001(\005\022\021\n\tflow_pool\030\007 \001(\t\022\027\n\017is_in_flow_p" +
+      "ool\030\010 \001(\005\022\014\n\004rand\030\t \001(\001\022\'\n\017push_from_ind" +
+      "ex\030\n \003(\0132\016.PushFromIndex\"1\n\rPushFromInde" +
+      "x\022\021\n\tpush_from\030\001 \001(\t\022\r\n\005index\030\002 \003(\t\"4\n\024V" +
+      "ideoActionInfoProto\022\020\n\010video_id\030\001 \001(\003\022\n\n" +
+      "\002ts\030\002 \001(\0032\212\001\n\020RecommendService\022:\n\021Homepa" +
+      "geRecommend\022\021.RecommendRequest\032\022.Recomme" +
+      "ndResponse\022:\n\021RelevantRecommend\022\021.Recomm" +
+      "endRequest\032\022.RecommendResponseB7\n0com.tz" +
+      "ld.piaoquan.recommend.server.gen.recomme" +
+      "ndP\001\210\001\001b\006proto3"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -112,7 +113,7 @@ public final class Recommend {
     internal_static_RecommendRequest_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_RecommendRequest_descriptor,
-        new java.lang.String[] { "RequestId", "Mid", "Uid", "Size", "AppType", "CityCode", "ProvinceCode", "AbExpCode", "EventId", "VersionAuditStatus", "RecommendTraceId", "VideoId", "City", "Province", "MachineInfo", "NewExpGroup", "SessionId", "SubSessionId", "PageSource", "CategoryId", "HotSceneType", "ClientIp", "VersionCode", "RootSourceId", "UserShareDepth", "PageNum", "RootSessionId", "ShareList", "RequestVideoId", "CurrentPageSource", "OpenGId", "UnionId", });
+        new java.lang.String[] { "RequestId", "Mid", "Uid", "Size", "AppType", "CityCode", "ProvinceCode", "AbExpCode", "EventId", "VersionAuditStatus", "RecommendTraceId", "VideoId", "City", "Province", "MachineInfo", "NewExpGroup", "SessionId", "SubSessionId", "PageSource", "CategoryId", "HotSceneType", "ClientIp", "VersionCode", "RootSourceId", "UserShareDepth", "PageNum", "RootSessionId", "ShareList", "RequestVideoId", "CurrentPageSource", "OpenGId", "UnionId", "Tab", });
     internal_static_RecommendRequest_EventIdEntry_descriptor =
       internal_static_RecommendRequest_descriptor.getNestedTypes().get(0);
     internal_static_RecommendRequest_EventIdEntry_fieldAccessorTable = new

+ 188 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequest.java

@@ -273,6 +273,19 @@ private static final long serialVersionUID = 0L;
             unionId_ = s;
             break;
           }
+          case 266: {
+            com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder subBuilder = null;
+            if (tab_ != null) {
+              subBuilder = tab_.toBuilder();
+            }
+            tab_ = input.readMessage(com.tzld.piaoquan.recommend.server.gen.common.TabProto.parser(), extensionRegistry);
+            if (subBuilder != null) {
+              subBuilder.mergeFrom(tab_);
+              tab_ = subBuilder.buildPartial();
+            }
+
+            break;
+          }
           default: {
             if (!parseUnknownField(
                 input, unknownFields, extensionRegistry, tag)) {
@@ -1342,6 +1355,32 @@ private static final long serialVersionUID = 0L;
     }
   }
 
+  public static final int TAB_FIELD_NUMBER = 33;
+  private com.tzld.piaoquan.recommend.server.gen.common.TabProto tab_;
+  /**
+   * <code>.TabProto tab = 33;</code>
+   * @return Whether the tab field is set.
+   */
+  @java.lang.Override
+  public boolean hasTab() {
+    return tab_ != null;
+  }
+  /**
+   * <code>.TabProto tab = 33;</code>
+   * @return The tab.
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.common.TabProto getTab() {
+    return tab_ == null ? com.tzld.piaoquan.recommend.server.gen.common.TabProto.getDefaultInstance() : tab_;
+  }
+  /**
+   * <code>.TabProto tab = 33;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder getTabOrBuilder() {
+    return getTab();
+  }
+
   private byte memoizedIsInitialized = -1;
   @java.lang.Override
   public final boolean isInitialized() {
@@ -1455,6 +1494,9 @@ private static final long serialVersionUID = 0L;
     if (!getUnionIdBytes().isEmpty()) {
       com.google.protobuf.GeneratedMessageV3.writeString(output, 32, unionId_);
     }
+    if (tab_ != null) {
+      output.writeMessage(33, getTab());
+    }
     unknownFields.writeTo(output);
   }
 
@@ -1583,6 +1625,10 @@ private static final long serialVersionUID = 0L;
     if (!getUnionIdBytes().isEmpty()) {
       size += com.google.protobuf.GeneratedMessageV3.computeStringSize(32, unionId_);
     }
+    if (tab_ != null) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(33, getTab());
+    }
     size += unknownFields.getSerializedSize();
     memoizedSize = size;
     return size;
@@ -1665,6 +1711,11 @@ private static final long serialVersionUID = 0L;
         .equals(other.getOpenGId())) return false;
     if (!getUnionId()
         .equals(other.getUnionId())) return false;
+    if (hasTab() != other.hasTab()) return false;
+    if (hasTab()) {
+      if (!getTab()
+          .equals(other.getTab())) return false;
+    }
     if (!unknownFields.equals(other.unknownFields)) return false;
     return true;
   }
@@ -1751,6 +1802,10 @@ private static final long serialVersionUID = 0L;
     hash = (53 * hash) + getOpenGId().hashCode();
     hash = (37 * hash) + UNION_ID_FIELD_NUMBER;
     hash = (53 * hash) + getUnionId().hashCode();
+    if (hasTab()) {
+      hash = (37 * hash) + TAB_FIELD_NUMBER;
+      hash = (53 * hash) + getTab().hashCode();
+    }
     hash = (29 * hash) + unknownFields.hashCode();
     memoizedHashCode = hash;
     return hash;
@@ -1978,6 +2033,12 @@ private static final long serialVersionUID = 0L;
 
       unionId_ = "";
 
+      if (tabBuilder_ == null) {
+        tab_ = null;
+      } else {
+        tab_ = null;
+        tabBuilder_ = null;
+      }
       return this;
     }
 
@@ -2054,6 +2115,11 @@ private static final long serialVersionUID = 0L;
       result.currentPageSource_ = currentPageSource_;
       result.openGId_ = openGId_;
       result.unionId_ = unionId_;
+      if (tabBuilder_ == null) {
+        result.tab_ = tab_;
+      } else {
+        result.tab_ = tabBuilder_.build();
+      }
       onBuilt();
       return result;
     }
@@ -2246,6 +2312,9 @@ private static final long serialVersionUID = 0L;
         unionId_ = other.unionId_;
         onChanged();
       }
+      if (other.hasTab()) {
+        mergeTab(other.getTab());
+      }
       this.mergeUnknownFields(other.unknownFields);
       onChanged();
       return this;
@@ -4643,6 +4712,125 @@ private static final long serialVersionUID = 0L;
       onChanged();
       return this;
     }
+
+    private com.tzld.piaoquan.recommend.server.gen.common.TabProto tab_;
+    private com.google.protobuf.SingleFieldBuilderV3<
+        com.tzld.piaoquan.recommend.server.gen.common.TabProto, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder, com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder> tabBuilder_;
+    /**
+     * <code>.TabProto tab = 33;</code>
+     * @return Whether the tab field is set.
+     */
+    public boolean hasTab() {
+      return tabBuilder_ != null || tab_ != null;
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     * @return The tab.
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto getTab() {
+      if (tabBuilder_ == null) {
+        return tab_ == null ? com.tzld.piaoquan.recommend.server.gen.common.TabProto.getDefaultInstance() : tab_;
+      } else {
+        return tabBuilder_.getMessage();
+      }
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     */
+    public Builder setTab(com.tzld.piaoquan.recommend.server.gen.common.TabProto value) {
+      if (tabBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        tab_ = value;
+        onChanged();
+      } else {
+        tabBuilder_.setMessage(value);
+      }
+
+      return this;
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     */
+    public Builder setTab(
+        com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder builderForValue) {
+      if (tabBuilder_ == null) {
+        tab_ = builderForValue.build();
+        onChanged();
+      } else {
+        tabBuilder_.setMessage(builderForValue.build());
+      }
+
+      return this;
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     */
+    public Builder mergeTab(com.tzld.piaoquan.recommend.server.gen.common.TabProto value) {
+      if (tabBuilder_ == null) {
+        if (tab_ != null) {
+          tab_ =
+            com.tzld.piaoquan.recommend.server.gen.common.TabProto.newBuilder(tab_).mergeFrom(value).buildPartial();
+        } else {
+          tab_ = value;
+        }
+        onChanged();
+      } else {
+        tabBuilder_.mergeFrom(value);
+      }
+
+      return this;
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     */
+    public Builder clearTab() {
+      if (tabBuilder_ == null) {
+        tab_ = null;
+        onChanged();
+      } else {
+        tab_ = null;
+        tabBuilder_ = null;
+      }
+
+      return this;
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder getTabBuilder() {
+      
+      onChanged();
+      return getTabFieldBuilder().getBuilder();
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder getTabOrBuilder() {
+      if (tabBuilder_ != null) {
+        return tabBuilder_.getMessageOrBuilder();
+      } else {
+        return tab_ == null ?
+            com.tzld.piaoquan.recommend.server.gen.common.TabProto.getDefaultInstance() : tab_;
+      }
+    }
+    /**
+     * <code>.TabProto tab = 33;</code>
+     */
+    private com.google.protobuf.SingleFieldBuilderV3<
+        com.tzld.piaoquan.recommend.server.gen.common.TabProto, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder, com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder> 
+        getTabFieldBuilder() {
+      if (tabBuilder_ == null) {
+        tabBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
+            com.tzld.piaoquan.recommend.server.gen.common.TabProto, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder, com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder>(
+                getTab(),
+                getParentForChildren(),
+                isClean());
+        tab_ = null;
+      }
+      return tabBuilder_;
+    }
     @java.lang.Override
     public final Builder setUnknownFields(
         final com.google.protobuf.UnknownFieldSet unknownFields) {

+ 15 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/recommend/RecommendRequestOrBuilder.java

@@ -402,4 +402,19 @@ public interface RecommendRequestOrBuilder extends
    */
   com.google.protobuf.ByteString
       getUnionIdBytes();
+
+  /**
+   * <code>.TabProto tab = 33;</code>
+   * @return Whether the tab field is set.
+   */
+  boolean hasTab();
+  /**
+   * <code>.TabProto tab = 33;</code>
+   * @return The tab.
+   */
+  com.tzld.piaoquan.recommend.server.gen.common.TabProto getTab();
+  /**
+   * <code>.TabProto tab = 33;</code>
+   */
+  com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder getTabOrBuilder();
 }

+ 72 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/Tab.java

@@ -0,0 +1,72 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/server/tab.proto
+
+package com.tzld.piaoquan.recommend.server.gen.tab;
+
+public final class Tab {
+  private Tab() {}
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistryLite registry) {
+  }
+
+  public static void registerAllExtensions(
+      com.google.protobuf.ExtensionRegistry registry) {
+    registerAllExtensions(
+        (com.google.protobuf.ExtensionRegistryLite) registry);
+  }
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_TabRequest_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_TabRequest_fieldAccessorTable;
+  static final com.google.protobuf.Descriptors.Descriptor
+    internal_static_TabResponse_descriptor;
+  static final 
+    com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internal_static_TabResponse_fieldAccessorTable;
+
+  public static com.google.protobuf.Descriptors.FileDescriptor
+      getDescriptor() {
+    return descriptor;
+  }
+  private static  com.google.protobuf.Descriptors.FileDescriptor
+      descriptor;
+  static {
+    java.lang.String[] descriptorData = {
+      "\n,com/tzld/piaoquan/recommend/server/tab" +
+      ".proto\032\031google/protobuf/any.proto\032/com/t" +
+      "zld/piaoquan/recommend/server/common.pro" +
+      "to\"\326\001\n\nTabRequest\022\022\n\nrequest_id\030\001 \001(\t\022\013\n" +
+      "\003mid\030\002 \001(\t\022\013\n\003uid\030\003 \001(\t\022\020\n\010app_type\030\004 \001(" +
+      "\005\022\020\n\010union_id\030\005 \001(\t\022\021\n\tcity_code\030\006 \001(\t\022\025" +
+      "\n\rprovince_code\030\007 \001(\t\022\014\n\004city\030\010 \001(\t\022\020\n\010p" +
+      "rovince\030\t \001(\t\022\023\n\013ab_exp_code\030\n \003(\t\022\027\n\017ro" +
+      "ot_session_id\030\013 \001(\t\">\n\013TabResponse\022\027\n\006re" +
+      "sult\030\001 \001(\0132\007.Result\022\026\n\003tab\030\002 \003(\0132\t.TabPr" +
+      "otoB1\n*com.tzld.piaoquan.recommend.serve" +
+      "r.gen.tabP\001\210\001\001b\006proto3"
+    };
+    descriptor = com.google.protobuf.Descriptors.FileDescriptor
+      .internalBuildGeneratedFileFrom(descriptorData,
+        new com.google.protobuf.Descriptors.FileDescriptor[] {
+          com.google.protobuf.AnyProto.getDescriptor(),
+          com.tzld.piaoquan.recommend.server.gen.common.Common.getDescriptor(),
+        });
+    internal_static_TabRequest_descriptor =
+      getDescriptor().getMessageTypes().get(0);
+    internal_static_TabRequest_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_TabRequest_descriptor,
+        new java.lang.String[] { "RequestId", "Mid", "Uid", "AppType", "UnionId", "CityCode", "ProvinceCode", "City", "Province", "AbExpCode", "RootSessionId", });
+    internal_static_TabResponse_descriptor =
+      getDescriptor().getMessageTypes().get(1);
+    internal_static_TabResponse_fieldAccessorTable = new
+      com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
+        internal_static_TabResponse_descriptor,
+        new java.lang.String[] { "Result", "Tab", });
+    com.google.protobuf.AnyProto.getDescriptor();
+    com.tzld.piaoquan.recommend.server.gen.common.Common.getDescriptor();
+  }
+
+  // @@protoc_insertion_point(outer_class_scope)
+}

+ 1936 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabRequest.java

@@ -0,0 +1,1936 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/server/tab.proto
+
+package com.tzld.piaoquan.recommend.server.gen.tab;
+
+/**
+ * Protobuf type {@code TabRequest}
+ */
+public final class TabRequest extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:TabRequest)
+    TabRequestOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use TabRequest.newBuilder() to construct.
+  private TabRequest(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private TabRequest() {
+    requestId_ = "";
+    mid_ = "";
+    uid_ = "";
+    unionId_ = "";
+    cityCode_ = "";
+    provinceCode_ = "";
+    city_ = "";
+    province_ = "";
+    abExpCode_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+    rootSessionId_ = "";
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new TabRequest();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private TabRequest(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    int mutable_bitField0_ = 0;
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 10: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            requestId_ = s;
+            break;
+          }
+          case 18: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            mid_ = s;
+            break;
+          }
+          case 26: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            uid_ = s;
+            break;
+          }
+          case 32: {
+
+            appType_ = input.readInt32();
+            break;
+          }
+          case 42: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            unionId_ = s;
+            break;
+          }
+          case 50: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            cityCode_ = s;
+            break;
+          }
+          case 58: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            provinceCode_ = s;
+            break;
+          }
+          case 66: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            city_ = s;
+            break;
+          }
+          case 74: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            province_ = s;
+            break;
+          }
+          case 82: {
+            java.lang.String s = input.readStringRequireUtf8();
+            if (!((mutable_bitField0_ & 0x00000001) != 0)) {
+              abExpCode_ = new com.google.protobuf.LazyStringArrayList();
+              mutable_bitField0_ |= 0x00000001;
+            }
+            abExpCode_.add(s);
+            break;
+          }
+          case 90: {
+            java.lang.String s = input.readStringRequireUtf8();
+
+            rootSessionId_ = s;
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      if (((mutable_bitField0_ & 0x00000001) != 0)) {
+        abExpCode_ = abExpCode_.getUnmodifiableView();
+      }
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabRequest_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabRequest_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.server.gen.tab.TabRequest.class, com.tzld.piaoquan.recommend.server.gen.tab.TabRequest.Builder.class);
+  }
+
+  public static final int REQUEST_ID_FIELD_NUMBER = 1;
+  private volatile java.lang.Object requestId_;
+  /**
+   * <code>string request_id = 1;</code>
+   * @return The requestId.
+   */
+  @java.lang.Override
+  public java.lang.String getRequestId() {
+    java.lang.Object ref = requestId_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      requestId_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string request_id = 1;</code>
+   * @return The bytes for requestId.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getRequestIdBytes() {
+    java.lang.Object ref = requestId_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      requestId_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int MID_FIELD_NUMBER = 2;
+  private volatile java.lang.Object mid_;
+  /**
+   * <code>string mid = 2;</code>
+   * @return The mid.
+   */
+  @java.lang.Override
+  public java.lang.String getMid() {
+    java.lang.Object ref = mid_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      mid_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string mid = 2;</code>
+   * @return The bytes for mid.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getMidBytes() {
+    java.lang.Object ref = mid_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      mid_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int UID_FIELD_NUMBER = 3;
+  private volatile java.lang.Object uid_;
+  /**
+   * <code>string uid = 3;</code>
+   * @return The uid.
+   */
+  @java.lang.Override
+  public java.lang.String getUid() {
+    java.lang.Object ref = uid_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      uid_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string uid = 3;</code>
+   * @return The bytes for uid.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getUidBytes() {
+    java.lang.Object ref = uid_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      uid_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int APP_TYPE_FIELD_NUMBER = 4;
+  private int appType_;
+  /**
+   * <pre>
+   * default 4
+   * </pre>
+   *
+   * <code>int32 app_type = 4;</code>
+   * @return The appType.
+   */
+  @java.lang.Override
+  public int getAppType() {
+    return appType_;
+  }
+
+  public static final int UNION_ID_FIELD_NUMBER = 5;
+  private volatile java.lang.Object unionId_;
+  /**
+   * <code>string union_id = 5;</code>
+   * @return The unionId.
+   */
+  @java.lang.Override
+  public java.lang.String getUnionId() {
+    java.lang.Object ref = unionId_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      unionId_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string union_id = 5;</code>
+   * @return The bytes for unionId.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getUnionIdBytes() {
+    java.lang.Object ref = unionId_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      unionId_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int CITY_CODE_FIELD_NUMBER = 6;
+  private volatile java.lang.Object cityCode_;
+  /**
+   * <code>string city_code = 6;</code>
+   * @return The cityCode.
+   */
+  @java.lang.Override
+  public java.lang.String getCityCode() {
+    java.lang.Object ref = cityCode_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      cityCode_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string city_code = 6;</code>
+   * @return The bytes for cityCode.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getCityCodeBytes() {
+    java.lang.Object ref = cityCode_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      cityCode_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int PROVINCE_CODE_FIELD_NUMBER = 7;
+  private volatile java.lang.Object provinceCode_;
+  /**
+   * <code>string province_code = 7;</code>
+   * @return The provinceCode.
+   */
+  @java.lang.Override
+  public java.lang.String getProvinceCode() {
+    java.lang.Object ref = provinceCode_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      provinceCode_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string province_code = 7;</code>
+   * @return The bytes for provinceCode.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getProvinceCodeBytes() {
+    java.lang.Object ref = provinceCode_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      provinceCode_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int CITY_FIELD_NUMBER = 8;
+  private volatile java.lang.Object city_;
+  /**
+   * <code>string city = 8;</code>
+   * @return The city.
+   */
+  @java.lang.Override
+  public java.lang.String getCity() {
+    java.lang.Object ref = city_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      city_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string city = 8;</code>
+   * @return The bytes for city.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getCityBytes() {
+    java.lang.Object ref = city_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      city_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int PROVINCE_FIELD_NUMBER = 9;
+  private volatile java.lang.Object province_;
+  /**
+   * <code>string province = 9;</code>
+   * @return The province.
+   */
+  @java.lang.Override
+  public java.lang.String getProvince() {
+    java.lang.Object ref = province_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      province_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string province = 9;</code>
+   * @return The bytes for province.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getProvinceBytes() {
+    java.lang.Object ref = province_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      province_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  public static final int AB_EXP_CODE_FIELD_NUMBER = 10;
+  private com.google.protobuf.LazyStringList abExpCode_;
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @return A list containing the abExpCode.
+   */
+  public com.google.protobuf.ProtocolStringList
+      getAbExpCodeList() {
+    return abExpCode_;
+  }
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @return The count of abExpCode.
+   */
+  public int getAbExpCodeCount() {
+    return abExpCode_.size();
+  }
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @param index The index of the element to return.
+   * @return The abExpCode at the given index.
+   */
+  public java.lang.String getAbExpCode(int index) {
+    return abExpCode_.get(index);
+  }
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @param index The index of the value to return.
+   * @return The bytes of the abExpCode at the given index.
+   */
+  public com.google.protobuf.ByteString
+      getAbExpCodeBytes(int index) {
+    return abExpCode_.getByteString(index);
+  }
+
+  public static final int ROOT_SESSION_ID_FIELD_NUMBER = 11;
+  private volatile java.lang.Object rootSessionId_;
+  /**
+   * <code>string root_session_id = 11;</code>
+   * @return The rootSessionId.
+   */
+  @java.lang.Override
+  public java.lang.String getRootSessionId() {
+    java.lang.Object ref = rootSessionId_;
+    if (ref instanceof java.lang.String) {
+      return (java.lang.String) ref;
+    } else {
+      com.google.protobuf.ByteString bs = 
+          (com.google.protobuf.ByteString) ref;
+      java.lang.String s = bs.toStringUtf8();
+      rootSessionId_ = s;
+      return s;
+    }
+  }
+  /**
+   * <code>string root_session_id = 11;</code>
+   * @return The bytes for rootSessionId.
+   */
+  @java.lang.Override
+  public com.google.protobuf.ByteString
+      getRootSessionIdBytes() {
+    java.lang.Object ref = rootSessionId_;
+    if (ref instanceof java.lang.String) {
+      com.google.protobuf.ByteString b = 
+          com.google.protobuf.ByteString.copyFromUtf8(
+              (java.lang.String) ref);
+      rootSessionId_ = b;
+      return b;
+    } else {
+      return (com.google.protobuf.ByteString) ref;
+    }
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (!getRequestIdBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 1, requestId_);
+    }
+    if (!getMidBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 2, mid_);
+    }
+    if (!getUidBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 3, uid_);
+    }
+    if (appType_ != 0) {
+      output.writeInt32(4, appType_);
+    }
+    if (!getUnionIdBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 5, unionId_);
+    }
+    if (!getCityCodeBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 6, cityCode_);
+    }
+    if (!getProvinceCodeBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 7, provinceCode_);
+    }
+    if (!getCityBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 8, city_);
+    }
+    if (!getProvinceBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 9, province_);
+    }
+    for (int i = 0; i < abExpCode_.size(); i++) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 10, abExpCode_.getRaw(i));
+    }
+    if (!getRootSessionIdBytes().isEmpty()) {
+      com.google.protobuf.GeneratedMessageV3.writeString(output, 11, rootSessionId_);
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (!getRequestIdBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(1, requestId_);
+    }
+    if (!getMidBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(2, mid_);
+    }
+    if (!getUidBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(3, uid_);
+    }
+    if (appType_ != 0) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeInt32Size(4, appType_);
+    }
+    if (!getUnionIdBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(5, unionId_);
+    }
+    if (!getCityCodeBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(6, cityCode_);
+    }
+    if (!getProvinceCodeBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(7, provinceCode_);
+    }
+    if (!getCityBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(8, city_);
+    }
+    if (!getProvinceBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(9, province_);
+    }
+    {
+      int dataSize = 0;
+      for (int i = 0; i < abExpCode_.size(); i++) {
+        dataSize += computeStringSizeNoTag(abExpCode_.getRaw(i));
+      }
+      size += dataSize;
+      size += 1 * getAbExpCodeList().size();
+    }
+    if (!getRootSessionIdBytes().isEmpty()) {
+      size += com.google.protobuf.GeneratedMessageV3.computeStringSize(11, rootSessionId_);
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.server.gen.tab.TabRequest)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.server.gen.tab.TabRequest other = (com.tzld.piaoquan.recommend.server.gen.tab.TabRequest) obj;
+
+    if (!getRequestId()
+        .equals(other.getRequestId())) return false;
+    if (!getMid()
+        .equals(other.getMid())) return false;
+    if (!getUid()
+        .equals(other.getUid())) return false;
+    if (getAppType()
+        != other.getAppType()) return false;
+    if (!getUnionId()
+        .equals(other.getUnionId())) return false;
+    if (!getCityCode()
+        .equals(other.getCityCode())) return false;
+    if (!getProvinceCode()
+        .equals(other.getProvinceCode())) return false;
+    if (!getCity()
+        .equals(other.getCity())) return false;
+    if (!getProvince()
+        .equals(other.getProvince())) return false;
+    if (!getAbExpCodeList()
+        .equals(other.getAbExpCodeList())) return false;
+    if (!getRootSessionId()
+        .equals(other.getRootSessionId())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    hash = (37 * hash) + REQUEST_ID_FIELD_NUMBER;
+    hash = (53 * hash) + getRequestId().hashCode();
+    hash = (37 * hash) + MID_FIELD_NUMBER;
+    hash = (53 * hash) + getMid().hashCode();
+    hash = (37 * hash) + UID_FIELD_NUMBER;
+    hash = (53 * hash) + getUid().hashCode();
+    hash = (37 * hash) + APP_TYPE_FIELD_NUMBER;
+    hash = (53 * hash) + getAppType();
+    hash = (37 * hash) + UNION_ID_FIELD_NUMBER;
+    hash = (53 * hash) + getUnionId().hashCode();
+    hash = (37 * hash) + CITY_CODE_FIELD_NUMBER;
+    hash = (53 * hash) + getCityCode().hashCode();
+    hash = (37 * hash) + PROVINCE_CODE_FIELD_NUMBER;
+    hash = (53 * hash) + getProvinceCode().hashCode();
+    hash = (37 * hash) + CITY_FIELD_NUMBER;
+    hash = (53 * hash) + getCity().hashCode();
+    hash = (37 * hash) + PROVINCE_FIELD_NUMBER;
+    hash = (53 * hash) + getProvince().hashCode();
+    if (getAbExpCodeCount() > 0) {
+      hash = (37 * hash) + AB_EXP_CODE_FIELD_NUMBER;
+      hash = (53 * hash) + getAbExpCodeList().hashCode();
+    }
+    hash = (37 * hash) + ROOT_SESSION_ID_FIELD_NUMBER;
+    hash = (53 * hash) + getRootSessionId().hashCode();
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.server.gen.tab.TabRequest prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code TabRequest}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:TabRequest)
+      com.tzld.piaoquan.recommend.server.gen.tab.TabRequestOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabRequest_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabRequest_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.server.gen.tab.TabRequest.class, com.tzld.piaoquan.recommend.server.gen.tab.TabRequest.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.server.gen.tab.TabRequest.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      requestId_ = "";
+
+      mid_ = "";
+
+      uid_ = "";
+
+      appType_ = 0;
+
+      unionId_ = "";
+
+      cityCode_ = "";
+
+      provinceCode_ = "";
+
+      city_ = "";
+
+      province_ = "";
+
+      abExpCode_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+      bitField0_ = (bitField0_ & ~0x00000001);
+      rootSessionId_ = "";
+
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabRequest_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.tab.TabRequest getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.TabRequest.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.tab.TabRequest build() {
+      com.tzld.piaoquan.recommend.server.gen.tab.TabRequest result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.tab.TabRequest buildPartial() {
+      com.tzld.piaoquan.recommend.server.gen.tab.TabRequest result = new com.tzld.piaoquan.recommend.server.gen.tab.TabRequest(this);
+      int from_bitField0_ = bitField0_;
+      result.requestId_ = requestId_;
+      result.mid_ = mid_;
+      result.uid_ = uid_;
+      result.appType_ = appType_;
+      result.unionId_ = unionId_;
+      result.cityCode_ = cityCode_;
+      result.provinceCode_ = provinceCode_;
+      result.city_ = city_;
+      result.province_ = province_;
+      if (((bitField0_ & 0x00000001) != 0)) {
+        abExpCode_ = abExpCode_.getUnmodifiableView();
+        bitField0_ = (bitField0_ & ~0x00000001);
+      }
+      result.abExpCode_ = abExpCode_;
+      result.rootSessionId_ = rootSessionId_;
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.server.gen.tab.TabRequest) {
+        return mergeFrom((com.tzld.piaoquan.recommend.server.gen.tab.TabRequest)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.server.gen.tab.TabRequest other) {
+      if (other == com.tzld.piaoquan.recommend.server.gen.tab.TabRequest.getDefaultInstance()) return this;
+      if (!other.getRequestId().isEmpty()) {
+        requestId_ = other.requestId_;
+        onChanged();
+      }
+      if (!other.getMid().isEmpty()) {
+        mid_ = other.mid_;
+        onChanged();
+      }
+      if (!other.getUid().isEmpty()) {
+        uid_ = other.uid_;
+        onChanged();
+      }
+      if (other.getAppType() != 0) {
+        setAppType(other.getAppType());
+      }
+      if (!other.getUnionId().isEmpty()) {
+        unionId_ = other.unionId_;
+        onChanged();
+      }
+      if (!other.getCityCode().isEmpty()) {
+        cityCode_ = other.cityCode_;
+        onChanged();
+      }
+      if (!other.getProvinceCode().isEmpty()) {
+        provinceCode_ = other.provinceCode_;
+        onChanged();
+      }
+      if (!other.getCity().isEmpty()) {
+        city_ = other.city_;
+        onChanged();
+      }
+      if (!other.getProvince().isEmpty()) {
+        province_ = other.province_;
+        onChanged();
+      }
+      if (!other.abExpCode_.isEmpty()) {
+        if (abExpCode_.isEmpty()) {
+          abExpCode_ = other.abExpCode_;
+          bitField0_ = (bitField0_ & ~0x00000001);
+        } else {
+          ensureAbExpCodeIsMutable();
+          abExpCode_.addAll(other.abExpCode_);
+        }
+        onChanged();
+      }
+      if (!other.getRootSessionId().isEmpty()) {
+        rootSessionId_ = other.rootSessionId_;
+        onChanged();
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.server.gen.tab.TabRequest parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.server.gen.tab.TabRequest) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+    private int bitField0_;
+
+    private java.lang.Object requestId_ = "";
+    /**
+     * <code>string request_id = 1;</code>
+     * @return The requestId.
+     */
+    public java.lang.String getRequestId() {
+      java.lang.Object ref = requestId_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        requestId_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string request_id = 1;</code>
+     * @return The bytes for requestId.
+     */
+    public com.google.protobuf.ByteString
+        getRequestIdBytes() {
+      java.lang.Object ref = requestId_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        requestId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string request_id = 1;</code>
+     * @param value The requestId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setRequestId(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      requestId_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string request_id = 1;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearRequestId() {
+      
+      requestId_ = getDefaultInstance().getRequestId();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string request_id = 1;</code>
+     * @param value The bytes for requestId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setRequestIdBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      requestId_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object mid_ = "";
+    /**
+     * <code>string mid = 2;</code>
+     * @return The mid.
+     */
+    public java.lang.String getMid() {
+      java.lang.Object ref = mid_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        mid_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string mid = 2;</code>
+     * @return The bytes for mid.
+     */
+    public com.google.protobuf.ByteString
+        getMidBytes() {
+      java.lang.Object ref = mid_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        mid_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string mid = 2;</code>
+     * @param value The mid to set.
+     * @return This builder for chaining.
+     */
+    public Builder setMid(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      mid_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string mid = 2;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearMid() {
+      
+      mid_ = getDefaultInstance().getMid();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string mid = 2;</code>
+     * @param value The bytes for mid to set.
+     * @return This builder for chaining.
+     */
+    public Builder setMidBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      mid_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object uid_ = "";
+    /**
+     * <code>string uid = 3;</code>
+     * @return The uid.
+     */
+    public java.lang.String getUid() {
+      java.lang.Object ref = uid_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        uid_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string uid = 3;</code>
+     * @return The bytes for uid.
+     */
+    public com.google.protobuf.ByteString
+        getUidBytes() {
+      java.lang.Object ref = uid_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        uid_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string uid = 3;</code>
+     * @param value The uid to set.
+     * @return This builder for chaining.
+     */
+    public Builder setUid(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      uid_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string uid = 3;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearUid() {
+      
+      uid_ = getDefaultInstance().getUid();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string uid = 3;</code>
+     * @param value The bytes for uid to set.
+     * @return This builder for chaining.
+     */
+    public Builder setUidBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      uid_ = value;
+      onChanged();
+      return this;
+    }
+
+    private int appType_ ;
+    /**
+     * <pre>
+     * default 4
+     * </pre>
+     *
+     * <code>int32 app_type = 4;</code>
+     * @return The appType.
+     */
+    @java.lang.Override
+    public int getAppType() {
+      return appType_;
+    }
+    /**
+     * <pre>
+     * default 4
+     * </pre>
+     *
+     * <code>int32 app_type = 4;</code>
+     * @param value The appType to set.
+     * @return This builder for chaining.
+     */
+    public Builder setAppType(int value) {
+      
+      appType_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <pre>
+     * default 4
+     * </pre>
+     *
+     * <code>int32 app_type = 4;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearAppType() {
+      
+      appType_ = 0;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object unionId_ = "";
+    /**
+     * <code>string union_id = 5;</code>
+     * @return The unionId.
+     */
+    public java.lang.String getUnionId() {
+      java.lang.Object ref = unionId_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        unionId_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string union_id = 5;</code>
+     * @return The bytes for unionId.
+     */
+    public com.google.protobuf.ByteString
+        getUnionIdBytes() {
+      java.lang.Object ref = unionId_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        unionId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string union_id = 5;</code>
+     * @param value The unionId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setUnionId(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      unionId_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string union_id = 5;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearUnionId() {
+      
+      unionId_ = getDefaultInstance().getUnionId();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string union_id = 5;</code>
+     * @param value The bytes for unionId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setUnionIdBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      unionId_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object cityCode_ = "";
+    /**
+     * <code>string city_code = 6;</code>
+     * @return The cityCode.
+     */
+    public java.lang.String getCityCode() {
+      java.lang.Object ref = cityCode_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        cityCode_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string city_code = 6;</code>
+     * @return The bytes for cityCode.
+     */
+    public com.google.protobuf.ByteString
+        getCityCodeBytes() {
+      java.lang.Object ref = cityCode_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        cityCode_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string city_code = 6;</code>
+     * @param value The cityCode to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCityCode(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      cityCode_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string city_code = 6;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearCityCode() {
+      
+      cityCode_ = getDefaultInstance().getCityCode();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string city_code = 6;</code>
+     * @param value The bytes for cityCode to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCityCodeBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      cityCode_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object provinceCode_ = "";
+    /**
+     * <code>string province_code = 7;</code>
+     * @return The provinceCode.
+     */
+    public java.lang.String getProvinceCode() {
+      java.lang.Object ref = provinceCode_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        provinceCode_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string province_code = 7;</code>
+     * @return The bytes for provinceCode.
+     */
+    public com.google.protobuf.ByteString
+        getProvinceCodeBytes() {
+      java.lang.Object ref = provinceCode_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        provinceCode_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string province_code = 7;</code>
+     * @param value The provinceCode to set.
+     * @return This builder for chaining.
+     */
+    public Builder setProvinceCode(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      provinceCode_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string province_code = 7;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearProvinceCode() {
+      
+      provinceCode_ = getDefaultInstance().getProvinceCode();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string province_code = 7;</code>
+     * @param value The bytes for provinceCode to set.
+     * @return This builder for chaining.
+     */
+    public Builder setProvinceCodeBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      provinceCode_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object city_ = "";
+    /**
+     * <code>string city = 8;</code>
+     * @return The city.
+     */
+    public java.lang.String getCity() {
+      java.lang.Object ref = city_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        city_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string city = 8;</code>
+     * @return The bytes for city.
+     */
+    public com.google.protobuf.ByteString
+        getCityBytes() {
+      java.lang.Object ref = city_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        city_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string city = 8;</code>
+     * @param value The city to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCity(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      city_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string city = 8;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearCity() {
+      
+      city_ = getDefaultInstance().getCity();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string city = 8;</code>
+     * @param value The bytes for city to set.
+     * @return This builder for chaining.
+     */
+    public Builder setCityBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      city_ = value;
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object province_ = "";
+    /**
+     * <code>string province = 9;</code>
+     * @return The province.
+     */
+    public java.lang.String getProvince() {
+      java.lang.Object ref = province_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        province_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string province = 9;</code>
+     * @return The bytes for province.
+     */
+    public com.google.protobuf.ByteString
+        getProvinceBytes() {
+      java.lang.Object ref = province_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        province_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string province = 9;</code>
+     * @param value The province to set.
+     * @return This builder for chaining.
+     */
+    public Builder setProvince(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      province_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string province = 9;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearProvince() {
+      
+      province_ = getDefaultInstance().getProvince();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string province = 9;</code>
+     * @param value The bytes for province to set.
+     * @return This builder for chaining.
+     */
+    public Builder setProvinceBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      province_ = value;
+      onChanged();
+      return this;
+    }
+
+    private com.google.protobuf.LazyStringList abExpCode_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+    private void ensureAbExpCodeIsMutable() {
+      if (!((bitField0_ & 0x00000001) != 0)) {
+        abExpCode_ = new com.google.protobuf.LazyStringArrayList(abExpCode_);
+        bitField0_ |= 0x00000001;
+       }
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @return A list containing the abExpCode.
+     */
+    public com.google.protobuf.ProtocolStringList
+        getAbExpCodeList() {
+      return abExpCode_.getUnmodifiableView();
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @return The count of abExpCode.
+     */
+    public int getAbExpCodeCount() {
+      return abExpCode_.size();
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @param index The index of the element to return.
+     * @return The abExpCode at the given index.
+     */
+    public java.lang.String getAbExpCode(int index) {
+      return abExpCode_.get(index);
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @param index The index of the value to return.
+     * @return The bytes of the abExpCode at the given index.
+     */
+    public com.google.protobuf.ByteString
+        getAbExpCodeBytes(int index) {
+      return abExpCode_.getByteString(index);
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @param index The index to set the value at.
+     * @param value The abExpCode to set.
+     * @return This builder for chaining.
+     */
+    public Builder setAbExpCode(
+        int index, java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureAbExpCodeIsMutable();
+      abExpCode_.set(index, value);
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @param value The abExpCode to add.
+     * @return This builder for chaining.
+     */
+    public Builder addAbExpCode(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  ensureAbExpCodeIsMutable();
+      abExpCode_.add(value);
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @param values The abExpCode to add.
+     * @return This builder for chaining.
+     */
+    public Builder addAllAbExpCode(
+        java.lang.Iterable<java.lang.String> values) {
+      ensureAbExpCodeIsMutable();
+      com.google.protobuf.AbstractMessageLite.Builder.addAll(
+          values, abExpCode_);
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearAbExpCode() {
+      abExpCode_ = com.google.protobuf.LazyStringArrayList.EMPTY;
+      bitField0_ = (bitField0_ & ~0x00000001);
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>repeated string ab_exp_code = 10;</code>
+     * @param value The bytes of the abExpCode to add.
+     * @return This builder for chaining.
+     */
+    public Builder addAbExpCodeBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      ensureAbExpCodeIsMutable();
+      abExpCode_.add(value);
+      onChanged();
+      return this;
+    }
+
+    private java.lang.Object rootSessionId_ = "";
+    /**
+     * <code>string root_session_id = 11;</code>
+     * @return The rootSessionId.
+     */
+    public java.lang.String getRootSessionId() {
+      java.lang.Object ref = rootSessionId_;
+      if (!(ref instanceof java.lang.String)) {
+        com.google.protobuf.ByteString bs =
+            (com.google.protobuf.ByteString) ref;
+        java.lang.String s = bs.toStringUtf8();
+        rootSessionId_ = s;
+        return s;
+      } else {
+        return (java.lang.String) ref;
+      }
+    }
+    /**
+     * <code>string root_session_id = 11;</code>
+     * @return The bytes for rootSessionId.
+     */
+    public com.google.protobuf.ByteString
+        getRootSessionIdBytes() {
+      java.lang.Object ref = rootSessionId_;
+      if (ref instanceof String) {
+        com.google.protobuf.ByteString b = 
+            com.google.protobuf.ByteString.copyFromUtf8(
+                (java.lang.String) ref);
+        rootSessionId_ = b;
+        return b;
+      } else {
+        return (com.google.protobuf.ByteString) ref;
+      }
+    }
+    /**
+     * <code>string root_session_id = 11;</code>
+     * @param value The rootSessionId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setRootSessionId(
+        java.lang.String value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  
+      rootSessionId_ = value;
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string root_session_id = 11;</code>
+     * @return This builder for chaining.
+     */
+    public Builder clearRootSessionId() {
+      
+      rootSessionId_ = getDefaultInstance().getRootSessionId();
+      onChanged();
+      return this;
+    }
+    /**
+     * <code>string root_session_id = 11;</code>
+     * @param value The bytes for rootSessionId to set.
+     * @return This builder for chaining.
+     */
+    public Builder setRootSessionIdBytes(
+        com.google.protobuf.ByteString value) {
+      if (value == null) {
+    throw new NullPointerException();
+  }
+  checkByteStringIsUtf8(value);
+      
+      rootSessionId_ = value;
+      onChanged();
+      return this;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:TabRequest)
+  }
+
+  // @@protoc_insertion_point(class_scope:TabRequest)
+  private static final com.tzld.piaoquan.recommend.server.gen.tab.TabRequest DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.server.gen.tab.TabRequest();
+  }
+
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabRequest getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<TabRequest>
+      PARSER = new com.google.protobuf.AbstractParser<TabRequest>() {
+    @java.lang.Override
+    public TabRequest parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new TabRequest(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<TabRequest> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<TabRequest> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.tab.TabRequest getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 152 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabRequestOrBuilder.java

@@ -0,0 +1,152 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/server/tab.proto
+
+package com.tzld.piaoquan.recommend.server.gen.tab;
+
+public interface TabRequestOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:TabRequest)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>string request_id = 1;</code>
+   * @return The requestId.
+   */
+  java.lang.String getRequestId();
+  /**
+   * <code>string request_id = 1;</code>
+   * @return The bytes for requestId.
+   */
+  com.google.protobuf.ByteString
+      getRequestIdBytes();
+
+  /**
+   * <code>string mid = 2;</code>
+   * @return The mid.
+   */
+  java.lang.String getMid();
+  /**
+   * <code>string mid = 2;</code>
+   * @return The bytes for mid.
+   */
+  com.google.protobuf.ByteString
+      getMidBytes();
+
+  /**
+   * <code>string uid = 3;</code>
+   * @return The uid.
+   */
+  java.lang.String getUid();
+  /**
+   * <code>string uid = 3;</code>
+   * @return The bytes for uid.
+   */
+  com.google.protobuf.ByteString
+      getUidBytes();
+
+  /**
+   * <pre>
+   * default 4
+   * </pre>
+   *
+   * <code>int32 app_type = 4;</code>
+   * @return The appType.
+   */
+  int getAppType();
+
+  /**
+   * <code>string union_id = 5;</code>
+   * @return The unionId.
+   */
+  java.lang.String getUnionId();
+  /**
+   * <code>string union_id = 5;</code>
+   * @return The bytes for unionId.
+   */
+  com.google.protobuf.ByteString
+      getUnionIdBytes();
+
+  /**
+   * <code>string city_code = 6;</code>
+   * @return The cityCode.
+   */
+  java.lang.String getCityCode();
+  /**
+   * <code>string city_code = 6;</code>
+   * @return The bytes for cityCode.
+   */
+  com.google.protobuf.ByteString
+      getCityCodeBytes();
+
+  /**
+   * <code>string province_code = 7;</code>
+   * @return The provinceCode.
+   */
+  java.lang.String getProvinceCode();
+  /**
+   * <code>string province_code = 7;</code>
+   * @return The bytes for provinceCode.
+   */
+  com.google.protobuf.ByteString
+      getProvinceCodeBytes();
+
+  /**
+   * <code>string city = 8;</code>
+   * @return The city.
+   */
+  java.lang.String getCity();
+  /**
+   * <code>string city = 8;</code>
+   * @return The bytes for city.
+   */
+  com.google.protobuf.ByteString
+      getCityBytes();
+
+  /**
+   * <code>string province = 9;</code>
+   * @return The province.
+   */
+  java.lang.String getProvince();
+  /**
+   * <code>string province = 9;</code>
+   * @return The bytes for province.
+   */
+  com.google.protobuf.ByteString
+      getProvinceBytes();
+
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @return A list containing the abExpCode.
+   */
+  java.util.List<java.lang.String>
+      getAbExpCodeList();
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @return The count of abExpCode.
+   */
+  int getAbExpCodeCount();
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @param index The index of the element to return.
+   * @return The abExpCode at the given index.
+   */
+  java.lang.String getAbExpCode(int index);
+  /**
+   * <code>repeated string ab_exp_code = 10;</code>
+   * @param index The index of the value to return.
+   * @return The bytes of the abExpCode at the given index.
+   */
+  com.google.protobuf.ByteString
+      getAbExpCodeBytes(int index);
+
+  /**
+   * <code>string root_session_id = 11;</code>
+   * @return The rootSessionId.
+   */
+  java.lang.String getRootSessionId();
+  /**
+   * <code>string root_session_id = 11;</code>
+   * @return The bytes for rootSessionId.
+   */
+  com.google.protobuf.ByteString
+      getRootSessionIdBytes();
+}

+ 958 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabResponse.java

@@ -0,0 +1,958 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/server/tab.proto
+
+package com.tzld.piaoquan.recommend.server.gen.tab;
+
+/**
+ * Protobuf type {@code TabResponse}
+ */
+public final class TabResponse extends
+    com.google.protobuf.GeneratedMessageV3 implements
+    // @@protoc_insertion_point(message_implements:TabResponse)
+    TabResponseOrBuilder {
+private static final long serialVersionUID = 0L;
+  // Use TabResponse.newBuilder() to construct.
+  private TabResponse(com.google.protobuf.GeneratedMessageV3.Builder<?> builder) {
+    super(builder);
+  }
+  private TabResponse() {
+    tab_ = java.util.Collections.emptyList();
+  }
+
+  @java.lang.Override
+  @SuppressWarnings({"unused"})
+  protected java.lang.Object newInstance(
+      UnusedPrivateParameter unused) {
+    return new TabResponse();
+  }
+
+  @java.lang.Override
+  public final com.google.protobuf.UnknownFieldSet
+  getUnknownFields() {
+    return this.unknownFields;
+  }
+  private TabResponse(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    this();
+    if (extensionRegistry == null) {
+      throw new java.lang.NullPointerException();
+    }
+    int mutable_bitField0_ = 0;
+    com.google.protobuf.UnknownFieldSet.Builder unknownFields =
+        com.google.protobuf.UnknownFieldSet.newBuilder();
+    try {
+      boolean done = false;
+      while (!done) {
+        int tag = input.readTag();
+        switch (tag) {
+          case 0:
+            done = true;
+            break;
+          case 10: {
+            com.tzld.piaoquan.recommend.server.gen.common.Result.Builder subBuilder = null;
+            if (result_ != null) {
+              subBuilder = result_.toBuilder();
+            }
+            result_ = input.readMessage(com.tzld.piaoquan.recommend.server.gen.common.Result.parser(), extensionRegistry);
+            if (subBuilder != null) {
+              subBuilder.mergeFrom(result_);
+              result_ = subBuilder.buildPartial();
+            }
+
+            break;
+          }
+          case 18: {
+            if (!((mutable_bitField0_ & 0x00000001) != 0)) {
+              tab_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.server.gen.common.TabProto>();
+              mutable_bitField0_ |= 0x00000001;
+            }
+            tab_.add(
+                input.readMessage(com.tzld.piaoquan.recommend.server.gen.common.TabProto.parser(), extensionRegistry));
+            break;
+          }
+          default: {
+            if (!parseUnknownField(
+                input, unknownFields, extensionRegistry, tag)) {
+              done = true;
+            }
+            break;
+          }
+        }
+      }
+    } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+      throw e.setUnfinishedMessage(this);
+    } catch (java.io.IOException e) {
+      throw new com.google.protobuf.InvalidProtocolBufferException(
+          e).setUnfinishedMessage(this);
+    } finally {
+      if (((mutable_bitField0_ & 0x00000001) != 0)) {
+        tab_ = java.util.Collections.unmodifiableList(tab_);
+      }
+      this.unknownFields = unknownFields.build();
+      makeExtensionsImmutable();
+    }
+  }
+  public static final com.google.protobuf.Descriptors.Descriptor
+      getDescriptor() {
+    return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabResponse_descriptor;
+  }
+
+  @java.lang.Override
+  protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+      internalGetFieldAccessorTable() {
+    return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabResponse_fieldAccessorTable
+        .ensureFieldAccessorsInitialized(
+            com.tzld.piaoquan.recommend.server.gen.tab.TabResponse.class, com.tzld.piaoquan.recommend.server.gen.tab.TabResponse.Builder.class);
+  }
+
+  public static final int RESULT_FIELD_NUMBER = 1;
+  private com.tzld.piaoquan.recommend.server.gen.common.Result result_;
+  /**
+   * <code>.Result result = 1;</code>
+   * @return Whether the result field is set.
+   */
+  @java.lang.Override
+  public boolean hasResult() {
+    return result_ != null;
+  }
+  /**
+   * <code>.Result result = 1;</code>
+   * @return The result.
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.common.Result getResult() {
+    return result_ == null ? com.tzld.piaoquan.recommend.server.gen.common.Result.getDefaultInstance() : result_;
+  }
+  /**
+   * <code>.Result result = 1;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.common.ResultOrBuilder getResultOrBuilder() {
+    return getResult();
+  }
+
+  public static final int TAB_FIELD_NUMBER = 2;
+  private java.util.List<com.tzld.piaoquan.recommend.server.gen.common.TabProto> tab_;
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  @java.lang.Override
+  public java.util.List<com.tzld.piaoquan.recommend.server.gen.common.TabProto> getTabList() {
+    return tab_;
+  }
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  @java.lang.Override
+  public java.util.List<? extends com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder> 
+      getTabOrBuilderList() {
+    return tab_;
+  }
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  @java.lang.Override
+  public int getTabCount() {
+    return tab_.size();
+  }
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.common.TabProto getTab(int index) {
+    return tab_.get(index);
+  }
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder getTabOrBuilder(
+      int index) {
+    return tab_.get(index);
+  }
+
+  private byte memoizedIsInitialized = -1;
+  @java.lang.Override
+  public final boolean isInitialized() {
+    byte isInitialized = memoizedIsInitialized;
+    if (isInitialized == 1) return true;
+    if (isInitialized == 0) return false;
+
+    memoizedIsInitialized = 1;
+    return true;
+  }
+
+  @java.lang.Override
+  public void writeTo(com.google.protobuf.CodedOutputStream output)
+                      throws java.io.IOException {
+    if (result_ != null) {
+      output.writeMessage(1, getResult());
+    }
+    for (int i = 0; i < tab_.size(); i++) {
+      output.writeMessage(2, tab_.get(i));
+    }
+    unknownFields.writeTo(output);
+  }
+
+  @java.lang.Override
+  public int getSerializedSize() {
+    int size = memoizedSize;
+    if (size != -1) return size;
+
+    size = 0;
+    if (result_ != null) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(1, getResult());
+    }
+    for (int i = 0; i < tab_.size(); i++) {
+      size += com.google.protobuf.CodedOutputStream
+        .computeMessageSize(2, tab_.get(i));
+    }
+    size += unknownFields.getSerializedSize();
+    memoizedSize = size;
+    return size;
+  }
+
+  @java.lang.Override
+  public boolean equals(final java.lang.Object obj) {
+    if (obj == this) {
+     return true;
+    }
+    if (!(obj instanceof com.tzld.piaoquan.recommend.server.gen.tab.TabResponse)) {
+      return super.equals(obj);
+    }
+    com.tzld.piaoquan.recommend.server.gen.tab.TabResponse other = (com.tzld.piaoquan.recommend.server.gen.tab.TabResponse) obj;
+
+    if (hasResult() != other.hasResult()) return false;
+    if (hasResult()) {
+      if (!getResult()
+          .equals(other.getResult())) return false;
+    }
+    if (!getTabList()
+        .equals(other.getTabList())) return false;
+    if (!unknownFields.equals(other.unknownFields)) return false;
+    return true;
+  }
+
+  @java.lang.Override
+  public int hashCode() {
+    if (memoizedHashCode != 0) {
+      return memoizedHashCode;
+    }
+    int hash = 41;
+    hash = (19 * hash) + getDescriptor().hashCode();
+    if (hasResult()) {
+      hash = (37 * hash) + RESULT_FIELD_NUMBER;
+      hash = (53 * hash) + getResult().hashCode();
+    }
+    if (getTabCount() > 0) {
+      hash = (37 * hash) + TAB_FIELD_NUMBER;
+      hash = (53 * hash) + getTabList().hashCode();
+    }
+    hash = (29 * hash) + unknownFields.hashCode();
+    memoizedHashCode = hash;
+    return hash;
+  }
+
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      java.nio.ByteBuffer data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      java.nio.ByteBuffer data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      com.google.protobuf.ByteString data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      com.google.protobuf.ByteString data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(byte[] data)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      byte[] data,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws com.google.protobuf.InvalidProtocolBufferException {
+    return PARSER.parseFrom(data, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseDelimitedFrom(java.io.InputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseDelimitedFrom(
+      java.io.InputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseDelimitedWithIOException(PARSER, input, extensionRegistry);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      com.google.protobuf.CodedInputStream input)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input);
+  }
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parseFrom(
+      com.google.protobuf.CodedInputStream input,
+      com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+      throws java.io.IOException {
+    return com.google.protobuf.GeneratedMessageV3
+        .parseWithIOException(PARSER, input, extensionRegistry);
+  }
+
+  @java.lang.Override
+  public Builder newBuilderForType() { return newBuilder(); }
+  public static Builder newBuilder() {
+    return DEFAULT_INSTANCE.toBuilder();
+  }
+  public static Builder newBuilder(com.tzld.piaoquan.recommend.server.gen.tab.TabResponse prototype) {
+    return DEFAULT_INSTANCE.toBuilder().mergeFrom(prototype);
+  }
+  @java.lang.Override
+  public Builder toBuilder() {
+    return this == DEFAULT_INSTANCE
+        ? new Builder() : new Builder().mergeFrom(this);
+  }
+
+  @java.lang.Override
+  protected Builder newBuilderForType(
+      com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+    Builder builder = new Builder(parent);
+    return builder;
+  }
+  /**
+   * Protobuf type {@code TabResponse}
+   */
+  public static final class Builder extends
+      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
+      // @@protoc_insertion_point(builder_implements:TabResponse)
+      com.tzld.piaoquan.recommend.server.gen.tab.TabResponseOrBuilder {
+    public static final com.google.protobuf.Descriptors.Descriptor
+        getDescriptor() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabResponse_descriptor;
+    }
+
+    @java.lang.Override
+    protected com.google.protobuf.GeneratedMessageV3.FieldAccessorTable
+        internalGetFieldAccessorTable() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabResponse_fieldAccessorTable
+          .ensureFieldAccessorsInitialized(
+              com.tzld.piaoquan.recommend.server.gen.tab.TabResponse.class, com.tzld.piaoquan.recommend.server.gen.tab.TabResponse.Builder.class);
+    }
+
+    // Construct using com.tzld.piaoquan.recommend.server.gen.tab.TabResponse.newBuilder()
+    private Builder() {
+      maybeForceBuilderInitialization();
+    }
+
+    private Builder(
+        com.google.protobuf.GeneratedMessageV3.BuilderParent parent) {
+      super(parent);
+      maybeForceBuilderInitialization();
+    }
+    private void maybeForceBuilderInitialization() {
+      if (com.google.protobuf.GeneratedMessageV3
+              .alwaysUseFieldBuilders) {
+        getTabFieldBuilder();
+      }
+    }
+    @java.lang.Override
+    public Builder clear() {
+      super.clear();
+      if (resultBuilder_ == null) {
+        result_ = null;
+      } else {
+        result_ = null;
+        resultBuilder_ = null;
+      }
+      if (tabBuilder_ == null) {
+        tab_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+      } else {
+        tabBuilder_.clear();
+      }
+      return this;
+    }
+
+    @java.lang.Override
+    public com.google.protobuf.Descriptors.Descriptor
+        getDescriptorForType() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.Tab.internal_static_TabResponse_descriptor;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.tab.TabResponse getDefaultInstanceForType() {
+      return com.tzld.piaoquan.recommend.server.gen.tab.TabResponse.getDefaultInstance();
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.tab.TabResponse build() {
+      com.tzld.piaoquan.recommend.server.gen.tab.TabResponse result = buildPartial();
+      if (!result.isInitialized()) {
+        throw newUninitializedMessageException(result);
+      }
+      return result;
+    }
+
+    @java.lang.Override
+    public com.tzld.piaoquan.recommend.server.gen.tab.TabResponse buildPartial() {
+      com.tzld.piaoquan.recommend.server.gen.tab.TabResponse result = new com.tzld.piaoquan.recommend.server.gen.tab.TabResponse(this);
+      int from_bitField0_ = bitField0_;
+      if (resultBuilder_ == null) {
+        result.result_ = result_;
+      } else {
+        result.result_ = resultBuilder_.build();
+      }
+      if (tabBuilder_ == null) {
+        if (((bitField0_ & 0x00000001) != 0)) {
+          tab_ = java.util.Collections.unmodifiableList(tab_);
+          bitField0_ = (bitField0_ & ~0x00000001);
+        }
+        result.tab_ = tab_;
+      } else {
+        result.tab_ = tabBuilder_.build();
+      }
+      onBuilt();
+      return result;
+    }
+
+    @java.lang.Override
+    public Builder clone() {
+      return super.clone();
+    }
+    @java.lang.Override
+    public Builder setField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.setField(field, value);
+    }
+    @java.lang.Override
+    public Builder clearField(
+        com.google.protobuf.Descriptors.FieldDescriptor field) {
+      return super.clearField(field);
+    }
+    @java.lang.Override
+    public Builder clearOneof(
+        com.google.protobuf.Descriptors.OneofDescriptor oneof) {
+      return super.clearOneof(oneof);
+    }
+    @java.lang.Override
+    public Builder setRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        int index, java.lang.Object value) {
+      return super.setRepeatedField(field, index, value);
+    }
+    @java.lang.Override
+    public Builder addRepeatedField(
+        com.google.protobuf.Descriptors.FieldDescriptor field,
+        java.lang.Object value) {
+      return super.addRepeatedField(field, value);
+    }
+    @java.lang.Override
+    public Builder mergeFrom(com.google.protobuf.Message other) {
+      if (other instanceof com.tzld.piaoquan.recommend.server.gen.tab.TabResponse) {
+        return mergeFrom((com.tzld.piaoquan.recommend.server.gen.tab.TabResponse)other);
+      } else {
+        super.mergeFrom(other);
+        return this;
+      }
+    }
+
+    public Builder mergeFrom(com.tzld.piaoquan.recommend.server.gen.tab.TabResponse other) {
+      if (other == com.tzld.piaoquan.recommend.server.gen.tab.TabResponse.getDefaultInstance()) return this;
+      if (other.hasResult()) {
+        mergeResult(other.getResult());
+      }
+      if (tabBuilder_ == null) {
+        if (!other.tab_.isEmpty()) {
+          if (tab_.isEmpty()) {
+            tab_ = other.tab_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+          } else {
+            ensureTabIsMutable();
+            tab_.addAll(other.tab_);
+          }
+          onChanged();
+        }
+      } else {
+        if (!other.tab_.isEmpty()) {
+          if (tabBuilder_.isEmpty()) {
+            tabBuilder_.dispose();
+            tabBuilder_ = null;
+            tab_ = other.tab_;
+            bitField0_ = (bitField0_ & ~0x00000001);
+            tabBuilder_ = 
+              com.google.protobuf.GeneratedMessageV3.alwaysUseFieldBuilders ?
+                 getTabFieldBuilder() : null;
+          } else {
+            tabBuilder_.addAllMessages(other.tab_);
+          }
+        }
+      }
+      this.mergeUnknownFields(other.unknownFields);
+      onChanged();
+      return this;
+    }
+
+    @java.lang.Override
+    public final boolean isInitialized() {
+      return true;
+    }
+
+    @java.lang.Override
+    public Builder mergeFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws java.io.IOException {
+      com.tzld.piaoquan.recommend.server.gen.tab.TabResponse parsedMessage = null;
+      try {
+        parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);
+      } catch (com.google.protobuf.InvalidProtocolBufferException e) {
+        parsedMessage = (com.tzld.piaoquan.recommend.server.gen.tab.TabResponse) e.getUnfinishedMessage();
+        throw e.unwrapIOException();
+      } finally {
+        if (parsedMessage != null) {
+          mergeFrom(parsedMessage);
+        }
+      }
+      return this;
+    }
+    private int bitField0_;
+
+    private com.tzld.piaoquan.recommend.server.gen.common.Result result_;
+    private com.google.protobuf.SingleFieldBuilderV3<
+        com.tzld.piaoquan.recommend.server.gen.common.Result, com.tzld.piaoquan.recommend.server.gen.common.Result.Builder, com.tzld.piaoquan.recommend.server.gen.common.ResultOrBuilder> resultBuilder_;
+    /**
+     * <code>.Result result = 1;</code>
+     * @return Whether the result field is set.
+     */
+    public boolean hasResult() {
+      return resultBuilder_ != null || result_ != null;
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     * @return The result.
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.Result getResult() {
+      if (resultBuilder_ == null) {
+        return result_ == null ? com.tzld.piaoquan.recommend.server.gen.common.Result.getDefaultInstance() : result_;
+      } else {
+        return resultBuilder_.getMessage();
+      }
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     */
+    public Builder setResult(com.tzld.piaoquan.recommend.server.gen.common.Result value) {
+      if (resultBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        result_ = value;
+        onChanged();
+      } else {
+        resultBuilder_.setMessage(value);
+      }
+
+      return this;
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     */
+    public Builder setResult(
+        com.tzld.piaoquan.recommend.server.gen.common.Result.Builder builderForValue) {
+      if (resultBuilder_ == null) {
+        result_ = builderForValue.build();
+        onChanged();
+      } else {
+        resultBuilder_.setMessage(builderForValue.build());
+      }
+
+      return this;
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     */
+    public Builder mergeResult(com.tzld.piaoquan.recommend.server.gen.common.Result value) {
+      if (resultBuilder_ == null) {
+        if (result_ != null) {
+          result_ =
+            com.tzld.piaoquan.recommend.server.gen.common.Result.newBuilder(result_).mergeFrom(value).buildPartial();
+        } else {
+          result_ = value;
+        }
+        onChanged();
+      } else {
+        resultBuilder_.mergeFrom(value);
+      }
+
+      return this;
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     */
+    public Builder clearResult() {
+      if (resultBuilder_ == null) {
+        result_ = null;
+        onChanged();
+      } else {
+        result_ = null;
+        resultBuilder_ = null;
+      }
+
+      return this;
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.Result.Builder getResultBuilder() {
+      
+      onChanged();
+      return getResultFieldBuilder().getBuilder();
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.ResultOrBuilder getResultOrBuilder() {
+      if (resultBuilder_ != null) {
+        return resultBuilder_.getMessageOrBuilder();
+      } else {
+        return result_ == null ?
+            com.tzld.piaoquan.recommend.server.gen.common.Result.getDefaultInstance() : result_;
+      }
+    }
+    /**
+     * <code>.Result result = 1;</code>
+     */
+    private com.google.protobuf.SingleFieldBuilderV3<
+        com.tzld.piaoquan.recommend.server.gen.common.Result, com.tzld.piaoquan.recommend.server.gen.common.Result.Builder, com.tzld.piaoquan.recommend.server.gen.common.ResultOrBuilder> 
+        getResultFieldBuilder() {
+      if (resultBuilder_ == null) {
+        resultBuilder_ = new com.google.protobuf.SingleFieldBuilderV3<
+            com.tzld.piaoquan.recommend.server.gen.common.Result, com.tzld.piaoquan.recommend.server.gen.common.Result.Builder, com.tzld.piaoquan.recommend.server.gen.common.ResultOrBuilder>(
+                getResult(),
+                getParentForChildren(),
+                isClean());
+        result_ = null;
+      }
+      return resultBuilder_;
+    }
+
+    private java.util.List<com.tzld.piaoquan.recommend.server.gen.common.TabProto> tab_ =
+      java.util.Collections.emptyList();
+    private void ensureTabIsMutable() {
+      if (!((bitField0_ & 0x00000001) != 0)) {
+        tab_ = new java.util.ArrayList<com.tzld.piaoquan.recommend.server.gen.common.TabProto>(tab_);
+        bitField0_ |= 0x00000001;
+       }
+    }
+
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.server.gen.common.TabProto, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder, com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder> tabBuilder_;
+
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.server.gen.common.TabProto> getTabList() {
+      if (tabBuilder_ == null) {
+        return java.util.Collections.unmodifiableList(tab_);
+      } else {
+        return tabBuilder_.getMessageList();
+      }
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public int getTabCount() {
+      if (tabBuilder_ == null) {
+        return tab_.size();
+      } else {
+        return tabBuilder_.getCount();
+      }
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto getTab(int index) {
+      if (tabBuilder_ == null) {
+        return tab_.get(index);
+      } else {
+        return tabBuilder_.getMessage(index);
+      }
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder setTab(
+        int index, com.tzld.piaoquan.recommend.server.gen.common.TabProto value) {
+      if (tabBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureTabIsMutable();
+        tab_.set(index, value);
+        onChanged();
+      } else {
+        tabBuilder_.setMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder setTab(
+        int index, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder builderForValue) {
+      if (tabBuilder_ == null) {
+        ensureTabIsMutable();
+        tab_.set(index, builderForValue.build());
+        onChanged();
+      } else {
+        tabBuilder_.setMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder addTab(com.tzld.piaoquan.recommend.server.gen.common.TabProto value) {
+      if (tabBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureTabIsMutable();
+        tab_.add(value);
+        onChanged();
+      } else {
+        tabBuilder_.addMessage(value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder addTab(
+        int index, com.tzld.piaoquan.recommend.server.gen.common.TabProto value) {
+      if (tabBuilder_ == null) {
+        if (value == null) {
+          throw new NullPointerException();
+        }
+        ensureTabIsMutable();
+        tab_.add(index, value);
+        onChanged();
+      } else {
+        tabBuilder_.addMessage(index, value);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder addTab(
+        com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder builderForValue) {
+      if (tabBuilder_ == null) {
+        ensureTabIsMutable();
+        tab_.add(builderForValue.build());
+        onChanged();
+      } else {
+        tabBuilder_.addMessage(builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder addTab(
+        int index, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder builderForValue) {
+      if (tabBuilder_ == null) {
+        ensureTabIsMutable();
+        tab_.add(index, builderForValue.build());
+        onChanged();
+      } else {
+        tabBuilder_.addMessage(index, builderForValue.build());
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder addAllTab(
+        java.lang.Iterable<? extends com.tzld.piaoquan.recommend.server.gen.common.TabProto> values) {
+      if (tabBuilder_ == null) {
+        ensureTabIsMutable();
+        com.google.protobuf.AbstractMessageLite.Builder.addAll(
+            values, tab_);
+        onChanged();
+      } else {
+        tabBuilder_.addAllMessages(values);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder clearTab() {
+      if (tabBuilder_ == null) {
+        tab_ = java.util.Collections.emptyList();
+        bitField0_ = (bitField0_ & ~0x00000001);
+        onChanged();
+      } else {
+        tabBuilder_.clear();
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public Builder removeTab(int index) {
+      if (tabBuilder_ == null) {
+        ensureTabIsMutable();
+        tab_.remove(index);
+        onChanged();
+      } else {
+        tabBuilder_.remove(index);
+      }
+      return this;
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder getTabBuilder(
+        int index) {
+      return getTabFieldBuilder().getBuilder(index);
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder getTabOrBuilder(
+        int index) {
+      if (tabBuilder_ == null) {
+        return tab_.get(index);  } else {
+        return tabBuilder_.getMessageOrBuilder(index);
+      }
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public java.util.List<? extends com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder> 
+         getTabOrBuilderList() {
+      if (tabBuilder_ != null) {
+        return tabBuilder_.getMessageOrBuilderList();
+      } else {
+        return java.util.Collections.unmodifiableList(tab_);
+      }
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder addTabBuilder() {
+      return getTabFieldBuilder().addBuilder(
+          com.tzld.piaoquan.recommend.server.gen.common.TabProto.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder addTabBuilder(
+        int index) {
+      return getTabFieldBuilder().addBuilder(
+          index, com.tzld.piaoquan.recommend.server.gen.common.TabProto.getDefaultInstance());
+    }
+    /**
+     * <code>repeated .TabProto tab = 2;</code>
+     */
+    public java.util.List<com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder> 
+         getTabBuilderList() {
+      return getTabFieldBuilder().getBuilderList();
+    }
+    private com.google.protobuf.RepeatedFieldBuilderV3<
+        com.tzld.piaoquan.recommend.server.gen.common.TabProto, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder, com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder> 
+        getTabFieldBuilder() {
+      if (tabBuilder_ == null) {
+        tabBuilder_ = new com.google.protobuf.RepeatedFieldBuilderV3<
+            com.tzld.piaoquan.recommend.server.gen.common.TabProto, com.tzld.piaoquan.recommend.server.gen.common.TabProto.Builder, com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder>(
+                tab_,
+                ((bitField0_ & 0x00000001) != 0),
+                getParentForChildren(),
+                isClean());
+        tab_ = null;
+      }
+      return tabBuilder_;
+    }
+    @java.lang.Override
+    public final Builder setUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.setUnknownFields(unknownFields);
+    }
+
+    @java.lang.Override
+    public final Builder mergeUnknownFields(
+        final com.google.protobuf.UnknownFieldSet unknownFields) {
+      return super.mergeUnknownFields(unknownFields);
+    }
+
+
+    // @@protoc_insertion_point(builder_scope:TabResponse)
+  }
+
+  // @@protoc_insertion_point(class_scope:TabResponse)
+  private static final com.tzld.piaoquan.recommend.server.gen.tab.TabResponse DEFAULT_INSTANCE;
+  static {
+    DEFAULT_INSTANCE = new com.tzld.piaoquan.recommend.server.gen.tab.TabResponse();
+  }
+
+  public static com.tzld.piaoquan.recommend.server.gen.tab.TabResponse getDefaultInstance() {
+    return DEFAULT_INSTANCE;
+  }
+
+  private static final com.google.protobuf.Parser<TabResponse>
+      PARSER = new com.google.protobuf.AbstractParser<TabResponse>() {
+    @java.lang.Override
+    public TabResponse parsePartialFrom(
+        com.google.protobuf.CodedInputStream input,
+        com.google.protobuf.ExtensionRegistryLite extensionRegistry)
+        throws com.google.protobuf.InvalidProtocolBufferException {
+      return new TabResponse(input, extensionRegistry);
+    }
+  };
+
+  public static com.google.protobuf.Parser<TabResponse> parser() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.google.protobuf.Parser<TabResponse> getParserForType() {
+    return PARSER;
+  }
+
+  @java.lang.Override
+  public com.tzld.piaoquan.recommend.server.gen.tab.TabResponse getDefaultInstanceForType() {
+    return DEFAULT_INSTANCE;
+  }
+
+}
+

+ 48 - 0
recommend-server-client/src/main/java/com/tzld/piaoquan/recommend/server/gen/tab/TabResponseOrBuilder.java

@@ -0,0 +1,48 @@
+// Generated by the protocol buffer compiler.  DO NOT EDIT!
+// source: com/tzld/piaoquan/recommend/server/tab.proto
+
+package com.tzld.piaoquan.recommend.server.gen.tab;
+
+public interface TabResponseOrBuilder extends
+    // @@protoc_insertion_point(interface_extends:TabResponse)
+    com.google.protobuf.MessageOrBuilder {
+
+  /**
+   * <code>.Result result = 1;</code>
+   * @return Whether the result field is set.
+   */
+  boolean hasResult();
+  /**
+   * <code>.Result result = 1;</code>
+   * @return The result.
+   */
+  com.tzld.piaoquan.recommend.server.gen.common.Result getResult();
+  /**
+   * <code>.Result result = 1;</code>
+   */
+  com.tzld.piaoquan.recommend.server.gen.common.ResultOrBuilder getResultOrBuilder();
+
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  java.util.List<com.tzld.piaoquan.recommend.server.gen.common.TabProto> 
+      getTabList();
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  com.tzld.piaoquan.recommend.server.gen.common.TabProto getTab(int index);
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  int getTabCount();
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  java.util.List<? extends com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder> 
+      getTabOrBuilderList();
+  /**
+   * <code>repeated .TabProto tab = 2;</code>
+   */
+  com.tzld.piaoquan.recommend.server.gen.common.TabProtoOrBuilder getTabOrBuilder(
+      int index);
+}

+ 8 - 0
recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/common.proto

@@ -6,4 +6,12 @@ option java_package = "com.tzld.piaoquan.recommend.server.gen.common";
 message Result {
   int32 code = 1; // 1 成功
   string message = 2;
+}
+
+// Tab标签信息
+message TabProto{
+  string key = 1;
+  string title = 2;
+  string type = 3;
+  string source = 4;
 }

+ 1 - 0
recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/recommend.proto

@@ -41,6 +41,7 @@ message RecommendRequest {
   string current_page_source = 30;
   string openGId = 31;
   string union_id = 32;
+  TabProto tab = 33;
 }
 
 message MachineInfoProto {

+ 27 - 0
recommend-server-client/src/main/proto/com/tzld/piaoquan/recommend/server/tab.proto

@@ -0,0 +1,27 @@
+syntax = "proto3";
+
+import "google/protobuf/any.proto";
+import "com/tzld/piaoquan/recommend/server/common.proto";
+
+option java_multiple_files = true;
+option java_package = "com.tzld.piaoquan.recommend.server.gen.tab";
+option java_generic_services = true;
+
+message TabRequest{
+  string request_id = 1;
+  string mid = 2;
+  string uid = 3;
+  int32 app_type = 4; // default 4
+  string union_id = 5;
+  string city_code = 6;
+  string province_code = 7;
+  string city = 8;
+  string province = 9;
+  repeated string ab_exp_code = 10;
+  string root_session_id = 11;
+}
+
+message TabResponse{
+  Result result = 1;
+  repeated TabProto tab = 2;
+}

+ 1 - 1
recommend-server-service/pom.xml

@@ -175,7 +175,7 @@
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>
             <artifactId>recommend-server-client</artifactId>
-            <version>1.1.13</version>
+            <version>1.1.14</version>
         </dependency>
         <dependency>
             <groupId>com.tzld.piaoquan</groupId>

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

@@ -0,0 +1,23 @@
+package com.tzld.piaoquan.recommend.server.common.enums;
+
+import lombok.Getter;
+import lombok.ToString;
+
+@Getter
+@ToString
+public enum TabSource {
+
+    profile("profile", "画像"),
+    share_cate2("share_cate2", "分享二级品类"),
+    return_cate2("return_cate2", "回流二级品类"),
+    default_hot("default_hot", "默认-热度"),
+    other("", "其他");
+
+    private final String source;
+    private final String desc;
+
+    TabSource(String source, String desc) {
+        this.source = source;
+        this.desc = desc;
+    }
+}

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

@@ -0,0 +1,35 @@
+package com.tzld.piaoquan.recommend.server.common.enums;
+
+import lombok.Getter;
+import lombok.ToString;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Getter
+@ToString
+public enum TabType {
+
+    territory("territory", "地域"),
+    personalization("personalization", "个性化"),
+
+    other("other", "其他"),
+
+    ;
+    private final String type;
+    private final String desc;
+
+    private static final Map<String, TabType> typeMap = Arrays.stream(TabType.values())
+            .collect(Collectors.toMap(TabType::getType, Function.identity()));
+
+    TabType(String type, String desc) {
+        this.type = type;
+        this.desc = desc;
+    }
+
+    public static TabType getByType(String type) {
+        return typeMap.getOrDefault(type, other);
+    }
+}

+ 2 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/RecommendParam.java

@@ -69,5 +69,7 @@ public class RecommendParam {
     private String openGId;
 
     private String unionId;
+
+    private Tab tab;
 }
 

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

@@ -0,0 +1,14 @@
+package com.tzld.piaoquan.recommend.server.model;
+
+import lombok.Data;
+
+@Data
+public class Tab {
+
+    private String key;
+
+    private String type;
+
+    private String source;
+
+}

+ 28 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/model/TabParam.java

@@ -0,0 +1,28 @@
+package com.tzld.piaoquan.recommend.server.model;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Set;
+
+@Data
+@NoArgsConstructor
+public class TabParam {
+
+    private String requestId;
+
+    private String mid;
+    private String uid;
+    private String unionId;
+
+    private int appType;
+
+    private String cityCode;
+    private String provinceCode;
+    private String city;
+    private String province;
+
+    private Set<String> abExpCodes;
+
+    private String rootSessionId;
+}

+ 22 - 4
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/RecommendService.java

@@ -14,9 +14,11 @@ import com.tzld.piaoquan.recommend.server.feign.GrowthManagerFeign;
 import com.tzld.piaoquan.recommend.server.feign.model.CommonResponse;
 import com.tzld.piaoquan.recommend.server.feign.model.VideoCharacteristicInfo;
 import com.tzld.piaoquan.recommend.server.gen.common.Result;
+import com.tzld.piaoquan.recommend.server.gen.common.TabProto;
 import com.tzld.piaoquan.recommend.server.gen.recommend.*;
 import com.tzld.piaoquan.recommend.server.model.MachineInfo;
 import com.tzld.piaoquan.recommend.server.model.RecommendParam;
+import com.tzld.piaoquan.recommend.server.model.Tab;
 import com.tzld.piaoquan.recommend.server.model.Video;
 import com.tzld.piaoquan.recommend.server.repository.WxUserInfo;
 import com.tzld.piaoquan.recommend.server.repository.WxUserInfoRepository;
@@ -35,6 +37,7 @@ import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
 import com.tzld.piaoquan.recommend.server.service.recall.RecallResult;
 import com.tzld.piaoquan.recommend.server.service.recall.RecallService;
 import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
+import com.tzld.piaoquan.recommend.server.service.tab.TabService;
 import com.tzld.piaoquan.recommend.server.util.CommonCollectionUtils;
 import com.tzld.piaoquan.recommend.server.util.FeatureUtils;
 import com.tzld.piaoquan.recommend.server.util.JSONUtils;
@@ -91,7 +94,8 @@ public class RecommendService {
     private FunnelLogService funnelLogService;
     @Autowired
     private FeatureService featureService;
-
+    @Autowired
+    private TabService tabService;
     @Autowired
     private GrowthManagerFeign growthManagerFeign;
 
@@ -198,8 +202,7 @@ public class RecommendService {
             RecommendParam param = genRecommendParam(request, recommendType);
             long genRecommendParamTime = stopwatch.stop().elapsed(TimeUnit.MILLISECONDS);
             timerLogMapTL.get().put("genRecommendParamTime", genRecommendParamTime);
-            // log.info("genRecommendParam={},genRecommendParam cost={}", JSONUtils.toJson(param),
-            //         genRecommendParamTime);
+
             List<Video> videos = videoRecommend(param, request);
             stopwatch.reset().start();
             updateCache(request, param, videos);
@@ -315,6 +318,7 @@ public class RecommendService {
                 if (MapUtils.isNotEmpty(logUploadFieldSwitch) && StringUtils.equals("1", logUploadFieldSwitch.get("ext"))) {
                     extJson.put("rankVideoInfoMap", v.getRankVideoInfoMap());
                 }
+                extJson.put("tab", param.getTab());
                 map.put("ext", JSONUtils.toJson(extJson));
 
                 return map;
@@ -470,6 +474,15 @@ public class RecommendService {
             param.setMachineInfo(machineInfo);
         }
 
+        if (request.hasTab()) {
+            TabProto tabProto = request.getTab();
+            Tab tab = new Tab();
+            tab.setKey(tabProto.getKey());
+            tab.setType(tabProto.getType());
+            tab.setSource(tabProto.getSource());
+            param.setTab(tab);
+        }
+
         if (StringUtils.isNotBlank(request.getCategoryId()) && StringUtils.isNumeric(request.getCategoryId())) {
             param.setCategoryId(Integer.parseInt(request.getCategoryId()));
         }
@@ -732,7 +745,7 @@ public class RecommendService {
         recallParam.setCreativeInfoFeature(param.getCreativeInfoFeature());
         recallParam.setOpenGId(param.getOpenGId());
         recallParam.setUnionId(param.getUnionId());
-
+        recallParam.setTab(param.getTab());
         return recallParam;
     }
 
@@ -767,10 +780,14 @@ public class RecommendService {
         rankParam.setCreativeInfoFeature(param.getCreativeInfoFeature());
         rankParam.setOpenGId(param.getOpenGId());
         rankParam.setUnionId(param.getUnionId());
+        rankParam.setTab(param.getTab());
         return rankParam;
     }
 
     public void updateCache(RecommendRequest request, RecommendParam param, List<Video> videos) {
+
+        tabService.updateUserTabCache(param, videos);
+
         if (StringUtils.isBlank(request.getMid())
                 || CollectionUtils.isEmpty(videos)) {
             return;
@@ -788,6 +805,7 @@ public class RecommendService {
         updateFlowPoolCache(request, param, videos);
 
         updateDouHotVideoCache(request, param, videos);
+
     }
 
     private void updateFlowPoolCache(RecommendRequest request, RecommendParam param,

+ 3 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankParam.java

@@ -1,6 +1,7 @@
 package com.tzld.piaoquan.recommend.server.service.rank;
 
 import com.tzld.piaoquan.recommend.server.model.MachineInfo;
+import com.tzld.piaoquan.recommend.server.model.Tab;
 import com.tzld.piaoquan.recommend.server.service.funnel.FunnelContext;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.UserSRBO;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.UserShareReturnProfile;
@@ -54,4 +55,6 @@ public class RankParam {
     private Map<String, Map<String, String>> behaviorVideos;
     private String openGId;
     private String unionId;
+
+    private Tab tab;
 }

+ 15 - 1
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankRouter.java

@@ -1,10 +1,13 @@
 package com.tzld.piaoquan.recommend.server.service.rank;
 
+import com.tzld.piaoquan.recommend.server.common.enums.TabType;
+import com.tzld.piaoquan.recommend.server.model.Tab;
 import com.tzld.piaoquan.recommend.server.service.ExperimentService;
 import com.tzld.piaoquan.recommend.server.service.ServiceBeanFactory;
 import com.tzld.piaoquan.recommend.server.service.rank.strategy.*;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
@@ -26,6 +29,7 @@ public class RankRouter {
     private LinkedHashMap<String, RankService> strategyMap;
 
     private static final String relevantRank = "relevant";
+    private static final String sequenceRank = "sequence";
     private static final Map<String, Class<? extends RankService>> STRATEGY_CLASSES = new HashMap<>();
 
     static {
@@ -39,6 +43,7 @@ public class RankRouter {
         STRATEGY_CLASSES.put("569", RankStrategy4RegionMergeModelV569.class);
         STRATEGY_CLASSES.put("568", RankStrategy4RegionMergeModelV568.class);
         STRATEGY_CLASSES.put("839", RankStrategy4RegionMergeModelV839.class);
+        STRATEGY_CLASSES.put("sequence", RankSequenceStrategy.class);
         STRATEGY_CLASSES.put(relevantRank, RankStrategy4RelevantModelV1.class);
     }
 
@@ -59,11 +64,20 @@ public class RankRouter {
             return strategyMap.get(relevantRank).rank(param);
         }
 
+        Tab tab = param.getTab();
+        if (Objects.nonNull(tab) && StringUtils.isNotBlank(tab.getType())) {
+            TabType type = TabType.getByType(tab.getType());
+            if (Objects.equals(TabType.territory, type)) {
+                return strategyMap.get(sequenceRank).rank(param);
+            }if (Objects.equals(TabType.personalization, type)){
+                return strategyMap.get(sequenceRank).rank(param);
+            }
+        }
+
         // 裂变层实验,使用RootSessionId尾号进行实验
         for (Map.Entry<String, RankService> entry : strategyMap.entrySet()) {
             boolean hitExp = experimentService.judgeHitAlgoExp(param.getAppType(), param.getRootSessionId(), null, entry.getKey());
             if (hitExp) {
-                // log.info("apType: {}, rootSessionId: {} 命中实验: {} strategies: {}", param.getAppType(), param.getRootSessionId(), entry.getKey(), entry.getValue().getClass().getSimpleName());
                 return entry.getValue().rank(param);
             }
         }

+ 10 - 2
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/RankService.java

@@ -112,7 +112,9 @@ public abstract class RankService {
         return result;
     }
 
-    /** 阶段 4 + 阶段 5: 合并 + 排序打分 — rovRecallRank 顺序即合并顺序,Video.sortScore 是 rank 模型最终分 */
+    /**
+     * 阶段 4 + 阶段 5: 合并 + 排序打分 — rovRecallRank 顺序即合并顺序,Video.sortScore 是 rank 模型最终分
+     */
     private static void writeFunnelMergedStage(RankParam param, List<Video> rovRecallRank) {
         if (param == null || param.getFunnelContext() == null || CollectionUtils.isEmpty(rovRecallRank)) return;
         FunnelContext ctx = param.getFunnelContext();
@@ -125,7 +127,9 @@ public abstract class RankService {
         }
     }
 
-    /** 阶段 6: 排序截断 — 纯 rank 排序后的前 size 条(不含冷启,作为冷启替换前的快照) */
+    /**
+     * 阶段 6: 排序截断 — 纯 rank 排序后的前 size 条(不含冷启,作为冷启替换前的快照)
+     */
     private static void writeFunnelRankTruncatedStage(RankParam param, List<Video> rovRecallRank, int size) {
         if (param == null || param.getFunnelContext() == null || CollectionUtils.isEmpty(rovRecallRank)) return;
         FunnelContext ctx = param.getFunnelContext();
@@ -334,4 +338,8 @@ public abstract class RankService {
             log.error("addPushFromVideoRank ", e);
         }
     }
+
+    private void sequenceReturn() {
+
+    }
 }

+ 62 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/rank/strategy/RankSequenceStrategy.java

@@ -0,0 +1,62 @@
+package com.tzld.piaoquan.recommend.server.service.rank.strategy;
+
+import com.google.common.collect.Lists;
+import com.tzld.piaoquan.recommend.server.common.enums.TabType;
+import com.tzld.piaoquan.recommend.server.model.Tab;
+import com.tzld.piaoquan.recommend.server.model.Video;
+import com.tzld.piaoquan.recommend.server.service.rank.RankParam;
+import com.tzld.piaoquan.recommend.server.service.rank.RankResult;
+import com.tzld.piaoquan.recommend.server.service.rank.RankService;
+import com.tzld.piaoquan.recommend.server.service.recall.strategy.*;
+import com.tzld.piaoquan.recommend.server.util.RecallUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+@Slf4j
+@Service
+public class RankSequenceStrategy extends RankService {
+
+    private static final List<String> territoryRecall = Lists.newArrayList(
+            CityRovnAllRovRecallStrategy.PUSH_FROM,
+            CityRovnRecallStrategy.PUSH_FROM,
+            RegionHRecallStrategy.PUSH_FORM,
+            RegionRealtimeRecallStrategyV1.PUSH_FORM
+    );
+    private static final List<String> personalizationRecall = Lists.newArrayList(
+            PersonalizationTabRovnRecallStrategy.PUSH_FROM
+    );
+
+    @Override
+    public List<Video> mergeAndRankRovRecall(RankParam param) {
+        List<Video> rovRecallRank = new ArrayList<>();
+        Tab tab = param.getTab();
+        if (Objects.nonNull(tab) && StringUtils.isNotBlank(tab.getType())) {
+            TabType type = TabType.getByType(tab.getType());
+            if (Objects.equals(TabType.territory, type)) {
+                this.extractRecall(param, territoryRecall, rovRecallRank);
+            } else if (Objects.equals(TabType.personalization, type)) {
+                this.extractRecall(param, personalizationRecall, rovRecallRank);
+            }
+        }
+
+        // 记录召回源中的视频
+        this.rankBeforePostProcessor(rovRecallRank);
+        return rovRecallRank;
+    }
+
+    private void extractRecall(RankParam param, List<String> recalls, List<Video> videos) {
+        Set<Long> setVideo = new HashSet<>();
+        setVideo.add(param.getHeadVid());
+        for (String recall : recalls) {
+            RecallUtils.extractRecall(100, param, recall, setVideo, videos);
+        }
+    }
+
+    @Override
+    public RankResult mergeAndSort(RankParam param, List<Video> rovRecallRank, List<Video> flowPoolRank, List<Video> douHotFlowPoolRank) {
+        return new RankResult(rovRecallRank);
+    }
+}

+ 3 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallParam.java

@@ -1,5 +1,6 @@
 package com.tzld.piaoquan.recommend.server.service.recall;
 
+import com.tzld.piaoquan.recommend.server.model.Tab;
 import com.tzld.piaoquan.recommend.server.service.funnel.FunnelContext;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.UserSRBO;
 import com.tzld.piaoquan.recommend.server.service.rank.bo.UserShareReturnProfile;
@@ -62,4 +63,6 @@ public class RecallParam {
     private Map<String, String> userNetworkSeqFeature;
 
     private Map<Long, Map<String, String>> userNetworkSeqVideoInfoMap;
+
+    private Tab tab;
 }

+ 16 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/RecallService.java

@@ -3,6 +3,7 @@ package com.tzld.piaoquan.recommend.server.service.recall;
 import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
 import com.tzld.piaoquan.recommend.server.common.ThreadPoolFactory;
 import com.tzld.piaoquan.recommend.server.common.enums.AppTypeEnum;
+import com.tzld.piaoquan.recommend.server.common.enums.TabType;
 import com.tzld.piaoquan.recommend.server.model.Video;
 import com.tzld.piaoquan.recommend.server.service.ExperimentService;
 import com.tzld.piaoquan.recommend.server.service.funnel.FunnelContext;
@@ -124,6 +125,21 @@ public class RecallService implements ApplicationContextAware {
             return strategies;
         }
 
+        // 标签页的召回
+        if (Objects.nonNull(param.getTab())) {
+            TabType tabType = TabType.getByType(param.getTab().getType());
+            if (TabType.territory.equals(tabType)) {
+                strategies.add(strategyMap.get(CityRovnAllRovRecallStrategy.class.getSimpleName()));
+                strategies.add(strategyMap.get(CityRovnRecallStrategy.class.getSimpleName()));
+                strategies.add(strategyMap.get(RegionHRecallStrategy.class.getSimpleName()));
+                strategies.add(strategyMap.get(RegionRealtimeRecallStrategyV1.class.getSimpleName()));
+                return strategies;
+            } else if (TabType.personalization.equals(tabType)) {
+                strategies.add(strategyMap.get(PersonalizationTabRovnRecallStrategy.class.getSimpleName()));
+                return strategies;
+            }
+        }
+
         //1:通过“产品”控制“召回子策略”. 票圈美好祝福与内部tab只走祝福召回。APP只走固定列表。特殊配置的app只有固定召回列表。
         if (this.matchSpecialApp(param.getAppType())) {
             strategies.add(strategyMap.get(RegionRealtimeRecallStrategyV5Hand.class.getSimpleName()));

+ 88 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/recall/strategy/PersonalizationTabRovnRecallStrategy.java

@@ -0,0 +1,88 @@
+package com.tzld.piaoquan.recommend.server.service.recall.strategy;
+
+import com.tzld.piaoquan.recommend.server.model.Tab;
+import com.tzld.piaoquan.recommend.server.model.Video;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterParam;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterResult;
+import com.tzld.piaoquan.recommend.server.service.filter.FilterService;
+import com.tzld.piaoquan.recommend.server.service.recall.FilterParamFactory;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallParam;
+import com.tzld.piaoquan.recommend.server.service.recall.RecallStrategy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Component
+public class PersonalizationTabRovnRecallStrategy implements RecallStrategy {
+
+    @Autowired
+    private FilterService filterService;
+    @Autowired
+    @Qualifier("redisTemplate")
+    public RedisTemplate<String, String> redisTemplate;
+
+    public static final String PUSH_FROM = "personalized_tab_rovn_recall";
+
+    private static final String redisKeyFormat = "personalized_tab_rovn_recall:%s";
+
+    @Override
+    public List<Video> recall(RecallParam param) {
+        List<Video> result = new ArrayList<>();
+
+        Tab tab = param.getTab();
+        if (Objects.isNull(tab) || StringUtils.isBlank(tab.getKey())) {
+            return result;
+        }
+
+        String key = String.format(redisKeyFormat, tab.getKey());
+        String value = redisTemplate.opsForValue().get(key);
+        if (StringUtils.isBlank(value)) {
+            return result;
+        }
+        List<String[]> collect = Arrays.stream(value.split("\t"))
+                .map(i -> i.split(","))
+                .collect(Collectors.toList());
+        if (collect.size() != 2) {
+            return result;
+        }
+        String[] vids = collect.get(0);
+        String[] scores = collect.get(1);
+        if (vids.length != scores.length) {
+            return result;
+        }
+
+        Map<Long, Double> vidAndScoreMap = new HashMap<>();
+        for (int i = 0; i < vids.length; i++) {
+            vidAndScoreMap.put(Long.parseLong(vids[i]), Double.parseDouble(scores[i]));
+        }
+
+        FilterParam filterParam = FilterParamFactory.create(param, new ArrayList<>(vidAndScoreMap.keySet()), pushFrom(), vidAndScoreMap);
+        FilterResult filterResult = filterService.filter(filterParam);
+        if (Objects.isNull(filterResult) || CollectionUtils.isEmpty(filterResult.getVideoIds())){
+            return result;
+        }
+        for (Long videoId : filterResult.getVideoIds()) {
+            Video video = new Video();
+            video.setVideoId(videoId);
+            video.setRovScore(vidAndScoreMap.get(videoId));
+            video.setPushFrom(pushFrom());
+
+            result.add(video);
+        }
+
+        return result;
+    }
+
+    @Override
+    public String pushFrom() {
+        return PUSH_FROM;
+    }
+}

+ 228 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/service/tab/TabService.java

@@ -0,0 +1,228 @@
+package com.tzld.piaoquan.recommend.server.service.tab;
+
+import com.alibaba.fastjson.JSON;
+import com.ctrip.framework.apollo.spring.annotation.ApolloJsonValue;
+import com.google.common.collect.Sets;
+import com.tzld.piaoquan.recommend.server.common.enums.TabSource;
+import com.tzld.piaoquan.recommend.server.common.enums.TabType;
+import com.tzld.piaoquan.recommend.server.gen.common.Result;
+import com.tzld.piaoquan.recommend.server.gen.common.TabProto;
+import com.tzld.piaoquan.recommend.server.gen.tab.TabRequest;
+import com.tzld.piaoquan.recommend.server.gen.tab.TabResponse;
+import com.tzld.piaoquan.recommend.server.model.RecommendParam;
+import com.tzld.piaoquan.recommend.server.model.TabParam;
+import com.tzld.piaoquan.recommend.server.model.Video;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class TabService {
+
+
+    @Autowired
+    @Qualifier("redisTemplate")
+    protected RedisTemplate<String, String> redisTemplate;
+
+    @ApolloJsonValue("${homepage.default.tab:[历史名人,知识科普]}")
+    private List<String> homepageDefaultTab;
+
+    @ApolloJsonValue("${personalization.tab.size:2}")
+    private Integer personalizationTabSize;
+
+    /**
+     * 中国行政区划代码(GB/T 2260)省級前缀,前2位。
+     * 11-15 华北, 21-23 东北, 31-37 华东, 41-46 中南, 50-54 西南, 61-65 西北,
+     * 71 台湾, 81-82 香港/澳门
+     */
+    private static final Set<String> CHINA_PROVINCE_CODE_PREFIXES = Sets.newHashSet(
+            "11", "12", "13", "14", "15",
+            "21", "22", "23",
+            "31", "32", "33", "34", "35", "36", "37",
+            "41", "42", "43", "44", "45", "46",
+            "50", "51", "52", "53", "54",
+            "61", "62", "63", "64", "65",
+            "71", "81", "82"
+    );
+
+    private static final String personalizationTabCondidateFormat = "personalized_tab_candidate:%s";
+
+    private static final String userInvalidTabCache = "user:invalid:tab:cache:%s";
+
+    private static final String PERSONALIZATION_TAB_SEPARATOR = "&";
+
+    public TabResponse homepageTab(TabRequest request) {
+        TabParam tabParam = this.requestCoverToParam(request);
+
+        Set<String> tabs = new HashSet<>();
+
+        List<TabProto> tabProtos = new ArrayList<>();
+
+        List<TabProto> territoryTabs = this.territoryTab(tabParam, tabs);
+
+        // 地域Tab
+        if (CollectionUtils.isNotEmpty(territoryTabs)) {
+            tabProtos.addAll(territoryTabs);
+        }
+
+        // 个性化Tab
+        List<TabProto> personalizationTabs = this.personalizationTab(tabParam, tabs);
+        if (CollectionUtils.isNotEmpty(personalizationTabs)) {
+            tabProtos.addAll(personalizationTabs.subList(0, Math.min(personalizationTabs.size(), personalizationTabSize)));
+        }
+
+        return TabResponse.newBuilder()
+                .setResult(Result.newBuilder().setCode(1).setMessage("success"))
+                .addAllTab(tabProtos)
+                .build();
+    }
+
+    private List<TabProto> territoryTab(TabParam tabParam, Set<String> tabs) {
+        List<TabProto> tabProtos = new ArrayList<>();
+        // 非中国地域不返回地域Tab
+        if (isChinaRegion(tabParam.getProvinceCode())) {
+            String province = tabParam.getProvince().replaceAll("省$", "");
+            List<TabProto> provinceTab = this.buildTabProto(Collections.singletonList(province), tabParam.getUnionId(), TabSource.other, TabType.territory, tabs);
+            provinceTab = provinceTab.stream().map(i -> i.toBuilder().setTitle("同城").build()).collect(Collectors.toList());
+            tabProtos.addAll(provinceTab);
+        }
+        return tabProtos;
+    }
+
+    private List<TabProto> personalizationTab(TabParam tabParam, Set<String> tabs) {
+
+        List<TabProto> defaultTab = this.buildTabProto(homepageDefaultTab, tabParam.getUnionId(), TabSource.default_hot, TabType.personalization, tabs);
+        List<TabProto> tabProtos = new ArrayList<>(defaultTab);
+
+        if (StringUtils.isBlank(tabParam.getUnionId())) {
+            log.error("unionId is empty");
+            return tabProtos;
+        }
+
+        String key = String.format(personalizationTabCondidateFormat, tabParam.getUnionId());
+        String value = redisTemplate.opsForValue().get(key);
+        if (StringUtils.isBlank(value)) {
+            log.error("unionId is not exist");
+            return tabProtos;
+        }
+
+        List<List<String>> tabCollect = Arrays.stream(value.split("\t"))
+                .map(i -> Arrays.asList(i.split(PERSONALIZATION_TAB_SEPARATOR)))
+                .collect(Collectors.toList());
+        if (tabCollect.size() != 4) {
+            log.error("redis value size nq 4, {}", value);
+            return tabProtos;
+        }
+
+        log.info("tabCollect: {}", JSON.toJSONString(tabCollect));
+
+        List<TabProto> profileTab = this.buildTabProto(tabCollect.get(0), tabParam.getUnionId(), TabSource.profile, TabType.personalization, tabs);
+        List<TabProto> shareCate2Tab = this.buildTabProto(tabCollect.get(1), tabParam.getUnionId(), TabSource.share_cate2, TabType.personalization, tabs);
+        List<TabProto> returnCate2Tab = this.buildTabProto(tabCollect.get(2), tabParam.getUnionId(), TabSource.return_cate2, TabType.personalization, tabs);
+        List<TabProto> defaultHotTab = this.buildTabProto(tabCollect.get(3), tabParam.getUnionId(), TabSource.default_hot, TabType.personalization, tabs);
+
+        // 默认兜底Tab
+        tabProtos.addAll(0, defaultHotTab);
+        tabProtos.addAll(0, returnCate2Tab);
+        tabProtos.addAll(0, shareCate2Tab);
+        tabProtos.addAll(0, profileTab);
+        return tabProtos;
+    }
+
+    /**
+     * 包含tab去重,tab过滤
+     */
+    private List<TabProto> buildTabProto(List<String> tabNames, String unionId, TabSource source, TabType type, Set<String> tabs) {
+        if (CollectionUtils.isEmpty(tabNames)) {
+            return Collections.emptyList();
+        }
+
+
+        String invalidTabCacheKey = String.format(userInvalidTabCache, unionId);
+        Set<String> invalidTabCache = Optional.ofNullable(redisTemplate.opsForSet().members(invalidTabCacheKey)).orElse(new HashSet<>());
+
+        List<TabProto> tabProtos = new ArrayList<>();
+        for (String tabName : tabNames) {
+            if (StringUtils.isBlank(tabName)
+                    || tabs.contains(tabName)
+                    || invalidTabCache.contains(tabName)) {
+                continue;
+            }
+            tabProtos.add(
+                    TabProto.newBuilder()
+                            .setKey(tabName)
+                            .setTitle(tabName)
+                            .setSource(source.getSource())
+                            .setType(type.getType())
+                            .build()
+            );
+            tabs.add(tabName);
+        }
+        return tabProtos;
+    }
+
+    private TabParam requestCoverToParam(TabRequest request) {
+        TabParam param = new TabParam();
+        param.setRequestId(request.getRequestId());
+
+        param.setMid(request.getMid());
+        param.setUid(request.getUid());
+        param.setUnionId(request.getUnionId());
+
+        param.setAppType(request.getAppType());
+
+        param.setCityCode(request.getCityCode());
+        param.setProvinceCode(request.getProvinceCode());
+        param.setCity(request.getCity());
+        param.setProvince(request.getProvince());
+
+        if (request.getAbExpCodeCount() > 0) {
+            Set<String> abExpCodes = new HashSet<>(request.getAbExpCodeList());
+            param.setAbExpCodes(abExpCodes);
+        }
+        param.setRootSessionId(request.getRootSessionId());
+
+        return param;
+    }
+
+    /**
+     * 判断行政区划代码是否属于中国。
+     * 通过省份代码前2位匹配 GB/T 2260 中的中国省级前缀来校验。
+     *
+     * @param provinceCode 省份代码(2位或6位均可)
+     * @return true 表示是中国地域
+     */
+    private boolean isChinaRegion(String provinceCode) {
+        if (StringUtils.isBlank(provinceCode) || provinceCode.length() < 2) {
+            return false;
+        }
+        return CHINA_PROVINCE_CODE_PREFIXES.contains(provinceCode.substring(0, 2));
+    }
+
+    public void updateUserTabCache(RecommendParam param, List<Video> videos) {
+        try {
+
+            if (Objects.isNull(param.getTab()) || StringUtils.isBlank(param.getTab().getKey())) {
+                return;
+            }
+            int size = param.getSize();
+            if (CollectionUtils.isEmpty(videos) || videos.size() < size) {
+                String key = String.format(userInvalidTabCache, param.getUnionId());
+                redisTemplate.opsForSet().add(key, param.getTab().getKey());
+                redisTemplate.expire(key, 360 * 3600, TimeUnit.SECONDS);
+            }
+        } catch (Exception e) {
+            log.error("updateUserTabCache error", e);
+        }
+    }
+
+}

+ 34 - 0
recommend-server-service/src/main/java/com/tzld/piaoquan/recommend/server/web/TabController.java

@@ -0,0 +1,34 @@
+package com.tzld.piaoquan.recommend.server.web;
+
+import com.tzld.piaoquan.recommend.server.client.ProtobufUtils;
+import com.tzld.piaoquan.recommend.server.gen.tab.TabRequest;
+import com.tzld.piaoquan.recommend.server.gen.tab.TabResponse;
+import com.tzld.piaoquan.recommend.server.service.tab.TabService;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+@Slf4j
+@RestController
+public class TabController {
+
+    @Autowired
+    private TabService tabService;
+
+    @PostMapping("/homepage/tab")
+    public String homepageTab(@RequestBody TabRequest request) {
+        MDC.put("appType", String.valueOf(request.getAppType()));
+        TabResponse tabResponse = tabService.homepageTab(request);
+        String result = "";
+        try {
+            result = ProtobufUtils.toJson(tabResponse);
+        } catch (Exception e) {
+            log.error("homepageTab ProtobufUtils.toJson", e);
+        }
+        return result;
+    }
+
+}