Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ecbd9dda6a | ||
|
|
30707e84a7 | ||
|
|
f98cca8727 | ||
|
|
ea95697e88 | ||
|
|
e90268a56e | ||
|
|
fcc315782c | ||
|
|
b79529f607 | ||
|
|
f49e2f7d0c | ||
|
|
4929953acd | ||
|
|
8c946a96ba |
@@ -25,11 +25,11 @@ v1.0.6版本之前,如果kafka集群启用了ACL,但是控制台没看到Acl
|
||||

|
||||
|
||||
## 安装包下载
|
||||
点击下载(v1.0.8版本):[kafka-console-ui.zip](https://github.com/xxd763795151/kafka-console-ui/releases/download/v1.0.8/kafka-console-ui.zip)
|
||||
点击下载(v1.0.9版本):[kafka-console-ui.zip](https://github.com/xxd763795151/kafka-console-ui/releases/download/v1.0.9/kafka-console-ui-1.0.9.zip)
|
||||
|
||||
如果安装包下载的比较慢,可以查看下面的源码打包说明,把代码下载下来,本地快速打包.
|
||||
|
||||
github下载慢也可以试试从gitee下载,点击下载[gitee来源kafka-console-ui.zip](https://gitee.com/xiaodong_xu/kafka-console-ui/releases/download/v1.0.8/kafka-console-ui.zip)
|
||||
github下载慢也可以试试从gitee下载,点击下载[gitee来源kafka-console-ui.zip](https://gitee.com/xiaodong_xu/kafka-console-ui/releases/download/v1.0.9/kafka-console-ui-1.0.9.zip)
|
||||
|
||||
## 快速使用
|
||||
### Windows
|
||||
@@ -99,6 +99,8 @@ auth:
|
||||
## DockerCompose部署
|
||||
感谢@wdkang123 同学分享的部署方式,如果有需要请查看[DockerCompose部署方式](./document/deploy/docker部署.md)
|
||||
## 感谢支持
|
||||
感谢jetbrains的开源支持,如果有朋友愿意一起维护,很欢迎提pr.
|
||||
|
||||
[](https://jb.gg/OpenSourceSupport)
|
||||
## 联系方式
|
||||
+ 微信群
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 220 KiB After Width: | Height: | Size: 127 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 439 KiB After Width: | Height: | Size: 605 KiB |
10
pom.xml
10
pom.xml
@@ -10,7 +10,7 @@
|
||||
</parent>
|
||||
<groupId>com.xuxd</groupId>
|
||||
<artifactId>kafka-console-ui</artifactId>
|
||||
<version>1.0.9</version>
|
||||
<version>1.1.0</version>
|
||||
<name>kafka-console-ui</name>
|
||||
<description>Kafka console manage ui</description>
|
||||
<properties>
|
||||
@@ -21,7 +21,7 @@
|
||||
<ui.path>${project.basedir}/ui</ui.path>
|
||||
<frontend-maven-plugin.version>1.11.0</frontend-maven-plugin.version>
|
||||
<compiler.version>1.8</compiler.version>
|
||||
<kafka.version>3.2.0</kafka.version>
|
||||
<kafka.version>3.5.0</kafka.version>
|
||||
<maven.assembly.plugin.version>3.0.0</maven.assembly.plugin.version>
|
||||
<mybatis-plus-boot-starter.version>3.4.2</mybatis-plus-boot-starter.version>
|
||||
<scala.version>2.13.6</scala.version>
|
||||
@@ -90,6 +90,12 @@
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.apache.kafka</groupId>-->
|
||||
<!-- <artifactId>kafka-tools</artifactId>-->
|
||||
<!-- <version>${kafka.version}</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>com.typesafe.scala-logging</groupId>
|
||||
<artifactId>scala-logging_2.13</artifactId>
|
||||
|
||||
@@ -33,4 +33,6 @@ public class QueryMessage {
|
||||
private String headerKey;
|
||||
|
||||
private String headerValue;
|
||||
|
||||
private int filterNumber;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,8 @@ public class QueryMessageDTO {
|
||||
|
||||
private String headerValue;
|
||||
|
||||
private int filterNumber;
|
||||
|
||||
public QueryMessage toQueryMessage() {
|
||||
QueryMessage queryMessage = new QueryMessage();
|
||||
queryMessage.setTopic(topic);
|
||||
@@ -69,6 +71,7 @@ public class QueryMessageDTO {
|
||||
if (StringUtils.isNotBlank(headerValue)) {
|
||||
queryMessage.setHeaderValue(headerValue.trim());
|
||||
}
|
||||
queryMessage.setFilterNumber(filterNumber);
|
||||
|
||||
return queryMessage;
|
||||
}
|
||||
|
||||
@@ -33,4 +33,9 @@ public class AuthController {
|
||||
public ResponseData login(@RequestBody LoginUserDTO userDTO) {
|
||||
return authService.login(userDTO);
|
||||
}
|
||||
|
||||
@GetMapping("/own/data/auth")
|
||||
public boolean ownDataAuthority() {
|
||||
return authService.ownDataAuthority();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,6 @@ import com.xuxd.kafka.console.beans.dto.LoginUserDTO;
|
||||
public interface AuthService {
|
||||
|
||||
ResponseData login(LoginUserDTO userDTO);
|
||||
|
||||
boolean ownDataAuthority();
|
||||
}
|
||||
|
||||
@@ -93,4 +93,16 @@ public class AuthServiceImpl implements AuthService {
|
||||
return ResponseData.create().data(loginResult).success();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean ownDataAuthority() {
|
||||
if (!authConfig.isEnable()) {
|
||||
return true;
|
||||
}
|
||||
if (!authConfig.isEnableClusterAuthority()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class MessageServiceImpl implements MessageService, ApplicationContextAwa
|
||||
|
||||
@Override
|
||||
public ResponseData searchByTime(QueryMessage queryMessage) {
|
||||
int maxNums = 5000;
|
||||
int maxNums = queryMessage.getFilterNumber() <= 0 ? 5000 : queryMessage.getFilterNumber();
|
||||
|
||||
Object searchContent = null;
|
||||
String headerKey = null;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
CREATE TABLE IF NOT EXISTS T_KAFKA_USER
|
||||
(
|
||||
ID IDENTITY NOT NULL COMMENT '主键ID',
|
||||
USERNAME VARCHAR(50) NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
PASSWORD VARCHAR(50) NOT NULL DEFAULT '' COMMENT '密码',
|
||||
USERNAME VARCHAR(128) NOT NULL DEFAULT '' COMMENT '用户名',
|
||||
PASSWORD VARCHAR(128) NOT NULL DEFAULT '' COMMENT '密码',
|
||||
UPDATE_TIME TIMESTAMP NOT NULL DEFAULT NOW() COMMENT '更新时间',
|
||||
CLUSTER_INFO_ID BIGINT NOT NULL COMMENT '集群信息里的集群ID',
|
||||
PRIMARY KEY (ID),
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.apache.kafka.common.utils.{KafkaThread, LogContext, Time}
|
||||
import org.slf4j.{Logger, LoggerFactory}
|
||||
|
||||
import java.io.IOException
|
||||
import java.util.Properties
|
||||
import java.util.{Collections, Properties}
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import java.util.concurrent.{ConcurrentLinkedQueue, TimeUnit}
|
||||
import scala.jdk.CollectionConverters.{ListHasAsScala, MapHasAsJava, PropertiesHasAsScala, SetHasAsScala}
|
||||
@@ -162,7 +162,7 @@ object BrokerApiVersion{
|
||||
|
||||
def listAllBrokerVersionInfo(): Map[Node, Try[NodeApiVersions]] =
|
||||
findAllBrokers().map { broker =>
|
||||
broker -> Try[NodeApiVersions](new NodeApiVersions(getApiVersions(broker)))
|
||||
broker -> Try[NodeApiVersions](new NodeApiVersions(getApiVersions(broker), Collections.emptyList(), false))
|
||||
}.toMap
|
||||
|
||||
def close(): Unit = {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
setPermissions,
|
||||
setToken,
|
||||
setUsername,
|
||||
deleteClusterInfo,
|
||||
} from "@/utils/local-cache";
|
||||
|
||||
Vue.use(Vuex);
|
||||
@@ -38,6 +39,9 @@ export default new Vuex.Store({
|
||||
state.clusterInfo.enableSasl = enableSasl;
|
||||
setClusterInfo(clusterInfo);
|
||||
},
|
||||
[CLUSTER.DELETE]() {
|
||||
deleteClusterInfo();
|
||||
},
|
||||
[AUTH.ENABLE](state, enable) {
|
||||
state.auth.enable = enable;
|
||||
},
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
export const CLUSTER = {
|
||||
SWITCH: "switchCluster",
|
||||
DELETE: "deleteClusterInfo",
|
||||
};
|
||||
|
||||
export const AUTH = {
|
||||
|
||||
@@ -365,6 +365,10 @@ export const AuthApi = {
|
||||
url: "/auth/login",
|
||||
method: "post",
|
||||
},
|
||||
ownDataAuthority: {
|
||||
url: "/auth/own/data/auth",
|
||||
method: "get",
|
||||
},
|
||||
};
|
||||
|
||||
export const ClusterRoleRelationApi = {
|
||||
|
||||
@@ -4,6 +4,10 @@ export function setClusterInfo(clusterInfo) {
|
||||
localStorage.setItem(Cache.clusterInfo, JSON.stringify(clusterInfo));
|
||||
}
|
||||
|
||||
export function deleteClusterInfo() {
|
||||
localStorage.removeItem(Cache.clusterInfo);
|
||||
}
|
||||
|
||||
export function getClusterInfo() {
|
||||
const str = localStorage.getItem(Cache.clusterInfo);
|
||||
return str ? JSON.parse(str) : undefined;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<a-input
|
||||
placeholder="username"
|
||||
:allowClear="true"
|
||||
:maxLength="30"
|
||||
:maxLength="100"
|
||||
v-decorator="[
|
||||
'username',
|
||||
{
|
||||
@@ -30,7 +30,7 @@
|
||||
<a-input
|
||||
placeholder="password"
|
||||
:allowClear="true"
|
||||
:maxLength="30"
|
||||
:maxLength="100"
|
||||
v-decorator="[
|
||||
'password',
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<h3 class="login-title">登录kafka-console-ui</h3>
|
||||
<a-form-item label="账号">
|
||||
<a-input
|
||||
@keyup.enter="handleSubmit"
|
||||
style="width: 200px"
|
||||
allowClear
|
||||
v-decorator="[
|
||||
@@ -20,6 +21,7 @@
|
||||
</a-form-item>
|
||||
<a-form-item label="密码">
|
||||
<a-input-password
|
||||
@keyup.enter="handleSubmit"
|
||||
style="width: 200px"
|
||||
v-decorator="[
|
||||
'password',
|
||||
@@ -28,7 +30,11 @@
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item :wrapper-col="{ span: 16, offset: 5 }">
|
||||
<a-button type="primary" @click="handleSubmit" :loading="loading"
|
||||
<a-button
|
||||
type="primary"
|
||||
@click="handleSubmit"
|
||||
:loading="loading"
|
||||
@keyup.enter="handleSubmit"
|
||||
>登录</a-button
|
||||
>
|
||||
</a-form-item>
|
||||
@@ -40,7 +46,7 @@ import request from "@/utils/request";
|
||||
import { AuthApi } from "@/utils/api";
|
||||
import notification from "ant-design-vue/lib/notification";
|
||||
import { mapMutations } from "vuex";
|
||||
import { AUTH } from "@/store/mutation-types";
|
||||
import { AUTH, CLUSTER } from "@/store/mutation-types";
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
@@ -82,8 +88,19 @@ export default {
|
||||
setToken: AUTH.SET_TOKEN,
|
||||
setUsername: AUTH.SET_USERNAME,
|
||||
setPermissions: AUTH.SET_PERMISSIONS,
|
||||
deleteClusterInfo: CLUSTER.DELETE,
|
||||
}),
|
||||
},
|
||||
created() {
|
||||
request({
|
||||
url: AuthApi.ownDataAuthority.url,
|
||||
method: AuthApi.ownDataAuthority.method,
|
||||
}).then((res) => {
|
||||
if (!res) {
|
||||
this.deleteClusterInfo();
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
@@ -24,7 +24,11 @@
|
||||
<DeleteMessage :topic-list="topicList"></DeleteMessage>
|
||||
</a-tab-pane>
|
||||
|
||||
<a-tab-pane key="5" tab="发送统计" v-if="isAuthorized('message:send-statistics')">
|
||||
<a-tab-pane
|
||||
key="5"
|
||||
tab="发送统计"
|
||||
v-if="isAuthorized('message:send-statistics')"
|
||||
>
|
||||
<SendStatistics :topic-list="topicList"></SendStatistics>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
|
||||
@@ -60,6 +60,33 @@
|
||||
</a-col>
|
||||
</a-row>
|
||||
<hr class="hr" />
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="24">
|
||||
<a-form-item label="最大检索数">
|
||||
<a-input-number
|
||||
v-decorator="[
|
||||
'filterNumber',
|
||||
{
|
||||
initialValue: 5000,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '输入消息数!',
|
||||
},
|
||||
],
|
||||
},
|
||||
]"
|
||||
:min="1"
|
||||
:max="100000"
|
||||
/>
|
||||
<span
|
||||
>条
|
||||
注意:这里允许最多检索10万条,但是不建议将该值设置过大,这意味着一次查询要在内存里缓存这么多的数据,可能导致内存溢出;并且更大的消息量会导致更长的检索时间</span
|
||||
>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<hr class="hr" />
|
||||
<a-row :gutter="24">
|
||||
<a-col :span="5">
|
||||
<a-form-item label="消息过滤">
|
||||
|
||||
@@ -91,6 +91,7 @@ export default {
|
||||
loading: false,
|
||||
form: this.$form.createForm(this, { name: "coordinated" }),
|
||||
brokerSize: 0,
|
||||
brokerIdList: [],
|
||||
replicaNums: 0,
|
||||
defaultReplicaNums: 0,
|
||||
};
|
||||
@@ -136,6 +137,8 @@ export default {
|
||||
method: KafkaClusterApi.getClusterInfo.method,
|
||||
}).then((res) => {
|
||||
this.brokerSize = res.data.nodes.length;
|
||||
this.brokerIdList = res.data.nodes.map((o) => o.id);
|
||||
this.brokerIdList.sort((a, b) => a - b);
|
||||
});
|
||||
},
|
||||
handleCancel() {
|
||||
@@ -149,9 +152,16 @@ export default {
|
||||
if (this.data.partitions.length > 0) {
|
||||
this.data.partitions.forEach((p) => {
|
||||
if (value > p.replicas.length) {
|
||||
let min = this.brokerIdList[0];
|
||||
let max = this.brokerIdList[this.brokerSize - 1] + 1;
|
||||
let num = p.replicas[p.replicas.length - 1];
|
||||
for (let i = p.replicas.length; i < value; i++) {
|
||||
p.replicas.push(++num % this.brokerSize);
|
||||
++num;
|
||||
if (num < max) {
|
||||
p.replicas.push(num);
|
||||
} else {
|
||||
p.replicas.push((num % max) + min);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (value < p.replicas.length) {
|
||||
|
||||
Reference in New Issue
Block a user