Repository: didi/KnowStreaming (language: java)

Issue:
[Feature] Message->Consume just filter key or value, not both. 消费消息支持单独过滤key或者value
- [x] 我在 [issues](https://github.com/didi/KnowStreaming/issues) 中并未搜索到与此相关的功能需求。
- [x] 我在 [release note](https://github.com/didi/KnowStreaming/releases) 已经发布的版本中并没有搜到相关功能.

你是否希望来认领这个Feature。

「   Y  」

## 这里描述需求
When using Message->Consume and config filter as conatins, the key and value are both required.
I need to just filter key or value, **not both**.

![image](https://github.com/didi/KnowStreaming/assets/51365967/a4da46d4-5f91-4d12-8497-8ad882d87c36)![image](https://github.com/didi/KnowStreaming/assets/51365967/51ef9643-e9e7-4672-b4eb-fbfd9ebbebbe)





Discussion / hints:

Fix patch:
diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx
index 90625de80..79246b03c 100644
--- a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx
+++ b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/Consume.tsx
@@ -144,6 +144,8 @@ const ConsumeClientTest = () => {
             ...configInfo,
             needFilterKeyValue: changeValue === 1 || changeValue === 2,
             needFilterSize: changeValue === 3 || changeValue === 4 || changeValue === 5,
+            needFilterKey: changeValue === 6,
+            needFilterValue: changeValue === 7,
           });
           break;
       }
diff --git a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx
index fc529e9d8..022360889 100644
--- a/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx
+++ b/km-console/packages/layout-clusters-fe/src/pages/TestingConsumer/config.tsx
@@ -16,19 +16,19 @@ export const cardList = [
 
 export const filterList = [
   {
-    label: 'none',
+    label: 'None',
     value: 0,
   },
   {
-    label: 'contains',
+    label: 'Contains',
     value: 1,
   },
   {
-    label: 'does not contains',
+    label: 'Does Not Contains',
     value: 2,
   },
   {
-    label: 'equals',
+    label: 'Equals',
     value: 3,
   },
   {
@@ -39,6 +39,14 @@ export const filterList = [
     label: 'Under Size',
     value: 5,
   },
+  {
+      label: 'Key Contains',
+      value: 6,
+  },
+  {
+      label: 'Value Contains',
+      value: 7,
+  }
 ];
 
 export const untilList = [
@@ -324,10 +332,10 @@ export const getFormConfig = (topicMetaData: any, info = {} as any, partitionLis
       key: 'filterKey',
       label: 'Key',
       type: FormItemType.input,
-      invisible: !info?.needFilterKeyValue,
+      invisible: !info?.needFilterKeyValue && !info?.needFilterKey,
       rules: [
         {
-          required: info?.needFilterKeyValue,
+          required: info?.needFilterKeyValue || info?.needFilterKey,
           message: '请输入Key',
         },
       ],
@@ -336,10 +344,10 @@ export const getFormConfig = (topicMetaData: any, info = {} as any, partitionLis
       key: 'filterValue',
       label: 'Value',
       type: FormItemType.input,
-      invisible: !info?.needFilterKeyValue,
+      invisible: !info?.needFilterKeyValue && !info?.needFilterValue,
       rules: [
         {
-          required: info?.needFilterKeyValue,
+          required: info?.needFilterKeyValue || info?.needFilterValue,
           message: '请输入Value',
         },
       ],


Test patch:
diff --git a/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/biz/impl/KafkaClientTestManagerImpl.java b/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/biz/impl/KafkaClientTestManagerImpl.java
index f057ee182..3808b160e 100644
--- a/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/biz/impl/KafkaClientTestManagerImpl.java
+++ b/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/biz/impl/KafkaClientTestManagerImpl.java
@@ -451,6 +451,18 @@ private Result<Void> checkStartFromAndFilterLegal(KafkaConsumerStartFromDTO star
             return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "包含的方式过滤，必须有过滤的key或value");
         }
 
+        // key包含过滤
+        if (KafkaConsumerFilterEnum.KEY_CONTAINS.getCode().equals(filter.getFilterType())
+            && ValidateUtils.isBlank(filter.getFilterCompareKey())) {
+            return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "key包含的方式过滤，必须有过滤的key");
+        }
+
+        // value包含过滤
+        if (KafkaConsumerFilterEnum.VALUE_CONTAINS.getCode().equals(filter.getFilterType())
+            && ValidateUtils.isBlank(filter.getFilterCompareValue())) {
+            return Result.buildFromRSAndMsg(ResultStatus.PARAM_ILLEGAL, "value包含的方式过滤，必须有过滤的value");
+        }
+
         // 不包含过滤
         if (KafkaConsumerFilterEnum.NOT_CONTAINS.getCode().equals(filter.getFilterType())
                 && ValidateUtils.isBlank(filter.getFilterCompareKey()) && ValidateUtils.isBlank(filter.getFilterCompareValue())) {
@@ -550,6 +562,18 @@ private boolean checkMatchFilter(ConsumerRecord consumerRecord, KafkaConsumerFil
             return true;
         }
 
+        // key包含过滤
+        if (KafkaConsumerFilterEnum.KEY_CONTAINS.getCode().equals(filter.getFilterType())
+            && (!ValidateUtils.isBlank(filter.getFilterCompareKey()) && consumerRecord.key() != null && consumerRecord.key().toString().contains(filter.getFilterCompareKey()))) {
+            return true;
+        }
+
+        // value包含过滤
+        if (KafkaConsumerFilterEnum.VALUE_CONTAINS.getCode().equals(filter.getFilterType())
+            && (!ValidateUtils.isBlank(filter.getFilterCompareValue()) && consumerRecord.value() != null && consumerRecord.value().toString().contains(filter.getFilterCompareValue()))) {
+            return true;
+        }
+
         // 不包含过滤
         if (KafkaConsumerFilterEnum.NOT_CONTAINS.getCode().equals(filter.getFilterType())
                 && (!ValidateUtils.isBlank(filter.getFilterCompareKey()) && (consumerRecord.key() == null || !consumerRecord.key().toString().contains(filter.getFilterCompareKey())))
diff --git a/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/bean/dto/KafkaConsumerFilterDTO.java b/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/bean/dto/KafkaConsumerFilterDTO.java
index e184709b3..8d0b81a3a 100644
--- a/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/bean/dto/KafkaConsumerFilterDTO.java
+++ b/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/bean/dto/KafkaConsumerFilterDTO.java
@@ -19,7 +19,7 @@ public class KafkaConsumerFilterDTO extends BaseDTO {
     /**
      * @see KafkaConsumerFilterEnum
      */
-    @Range(min = 0, max = 5, message = "filterType最大和最小值必须在[0, 5]之间")
+    @Range(min = 0, max = 7, message = "filterType最大和最小值必须在[0, 7]之间")
     @ApiModelProperty(value = "开始消费位置的类型", example = "2")
     private Integer filterType;
 
diff --git a/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/enums/KafkaConsumerFilterEnum.java b/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/enums/KafkaConsumerFilterEnum.java
index f7f94d191..59ba003e5 100644
--- a/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/enums/KafkaConsumerFilterEnum.java
+++ b/km-enterprise/km-testing/src/main/java/com/xiaojukeji/know/streaming/km/testing/common/enums/KafkaConsumerFilterEnum.java
@@ -22,6 +22,10 @@ public enum KafkaConsumerFilterEnum {
 
     UNDER_SIZE(5, "size小于"),
 
+    KEY_CONTAINS(6, "key包含"),
+
+    VALUE_CONTAINS(7, "value包含"),
+
     ;
 
     private final Integer code;