增加分区

This commit is contained in:
许晓东
2021-10-18 20:53:25 +08:00
parent f18e857d3c
commit 0f4663d58f
8 changed files with 234 additions and 4 deletions

View File

@@ -0,0 +1,21 @@
package com.xuxd.kafka.console.beans.dto;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
/**
* kafka-console-ui.
*
* @author xuxd
* @date 2021-10-18 19:55:40
**/
@Data
public class AddPartitionDTO {
private String topic;
private int addNum;
private List<List<Integer>> assignment = new ArrayList<>();
}

View File

@@ -21,7 +21,7 @@ public class NewTopicDTO {
private Map<String, String> configs = new HashMap<>();
public NewTopic toNewTopic() {
NewTopic topic = new NewTopic(name, numPartitions, replicationFactor);
NewTopic topic = new NewTopic(name.trim(), numPartitions, replicationFactor);
if (MapUtils.isNotEmpty(configs)) {
topic.configs(configs);
}

View File

@@ -1,5 +1,6 @@
package com.xuxd.kafka.console.controller;
import com.xuxd.kafka.console.beans.dto.AddPartitionDTO;
import com.xuxd.kafka.console.beans.dto.NewTopicDTO;
import com.xuxd.kafka.console.beans.enums.TopicType;
import com.xuxd.kafka.console.service.TopicService;
@@ -37,11 +38,16 @@ public class TopicController {
@GetMapping("/partition")
public Object getTopicPartitionInfo(@RequestParam String topic) {
return topicService.getTopicPartitionInfo(topic);
return topicService.getTopicPartitionInfo(topic.trim());
}
@PostMapping("/new")
public Object createNewTopic(@RequestBody NewTopicDTO topicDTO) {
return topicService.createTopic(topicDTO.toNewTopic());
}
@PostMapping("/partition/new")
public Object addPartition(@RequestBody AddPartitionDTO partitionDTO) {
return topicService.addPartitions(partitionDTO.getTopic().trim(), partitionDTO.getAddNum(), partitionDTO.getAssignment());
}
}

View File

@@ -2,6 +2,9 @@ package com.xuxd.kafka.console.service;
import com.xuxd.kafka.console.beans.ResponseData;
import com.xuxd.kafka.console.beans.enums.TopicType;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.kafka.clients.admin.NewTopic;
/**
@@ -21,4 +24,6 @@ public interface TopicService {
ResponseData getTopicPartitionInfo(String topic);
ResponseData createTopic(NewTopic topic);
ResponseData addPartitions(String topic, int addNum, List<List<Integer>> newAssignmentst);
}

View File

@@ -16,6 +16,7 @@ import java.util.stream.Collectors;
import kafka.console.TopicConsole;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.kafka.clients.admin.NewPartitions;
import org.apache.kafka.clients.admin.NewTopic;
import org.apache.kafka.clients.admin.TopicDescription;
import org.apache.kafka.common.TopicPartition;
@@ -112,4 +113,21 @@ public class TopicServiceImpl implements TopicService {
Tuple2<Object, String> createResult = topicConsole.createTopic(topic);
return (boolean) createResult._1 ? ResponseData.create().success() : ResponseData.create().failed(String.valueOf(createResult._2));
}
@Override public ResponseData addPartitions(String topic, int addNum, List<List<Integer>> newAssignments) {
List<TopicDescription> list = topicConsole.getTopicList(Collections.singleton(topic));
if (list.isEmpty()) {
return ResponseData.create().failed("topic not exist.");
}
TopicDescription topicDescription = list.get(0);
Map<String, NewPartitions> param = new HashMap<>();
param.put(topic, (newAssignments.size() > 0 ? NewPartitions.increaseTo(topicDescription.partitions().size() + addNum, newAssignments) :
NewPartitions.increaseTo(topicDescription.partitions().size() + addNum)));
Tuple2<Object, String> tuple2 = topicConsole.createPartitions(param);
boolean success = (boolean) tuple2._1();
return success ? ResponseData.create().success() : ResponseData.create().failed(tuple2._2());
}
}

View File

@@ -5,7 +5,7 @@ import java.util.concurrent.TimeUnit
import java.util.{Collections, List, Set}
import com.xuxd.kafka.console.config.KafkaConfig
import org.apache.kafka.clients.admin.{CreateTopicsOptions, DeleteTopicsOptions, ListTopicsOptions, NewTopic, TopicDescription}
import org.apache.kafka.clients.admin._
import org.apache.kafka.common.TopicPartition
import scala.jdk.CollectionConverters.{CollectionHasAsScala, SetHasAsJava}
@@ -107,4 +107,18 @@ class TopicConsole(config: KafkaConfig) extends KafkaConsole(config: KafkaConfig
(false, e.getMessage)
}).asInstanceOf[(Boolean, String)]
}
/**
* create new partition.
*/
def createPartitions(newPartitions: util.Map[String, NewPartitions]): (Boolean, String) = {
withAdminClientAndCatchError(admin => {
admin.createPartitions(newPartitions,
new CreatePartitionsOptions().retryOnQuotaViolation(false)).all().get(timeoutMs, TimeUnit.MILLISECONDS)
(true, "")
}, e => {
log.error("create partition error, ", e)
(false, e.getMessage)
}).asInstanceOf[(Boolean, String)]
}
}

View File

@@ -0,0 +1,144 @@
<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="Topic名称">
<a-input disabled="true"
v-decorator="[
'name',
{ rules: [{ required: true, message: '输入topic名称!' }] },
]"
placeholder="topic"
/>
</a-form-item>
<a-form-item label="分区">
<a-input-number
:min="1"
:max="128"
v-decorator="[
'numPartitions',
{
initialValue: 1,
rules: [{ required: true, message: '输入分区数!' }],
},
]"
/>
<span class="ant-form-text"> 个分区 </span>
</a-form-item>
<a-form-item label="属性">
<a-textarea
rows="5"
placeholder="格式示例如下:
max.message.bytes=1024
retention.bytes=1024
retention.ms=3600000"
v-decorator="['configs']"
/>
</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 } from "@/utils/api";
import notification from "ant-design-vue/es/notification";
export default {
name: "AddPartition",
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" }),
};
},
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) => {
if (!err) {
if (values.configs) {
const config = {};
values.configs.split("\n").forEach((e) => {
const c = e.split("=");
if (c.length > 1) {
let k = c[0].trim(),
v = c[1].trim();
if (k && v) {
config[k] = v;
}
}
});
values.configs = config;
}
this.loading = true;
request({
url: KafkaTopicApi.creatTopic.url,
method: KafkaTopicApi.creatTopic.method,
data: values,
}).then((res) => {
this.loading = false;
if (res.code == 0) {
this.$message.success(res.msg);
this.$emit("closeAddPartitionDialog", { refresh: true });
} else {
notification.error({
message: "error",
description: res.msg,
});
}
});
}
});
},
handleCancel() {
this.data = [];
this.$emit("closeAddPartitionDialog", { refresh: false });
},
},
};
</script>
<style scoped></style>

