新建订阅

This commit is contained in:
许晓东
2021-10-21 17:00:47 +08:00
parent 06351558b5
commit 00eb51eb2e
12 changed files with 212 additions and 12 deletions

View File

@@ -0,0 +1,17 @@
package com.xuxd.kafka.console.beans.dto;
import lombok.Data;
/**
* kafka-console-ui.
*
* @author xuxd
* @date 2021-10-21 15:43:56
**/
@Data
public class AddSubscriptionDTO {
private String groupId;
private String topic;
}

View File

@@ -1,5 +1,6 @@
package com.xuxd.kafka.console.controller;
import com.xuxd.kafka.console.beans.dto.AddSubscriptionDTO;
import com.xuxd.kafka.console.beans.dto.QueryConsumerGroupDTO;
import com.xuxd.kafka.console.service.ConsumerService;
import java.util.Collections;
@@ -60,4 +61,9 @@ public class ConsumerController {
public Object getConsumerDetail(@RequestParam String groupId) {
return consumerService.getConsumerDetail(groupId);
}
@PostMapping("/subscription")
public Object addSubscription(@RequestBody AddSubscriptionDTO subscriptionDTO) {
return consumerService.addSubscription(subscriptionDTO.getGroupId(), subscriptionDTO.getTopic());
}
}

View File

@@ -30,6 +30,11 @@ public class TopicController {
@Autowired
private TopicService topicService;
@GetMapping
public Object getTopicNameList() {
return topicService.getTopicNameList(false);
}
@GetMapping("/list")
public Object getTopicList(@RequestParam(required = false) String topic, @RequestParam String type) {
return topicService.getTopicList(topic, TopicType.valueOf(type.toUpperCase()));

View File

@@ -20,4 +20,6 @@ public interface ConsumerService {
ResponseData getConsumerMembers(String groupId);
ResponseData getConsumerDetail(String groupId);
ResponseData addSubscription(String groupId, String topic);
}

View File

@@ -15,7 +15,7 @@ import org.apache.kafka.clients.admin.NewTopic;
**/
public interface TopicService {
ResponseData getTopicNameList();
ResponseData getTopicNameList(boolean internal);
ResponseData getTopicList(String topic, TopicType type);

View File

@@ -98,4 +98,22 @@ public class ConsumerServiceImpl implements ConsumerService {
});
return ResponseData.create().data(res).success();
}
@Override public ResponseData addSubscription(String groupId, String topic) {
// check whether exist subscription relationship.
Collection<ConsumerConsole.TopicPartitionConsumeInfo> consumerDetail = consumerConsole.getConsumerDetail(Collections.singleton(groupId));
if (CollectionUtils.isNotEmpty(consumerDetail)) {
List<ConsumerConsole.TopicPartitionConsumeInfo> collect = consumerDetail.stream()
.filter(t -> t.getTopicPartition().topic().equals(topic)).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(collect)) {
return ResponseData.create().failed("The subscription exist.");
}
}
// consumer message and commit offset.
// reset consume offset to 0.
return ResponseData.create().success();
}
}

View File

