From b19ccc7f8361b9e1cdf5e833da329979fe5436d2 Mon Sep 17 00:00:00 2001 From: yuanziwei Date: Tue, 4 Jun 2024 14:32:07 +0800 Subject: [PATCH 1/3] Support dashboard v4-v5 switch And query for v5 topic --- .../dashboard/controller/TopicController.java | 6 ++ .../model/request/TopicTypeList.java | 45 ++++++++++++++ .../model/request/TopicTypeMeta.java | 38 ++++++++++++ .../dashboard/service/TopicService.java | 3 + .../service/impl/TopicServiceImpl.java | 39 +++++++++++++ src/main/resources/static/src/controller.js | 7 +++ src/main/resources/static/src/i18n/en.js | 3 + src/main/resources/static/src/i18n/zh.js | 3 + src/main/resources/static/src/topic.js | 58 ++++++++++++++----- .../resources/static/view/layout/_header.html | 8 +++ .../resources/static/view/pages/topic.html | 6 ++ 11 files changed, 202 insertions(+), 14 deletions(-) create mode 100644 src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeList.java create mode 100644 src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeMeta.java diff --git a/src/main/java/org/apache/rocketmq/dashboard/controller/TopicController.java b/src/main/java/org/apache/rocketmq/dashboard/controller/TopicController.java index ebed69e1..467c18e4 100644 --- a/src/main/java/org/apache/rocketmq/dashboard/controller/TopicController.java +++ b/src/main/java/org/apache/rocketmq/dashboard/controller/TopicController.java @@ -56,6 +56,12 @@ public Object list(@RequestParam(value = "skipSysProcess", required = false) boo return topicService.fetchAllTopicList(skipSysProcess, skipRetryAndDlq); } + @RequestMapping(value = "/list.queryTopicType", method = RequestMethod.GET) + @ResponseBody + public Object listTopicType() { + return topicService.examineAllTopicType(); + } + @RequestMapping(value = "/stats.query", method = RequestMethod.GET) @ResponseBody public Object stats(@RequestParam String topic) { diff --git a/src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeList.java b/src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeList.java new file mode 100644 index 00000000..e7b8148f --- /dev/null +++ b/src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeList.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.dashboard.model.request; + +import java.util.List; + +public class TopicTypeList { + private List topicNameList; + private List messageTypeList; + + public List getTopicNameList() { + return topicNameList; + } + + public void setTopicNameList(List topicNameList) { + this.topicNameList = topicNameList; + } + + public List getMessageTypeList() { + return messageTypeList; + } + + public void setMessageTypeList(List messageTypeList) { + this.messageTypeList = messageTypeList; + } + + public TopicTypeList(List topicNameList, List messageTypeList) { + this.topicNameList = topicNameList; + this.messageTypeList = messageTypeList; + } +} diff --git a/src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeMeta.java b/src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeMeta.java new file mode 100644 index 00000000..a1fe9350 --- /dev/null +++ b/src/main/java/org/apache/rocketmq/dashboard/model/request/TopicTypeMeta.java @@ -0,0 +1,38 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.rocketmq.dashboard.model.request; + +public class TopicTypeMeta { + private String topicName; + private String messageType; + + public String getTopicName() { + return topicName; + } + + public void setTopicName(String topicName) { + this.topicName = topicName; + } + + public String getMessageType() { + return messageType; + } + + public void setMessageType(String messageType) { + this.messageType = messageType; + } +} diff --git a/src/main/java/org/apache/rocketmq/dashboard/service/TopicService.java b/src/main/java/org/apache/rocketmq/dashboard/service/TopicService.java index 3a28444f..9ff0bf0c 100644 --- a/src/main/java/org/apache/rocketmq/dashboard/service/TopicService.java +++ b/src/main/java/org/apache/rocketmq/dashboard/service/TopicService.java @@ -19,6 +19,7 @@ import org.apache.rocketmq.client.producer.SendResult; import org.apache.rocketmq.common.TopicConfig; +import org.apache.rocketmq.dashboard.model.request.TopicTypeList; import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable; import org.apache.rocketmq.remoting.protocol.body.GroupList; import org.apache.rocketmq.remoting.protocol.body.TopicList; @@ -31,6 +32,8 @@ public interface TopicService { TopicList fetchAllTopicList(boolean skipSysProcess, boolean skipRetryAndDlq); + TopicTypeList examineAllTopicType(); + TopicStatsTable stats(String topic); TopicRouteData route(String topic); diff --git a/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java b/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java index ecd08de2..4f34fc64 100644 --- a/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java +++ b/src/main/java/org/apache/rocketmq/dashboard/service/impl/TopicServiceImpl.java @@ -40,6 +40,8 @@ import org.apache.rocketmq.dashboard.config.RMQConfigure; import org.apache.rocketmq.dashboard.model.request.SendTopicMessageRequest; import org.apache.rocketmq.dashboard.model.request.TopicConfigInfo; +import org.apache.rocketmq.dashboard.model.request.TopicTypeList; +import org.apache.rocketmq.dashboard.model.request.TopicTypeMeta; import org.apache.rocketmq.dashboard.service.AbstractCommonService; import org.apache.rocketmq.dashboard.service.TopicService; import org.apache.rocketmq.remoting.RPCHook; @@ -54,7 +56,9 @@ import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -99,6 +103,41 @@ public TopicList fetchAllTopicList(boolean skipSysProcess, boolean skipRetryAndD } } + @Override + public TopicTypeList examineAllTopicType() { + ArrayList topicTypes = new ArrayList<>(); + ArrayList names = new ArrayList<>(); + ArrayList messageTypes = new ArrayList<>(); + TopicList topicList = fetchAllTopicList(false, false); + checkTopicType(topicList, topicTypes); + topicTypes.sort((t1, t2) -> t1.getTopicName().compareTo(t2.getTopicName())); + for (TopicTypeMeta topicTypeMeta : topicTypes) { + names.add(topicTypeMeta.getTopicName()); + messageTypes.add(topicTypeMeta.getMessageType()); + } + return new TopicTypeList(names, messageTypes); + } + + private void checkTopicType(TopicList topicList, ArrayList topicTypes) { + for (String topicName : topicList.getTopicList()) { + TopicTypeMeta topicType = new TopicTypeMeta(); + topicType.setTopicName(topicName); + if (topicName.startsWith("%R")) { + topicType.setMessageType("RETRY"); + } else if (topicName.startsWith("%D")) { + topicType.setMessageType("DELAY"); + } else if (topicName.startsWith("%S")) { + topicType.setMessageType("SYSTEM"); + } else { + List topicConfigInfos = examineTopicConfig(topicName); + if (!CollectionUtils.isEmpty(topicConfigInfos)) { + topicType.setMessageType(topicConfigInfos.get(0).getMessageType()); + } + } + topicTypes.add(topicType); + } + } + @Override public TopicStatsTable stats(String topic) { try { diff --git a/src/main/resources/static/src/controller.js b/src/main/resources/static/src/controller.js index cdcced59..4a861c41 100644 --- a/src/main/resources/static/src/controller.js +++ b/src/main/resources/static/src/controller.js @@ -15,10 +15,17 @@ * limitations under the License. */ app.controller('AppCtrl', ['$scope','$window','$translate','$http','Notification', function ($scope,$window,$translate, $http, Notification) { + $scope.rmqVersion = localStorage.getItem("isV5") === "true" ? true : false; + $scope.changeTranslate = function(langKey){ $translate.use(langKey); } + $scope.changeRMQVersion = function (version) { + $scope.rmqVersion = version === 5; + localStorage.setItem("isV5", $scope.rmqVersion); + } + $scope.logout = function(){ $http({ method: "POST", diff --git a/src/main/resources/static/src/i18n/en.js b/src/main/resources/static/src/i18n/en.js index 943ce482..6bc16cd3 100644 --- a/src/main/resources/static/src/i18n/en.js +++ b/src/main/resources/static/src/i18n/en.js @@ -54,9 +54,12 @@ var en = { "RESET_CUS_OFFSET": "Reset Consumer Offset", "DELETE": "Delete", "CHANGE_LANG": "ChangeLanguage", + "CHANGE_VERSION": "ChangeVersion", "BROKER": "Broker", "NORMAL": "NORMAL", "RETRY": "RETRY", + "FIFO": "FIFO", + "TRANSACTION": "TRANSACTION", "DLQ": "DLQ", "QUANTITY":"Quantity", "TYPE":"Type", diff --git a/src/main/resources/static/src/i18n/zh.js b/src/main/resources/static/src/i18n/zh.js index 8a3b3ff0..f71ae346 100644 --- a/src/main/resources/static/src/i18n/zh.js +++ b/src/main/resources/static/src/i18n/zh.js @@ -55,9 +55,12 @@ var zh = { "SKIP_MESSAGE_ACCUMULATE":"跳过堆积", "DELETE": "删除", "CHANGE_LANG": "更换语言", + "CHANGE_VERSION": "更换版本", "BROKER": "Broker", "NORMAL": "普通", "RETRY": "重试", + "FIFO": "顺序", + "TRANSACTION": "事务", "DLQ": "死信", "QUANTITY":"数量", "TYPE":"类型", diff --git a/src/main/resources/static/src/topic.js b/src/main/resources/static/src/topic.js index bce0df87..a4555723 100644 --- a/src/main/resources/static/src/topic.js +++ b/src/main/resources/static/src/topic.js @@ -45,24 +45,30 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati } }; $scope.filterNormal = true + $scope.filterDelay = false + $scope.filterFifo = false + $scope.filterTransaction = false $scope.filterRetry = false $scope.filterDLQ = false $scope.filterSystem = false $scope.allTopicList = []; + $scope.allTopicNameList = []; + $scope.allMessageTypeList = []; $scope.topicShowList = []; $scope.userRole = $window.sessionStorage.getItem("userrole"); - $scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false); + $scope.writeOperationEnabled = $scope.userRole == null ? true : ($scope.userRole == 1 ? true : false); $scope.refreshTopicList = function () { $http({ method: "GET", - url: "topic/list.query" + url: "topic/list.queryTopicType" }).success(function (resp) { if (resp.status == 0) { - $scope.allTopicList = resp.data.topicList.sort(); - console.log($scope.allTopicList); + $scope.allTopicNameList = resp.data.topicNameList; + $scope.allMessageTypeList = resp.data.messageTypeList; + console.log($scope.allTopicNameList); console.log(JSON.stringify(resp)); - $scope.showTopicList(1, $scope.allTopicList.length); + $scope.showTopicList(1, $scope.allTopicNameList.length); } else { Notification.error({message: resp.errMsg, delay: 5000}); @@ -79,6 +85,15 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati $scope.$watch('filterNormal', function () { $scope.filterList(1); }); + $scope.$watch('filterFifo', function () { + $scope.filterList(1); + }); + $scope.$watch('filterTransaction', function () { + $scope.filterList(1); + }); + $scope.$watch('filterDelay', function () { + $scope.filterList(1); + }); $scope.$watch('filterRetry', function () { $scope.filterList(1); }); @@ -92,13 +107,13 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati var lowExceptStr = $scope.filterStr.toLowerCase(); var canShowList = []; - $scope.allTopicList.forEach(function (element) { - if ($scope.filterByType(element)) { - if (element.toLowerCase().indexOf(lowExceptStr) != -1) { - canShowList.push(element); + for (let i = 0; i < $scope.allTopicNameList.length; ++i) { + if ($scope.filterByType($scope.allTopicNameList[i], $scope.allMessageTypeList[i])) { + if ($scope.allTopicNameList[i].toLowerCase().indexOf(lowExceptStr) != -1) { + canShowList.push($scope.allTopicNameList[i]); } } - }); + } $scope.paginationConf.totalItems = canShowList.length; var perPage = $scope.paginationConf.itemsPerPage; var from = (currentPage - 1) * perPage; @@ -106,7 +121,7 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati $scope.topicShowList = canShowList.slice(from, to); }; - $scope.filterByType = function (str) { + $scope.filterByType = function (str, type) { if ($scope.filterRetry) { if (str.startsWith("%R")) { return true @@ -123,7 +138,22 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati } } if ($scope.filterNormal) { - if (str.startsWith("%") == false) { + if (type.includes("NORMAL")) { + return true + } + } + if ($scope.filterDelay) { + if (type.includes("DELAY")) { + return true + } + } + if ($scope.filterFifo) { + if (type.includes("FIFO")) { + return true + } + } + if ($scope.filterTransaction) { + if (type.includes("TRANSACTION")) { return true } } @@ -138,10 +168,10 @@ module.controller('topicController', ['$scope', 'ngDialog', '$http', 'Notificati var perPage = $scope.paginationConf.itemsPerPage; var from = (currentPage - 1) * perPage; var to = (from + perPage) > totalItem ? totalItem : from + perPage; - console.log($scope.allTopicList); + console.log($scope.allTopicNameList); console.log(from) console.log(to) - $scope.topicShowList = $scope.allTopicList.slice(from, to); + $scope.topicShowList = $scope.allTopicNameList.slice(from, to); $scope.paginationConf.totalItems = totalItem; console.log($scope.topicShowList) console.log($scope.paginationConf.totalItems) diff --git a/src/main/resources/static/view/layout/_header.html b/src/main/resources/static/view/layout/_header.html index f4485418..9e05b093 100644 --- a/src/main/resources/static/view/layout/_header.html +++ b/src/main/resources/static/view/layout/_header.html @@ -47,6 +47,14 @@
  • Simplified Chinese
  • +