View File

@@ -70,6 +70,13 @@
>删除
</a-button>
</a-popconfirm>
<a-button
size="small"
href="javascript:;"
class="operation-btn"
@click="openAddPartitionDialog"
>增加分区
</a-button>
</div>
</a-table>
<PartitionInfo
@@ -82,6 +89,10 @@
@closeCreateTopicDialog="closeCreateTopicDialog"
>
</CreateTopic>
<AddPartition
:visible="showAddPartition"
@closeAddPartitionDialog="closeAddPartitionDialog"
></AddPartition>
</div>
</a-spin>
</div>
@@ -93,10 +104,11 @@ import { KafkaTopicApi } from "@/utils/api";
import notification from "ant-design-vue/es/notification";
import PartitionInfo from "@/views/topic/PartitionInfo";
import CreateTopic from "@/views/topic/CreateTopic";
import AddPartition from "@/views/topic/AddPartition";
export default {
name: "Topic",
components: { PartitionInfo, CreateTopic },
components: { PartitionInfo, CreateTopic, AddPartition },
data() {
return {
queryParam: { type: "normal" },
@@ -114,6 +126,7 @@ export default {
showPartitionInfo: false,
loading: false,
showCreateTopic: false,
showAddPartition: false,
};
},
methods: {
@@ -170,6 +183,15 @@ export default {
this.getTopicList();
}
},
openAddPartitionDialog() {
this.showAddPartition = true;
},
closeAddPartitionDialog(res) {
this.showAddPartition = false;
if (res.refresh) {
this.getTopicList();
}
},
},
created() {
this.getTopicList();