@@ -38,8 +38,8 @@ public class TopicServiceImpl implements TopicService {
@Autowired
private TopicConsole topicConsole;
@Override public ResponseData getTopicNameList() {
return ResponseData.create().data(topicConsole.getTopicNameList(true)).success();
@Override public ResponseData getTopicNameList(boolean internal) {
return ResponseData.create().data(topicConsole.getTopicNameList(internal)).success();
}
@Override public ResponseData getTopicList(String topic, TopicType type) {

View File

@@ -22,7 +22,7 @@ public class TopicServiceImplTest {
@Test
public void getTopicNameList() {
log.info(topicService.getTopicNameList().getData().toString());
log.info(topicService.getTopicNameList(true).getData().toString());
}
@Test

View File

@@ -57,6 +57,10 @@ export const KafkaConfigApi = {
};
export const KafkaTopicApi = {
getTopicNameList: {
url: "/topic",
method: "get",
},
getTopicList: {
url: "/topic/list",
method: "get",
@@ -96,6 +100,10 @@ export const KafkaConsumerApi = {
url: "/consumer/detail",
method: "get",
},
addSubscription: {
url: "/consumer/subscription",
method: "post",
},
};
export const KafkaClusterApi = {

View File

@@ -0,0 +1,135 @@
<template>
<a-modal
title="新增订阅关系"
:visible="show"
:width="800"
:mask="false"
:destroyOnClose="true"
:footer="null"
:maskClosable="false"
@cancel="handleCancel"
>
<div>
<a-spin :spinning="loading">
<a-form
:form="form"
:label-col="{ span: 5 }"
:wrapper-col="{ span: 12 }"
@submit="handleSubmit"
>
<a-form-item label="消费组">
<a-input
v-decorator="[
'groupId',
{ rules: [{ required: true, message: '输入消费组名称!' }] },
]"
placeholder="groupId"
/>
</a-form-item>
<a-form-item label="topic">
<a-select
show-search
option-filter-prop="children"
v-decorator="[
'topic',
{ rules: [{ required: true, message: '请选择一个topic!' }] },
]"
placeholder="请选择一个topic"
>
<a-select-option v-for="v in topicList" :key="v" :value="v">
{{ v }}
</a-select-option>
</a-select>
</a-form-item>
<a-form-item :wrapper-col="{ span: 12, offset: 5 }">
<a-button type="primary" html-type="submit"> 提交 </a-button>
</a-form-item>
</a-form>
</a-spin>
</div>
</a-modal>
</template>
<script>
import request from "@/utils/request";
import { KafkaTopicApi, KafkaConsumerApi } from "@/utils/api";
import notification from "ant-design-vue/es/notification";
export default {
name: "AddSubscription",
props: {
topic: {
type: String,
default: "",
},
visible: {
type: Boolean,
default: false,
},
},
data() {
return {
show: this.visible,
data: [],
loading: false,
form: this.$form.createForm(this, { name: "coordinated" }),
topicList: [],
};
},
watch: {
visible(v) {
this.show = v;
if (this.show) {
this.getTopicNameList();
}
},
},
methods: {
getTopicNameList() {
request({
url: KafkaTopicApi.getTopicNameList.url,
method: KafkaTopicApi.getTopicNameList.method,
}).then((res) => {
if (res.code == 0) {
this.topicList = res.data;
} else {
notification.error({
message: "error",
description: res.msg,
});
}
});
},
handleSubmit(e) {
e.preventDefault();
this.form.validateFields((err, values) => {
if (!err) {
this.loading = true;
request({
url: KafkaConsumerApi.addSubscription.url,
method: KafkaConsumerApi.addSubscription.method,
data: values,
}).then((res) => {
this.loading = false;
if (res.code == 0) {
this.$message.success(res.msg);
this.$emit("closeAddSubscriptionDialog", { refresh: true });
} else {
notification.error({
message: "error",
description: res.msg,
});
}
});
}
});
},
handleCancel() {
this.data = [];
this.$emit("closeAddSubscriptionDialog", { refresh: false });
},
},
};
</script>
<style scoped></style>

View File

@@ -61,7 +61,9 @@
</a-form>
</div>
<div class="operation-row-button">
<!-- <a-button type="primary" @click="handleReset">新增/更新</a-button>-->
<a-button type="primary" @click="openAddSubscriptionDialog"
>新增订阅</a-button
>
</div>
<a-table
:columns="columns"
@@ -111,6 +113,11 @@
@closeConsumerDetailDialog="closeConsumerDetailDialog"
>
</ConsumerDetail>
<AddSupscription
:visible="showAddSubscriptionDialog"
@closeAddSubscriptionDialog="closeAddSubscriptionDialog"
>
</AddSupscription>
</div>
</a-spin>
</div>
@@ -122,10 +129,11 @@ import { KafkaConsumerApi } from "@/utils/api";
import notification from "ant-design-vue/es/notification";
import Member from "@/views/group/Member";
import ConsumerDetail from "@/views/group/ConsumerDetail";
import AddSupscription from "@/views/group/AddSupscription";
export default {
name: "ConsumerGroup",
components: { Member, ConsumerDetail },
components: { Member, ConsumerDetail, AddSupscription },
data() {
return {
queryParam: {},
@@ -145,6 +153,7 @@ export default {
loading: false,
showConsumerGroupDialog: false,
showConsumerDetailDialog: false,
showAddSubscriptionDialog: false,
};
},
methods: {
@@ -201,6 +210,12 @@ export default {
closeConsumerDetailDialog() {
this.showConsumerDetailDialog = false;
},
openAddSubscriptionDialog() {
this.showAddSubscriptionDialog = true;
},
closeAddSubscriptionDialog() {
this.showAddSubscriptionDialog = false;
},
},
created() {
this.getConsumerGroupList();

View File

@@ -100,15 +100,9 @@ export default {
watch: {
visible(v) {
this.show = v;
if (this.show) {
this.getPartitionInfo();
}
},
},
methods: {
getPartitionInfo() {
this.loading = false;
},
handleSubmit(e) {
e.preventDefault();
this.form.validateFields((err, values) => {