Compare commits

...

4 Commits

Author SHA1 Message Date
Crazylychee
a5138eb0d8 [ISSUE #317] Removed useless topic cache 2025-06-24 15:21:57 +08:00
Crazylychee
b43c7abe52 [ISSUE #321] Fix interface permission verification 2025-06-24 15:21:25 +08:00
Crazylychee
bfd0e26737 [ISSUE #319] Store the username in localStorage 2025-06-24 15:21:10 +08:00
Crazylychee
31d8086db3 [ISSUES#323]: fix Maven packaging error 2025-06-24 14:56:12 +08:00
20 changed files with 95 additions and 165 deletions

View File

@@ -536,22 +536,6 @@ const remoteApi = {
} }
}, },
refreshTopicList: async () => {
try {
const response = await remoteApi._fetch(remoteApi.buildUrl("/topic/refresh"), {
method: 'POST'
});
const result = await response.json();
if (result.status === 0 && result.data === true) {
return remoteApi.queryTopicList();
}
return result;
} catch (error) {
console.error("Error refreshing topic list:", error);
return { status: 1, errMsg: "Failed to refresh topic list" };
}
},
deleteTopic: async (topic) => { deleteTopic: async (topic) => {
try { try {
const url = remoteApi.buildUrl(`/topic/deleteTopic.do?topic=${encodeURIComponent(topic)}`); const url = remoteApi.buildUrl(`/topic/deleteTopic.do?topic=${encodeURIComponent(topic)}`);

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import React, { useState } from 'react'; import React, {useEffect, useState} from 'react';
import { Layout, Menu, Dropdown, Button, Drawer, Grid, Space } from 'antd'; import { Layout, Menu, Dropdown, Button, Drawer, Grid, Space } from 'antd';
import {GlobalOutlined, DownOutlined, UserOutlined, MenuOutlined, BgColorsOutlined} from '@ant-design/icons'; import {GlobalOutlined, DownOutlined, UserOutlined, MenuOutlined, BgColorsOutlined} from '@ant-design/icons';
import { useLocation, useNavigate } from 'react-router-dom'; import { useLocation, useNavigate } from 'react-router-dom';
@@ -26,13 +26,13 @@ import {remoteApi} from "../api/remoteApi/remoteApi";
const { Header } = Layout; const { Header } = Layout;
const { useBreakpoint } = Grid; // Used to determine screen breakpoints const { useBreakpoint } = Grid; // Used to determine screen breakpoints
const Navbar = ({ username, rmqVersion = true, showAcl = true}) => { const Navbar = ({ rmqVersion = true, showAcl = true}) => {
const location = useLocation(); const location = useLocation();
const navigate = useNavigate(); const navigate = useNavigate();
const { lang, setLang, t } = useLanguage(); const { lang, setLang, t } = useLanguage();
const screens = useBreakpoint(); // Get current screen size breakpoints const screens = useBreakpoint(); // Get current screen size breakpoints
const { currentThemeName, setCurrentThemeName } = useTheme(); const { currentThemeName, setCurrentThemeName } = useTheme();
const [userName, setUserName] = useState(null);
const [drawerVisible, setDrawerVisible] = useState(false); // Controls drawer visibility const [drawerVisible, setDrawerVisible] = useState(false); // Controls drawer visibility
// Get selected menu item key based on current route path // Get selected menu item key based on current route path
@@ -46,10 +46,10 @@ const Navbar = ({ username, rmqVersion = true, showAcl = true}) => {
const onLogout = () => { const onLogout = () => {
remoteApi.logout().then(res => { remoteApi.logout().then(res => {
if (res.status === 0) { if (res.status === 0) {
window.sessionStorage.removeItem("username"); window.localStorage.removeItem("username");
window.sessionStorage.removeItem("userRole"); window.localStorage.removeItem("userRole");
window.sessionStorage.removeItem("token"); window.localStorage.removeItem("token");
window.sessionStorage.removeItem("rmqVersion"); window.localStorage.removeItem("rmqVersion");
navigate('/login'); navigate('/login');
} else { } else {
console.error('Logout failed:', res.message) console.error('Logout failed:', res.message)
@@ -59,6 +59,15 @@ const Navbar = ({ username, rmqVersion = true, showAcl = true}) => {
}; };
useEffect(() => {
const storedUsername = window.localStorage.getItem("username");
if (storedUsername) {
setUserName(storedUsername);
}else {
setUserName(null);
}
}, []);
const langMenu = ( const langMenu = (
<Menu onClick={({ key }) => setLang(key)}> <Menu onClick={({ key }) => setLang(key)}>
<Menu.Item key="en">{t.ENGLISH}</Menu.Item> <Menu.Item key="en">{t.ENGLISH}</Menu.Item>
@@ -66,13 +75,6 @@ const Navbar = ({ username, rmqVersion = true, showAcl = true}) => {
</Menu> </Menu>
); );
const versionMenu = (
<Menu onClick={({ key }) => alert(t.version.switchVersion + ': ' + key)}>
<Menu.Item key="5">RocketMQ v5</Menu.Item>
<Menu.Item key="4">RocketMQ v4</Menu.Item>
</Menu>
);
const userMenu = ( const userMenu = (
<Menu> <Menu>
<Menu.Item key="logout" onClick={onLogout}>{t.LOGOUT}</Menu.Item> <Menu.Item key="logout" onClick={onLogout}>{t.LOGOUT}</Menu.Item>
@@ -159,12 +161,12 @@ const Navbar = ({ username, rmqVersion = true, showAcl = true}) => {
</Button> </Button>
</Dropdown> </Dropdown>
{username && ( {userName && (
<Dropdown overlay={userMenu}> <Dropdown overlay={userMenu}>
{/* 使用一个可点击的元素作为 Dropdown 的唯一子元素 */} {/* 使用一个可点击的元素作为 Dropdown 的唯一子元素 */}
<a onClick={e => e.preventDefault()} style={{ display: 'flex', alignItems: 'center' }}> <a onClick={e => e.preventDefault()} style={{ display: 'flex', alignItems: 'center' }}>
<UserOutlined style={{ marginRight: 8 }} /> {/* 添加一些间距 */} <UserOutlined style={{ marginRight: 8 }} /> {/* 添加一些间距 */}
{username} {userName}
<DownOutlined style={{ marginLeft: 8 }} /> <DownOutlined style={{ marginLeft: 8 }} />
</a> </a>
</Dropdown> </Dropdown>

View File

@@ -15,7 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import {Button, Checkbox, Form, Input, message, Modal} from "antd"; import {Button, Checkbox, Form, Input, Modal} from "antd";
import React, {useEffect} from "react"; import React, {useEffect} from "react";
import {remoteApi} from "../../api/remoteApi/remoteApi"; import {remoteApi} from "../../api/remoteApi/remoteApi";
@@ -26,6 +26,7 @@ const SendTopicMessageDialog = ({
setSendResultData, setSendResultData,
setIsSendResultModalVisible, setIsSendResultModalVisible,
setIsSendTopicMessageModalVisible, setIsSendTopicMessageModalVisible,
message,
t, t,
}) => { }) => {
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -46,8 +47,8 @@ const SendTopicMessageDialog = ({
const handleSendTopicMessage = async () => { const handleSendTopicMessage = async () => {
try { try {
const values = await form.validateFields(); // 👈 从表单获取最新值 const values = await form.validateFields();
const result = await remoteApi.sendTopicMessage(values); // 👈 用表单数据发送 const result = await remoteApi.sendTopicMessage(values);
if (result.status === 0) { if (result.status === 0) {
setSendResultData(result.data); setSendResultData(result.data);
setIsSendResultModalVisible(true); setIsSendResultModalVisible(true);

View File

@@ -278,7 +278,7 @@ export const translations = {
"PLEASE_ADD_RESOURCE": "请添加资源!", "PLEASE_ADD_RESOURCE": "请添加资源!",
"ENTER_IP_HINT": "请输入 IP 地址,按回车键添加,支持 IPv4、IPv6 和 CIDR", "ENTER_IP_HINT": "请输入 IP 地址,按回车键添加,支持 IPv4、IPv6 和 CIDR",
"PLEASE_ENTER_DECISION": "请输入决策!", "PLEASE_ENTER_DECISION": "请输入决策!",
"MENU": "菜单",
}, },
en: { en: {
"DEFAULT": "Default", "DEFAULT": "Default",
@@ -535,6 +535,8 @@ export const translations = {
"PLEASE_ADD_RESOURCE": "Please add resource!", "PLEASE_ADD_RESOURCE": "Please add resource!",
"ENTER_IP_HINT": "Please enter IP address, press Enter to add. Supports IPv4, IPv6, and CIDR.", "ENTER_IP_HINT": "Please enter IP address, press Enter to add. Supports IPv4, IPv6, and CIDR.",
"PLEASE_ENTER_DECISION": "Please enter decision!", "PLEASE_ENTER_DECISION": "Please enter decision!",
"MENU": "Menu",
} }
}; };

View File

@@ -488,7 +488,7 @@ const Acl = () => {
dataIndex: 'userStatus', dataIndex: 'userStatus',
key: 'userStatus', key: 'userStatus',
render: (status) => ( render: (status) => (
<Tag color={status=== 'enable' ? 'red' : 'green'}>{status}</Tag> <Tag color={status=== 'enable' ? 'green' : 'red'}>{status}</Tag>
), ),
}, },
{ {

View File

@@ -30,8 +30,8 @@ const Login = () => {
remoteApi.login(username, password).then((res) => { remoteApi.login(username, password).then((res) => {
if (res.status === 0) { if (res.status === 0) {
messageApi.success('登录成功'); messageApi.success('登录成功');
window.sessionStorage.setItem("username", res.data.loginUserName); window.localStorage.setItem("username", res.data.loginUserName);
window.sessionStorage.setItem("userrole", res.data.loginUserRole); window.localStorage.setItem("userrole", res.data.loginUserRole);
window.location.href = '/'; window.location.href = '/';
} else { } else {
messageApi.error(res.message || '登录失败,请检查用户名和密码'); messageApi.error(res.message || '登录失败,请检查用户名和密码');

View File

@@ -172,28 +172,7 @@ const DeployHistoryList = () => {
} }
}; };
const refreshTopicList = async () => {
setLoading(true);
try {
const result = await remoteApi.refreshTopicList();
if (result.status === 0) {
setAllTopicList(result.data.topicNameList);
setAllMessageTypeList(result.data.messageTypeList);
setPaginationConf(prev => ({
...prev,
total: result.data.topicNameList.length
}));
messageApi.success(t.REFRESHING_TOPIC_LIST);
} else {
messageApi.error(result.errMsg);
}
} catch (error) {
console.error("Error refreshing topic list:", error);
messageApi.error("Failed to refresh topic list");
} finally {
setLoading(false);
}
};
const filterList = (currentPage) => { const filterList = (currentPage) => {
const lowExceptStr = filterStr.toLowerCase(); const lowExceptStr = filterStr.toLowerCase();
@@ -298,7 +277,7 @@ const DeployHistoryList = () => {
messageApi.success(t.TOPIC_OPERATION_SUCCESS); messageApi.success(t.TOPIC_OPERATION_SUCCESS);
closeAddUpdateDialog(); closeAddUpdateDialog();
if(!isUpdateMode) { if(!isUpdateMode) {
refreshTopicList(); await getTopicList()
} }
} else { } else {
messageApi.error(result.errMsg); messageApi.error(result.errMsg);
@@ -316,7 +295,7 @@ const DeployHistoryList = () => {
if (result.status === 0) { if (result.status === 0) {
messageApi.success(`${t.TOPIC} [${topicToDelete}] ${t.DELETED_SUCCESSFULLY}`); messageApi.success(`${t.TOPIC} [${topicToDelete}] ${t.DELETED_SUCCESSFULLY}`);
setAllTopicList(allTopicList.filter(topic => topic !== topicToDelete)); setAllTopicList(allTopicList.filter(topic => topic !== topicToDelete));
await refreshTopicList() await getTopicList()
} else { } else {
messageApi.error(result.errMsg); messageApi.error(result.errMsg);
} }
@@ -614,7 +593,7 @@ const DeployHistoryList = () => {
</Form.Item> </Form.Item>
)} )}
<Form.Item> <Form.Item>
<Button type="primary" onClick={refreshTopicList}> <Button type="primary" onClick={getTopicList}>
{t.REFRESH} {t.REFRESH}
</Button> </Button>
</Form.Item> </Form.Item>
@@ -714,6 +693,7 @@ const DeployHistoryList = () => {
setIsSendResultModalVisible={setIsSendResultModalVisible} setIsSendResultModalVisible={setIsSendResultModalVisible}
setIsSendTopicMessageModalVisible={setIsSendTopicMessageModalVisible} setIsSendTopicMessageModalVisible={setIsSendTopicMessageModalVisible}
sendTopicMessageData={sendTopicMessageData} sendTopicMessageData={sendTopicMessageData}
message={messageApi}
t={t} t={t}
/> />
</div> </div>

View File

@@ -71,7 +71,7 @@ const AppRouter = () => {
return ( return (
<Layout style={{minHeight: '100vh'}}> <Layout style={{minHeight: '100vh'}}>
<Header style={{padding: 0, height: 'auto', lineHeight: 'normal'}}> <Header style={{padding: 0, height: 'auto', lineHeight: 'normal'}}>
<Navbar username={window.sessionStorage.getItem("username")}/> <Navbar/>
</Header> </Header>
<Content style={{padding: '24px'}}> <Content style={{padding: '24px'}}>

46
pom.xml
View File

@@ -84,6 +84,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source> <maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target> <maven.compiler.target>17</maven.compiler.target>
<maven.test.skip>false</maven.test.skip>
<guava.version>29.0-jre</guava.version> <guava.version>29.0-jre</guava.version>
<commons-digester.version>2.1</commons-digester.version> <commons-digester.version>2.1</commons-digester.version>
<commons-lang.version>2.6</commons-lang.version> <commons-lang.version>2.6</commons-lang.version>
@@ -310,13 +311,13 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring.boot.version}</version> <version>${spring.boot.version}</version>
<!-- <executions>--> <executions>
<!-- <execution>--> <execution>
<!-- <goals>--> <goals>
<!-- <goal>repackage</goal>--> <goal>repackage</goal>
<!-- </goals>--> </goals>
<!-- </execution>--> </execution>
<!-- </executions>--> </executions>
</plugin> </plugin>
<!-- Use dockerfile-maven instead, https://github.com/spotify/dockerfile-maven --> <!-- Use dockerfile-maven instead, https://github.com/spotify/dockerfile-maven -->
<plugin> <plugin>
@@ -412,11 +413,11 @@
<exclude>docs/**</exclude> <exclude>docs/**</exclude>
<exclude>src/main/resources/static/vendor/**</exclude> <exclude>src/main/resources/static/vendor/**</exclude>
<exclude>src/main/resources/static/src/data/**</exclude> <exclude>src/main/resources/static/src/data/**</exclude>
<exclude>frontend/node_modules/**</exclude> <exclude>frontend-new/node_modules/**</exclude>
<exclude>frontend/build/**</exclude> <exclude>frontend-new/build/**</exclude>
<exclude>frontend/**.json</exclude> <exclude>frontend-new/**.json</exclude>
<exclude>frontend/**.lock</exclude> <exclude>frontend-new/**.lock</exclude>
<exclude>frontend/public/manifest.json</exclude> <exclude>frontend-new/public/manifest.json</exclude>
<exclude>package-lock.json</exclude> <exclude>package-lock.json</exclude>
</excludes> </excludes>
</configuration> </configuration>
@@ -431,32 +432,31 @@
</configuration> </configuration>
<executions> <executions>
<execution> <execution>
<id>install node and yarn</id> <id>install node </id>
<goals> <goals>
<goal>install-node-and-yarn</goal> <goal>install-node-and-npm</goal>
</goals> </goals>
<configuration> <configuration>
<nodeVersion>v16.2.0</nodeVersion> <nodeVersion>v18.2.0</nodeVersion>
<yarnVersion>v1.22.10</yarnVersion>
</configuration> </configuration>
</execution> </execution>
<execution> <execution>
<id>yarn install</id> <id>npm install</id>
<goals> <goals>
<goal>yarn</goal> <goal>npm</goal>
</goals> </goals>
<configuration> <configuration>
<arguments>install</arguments> <arguments>install --legacy-peer-deps</arguments>
</configuration> </configuration>
</execution> </execution>
<execution> <execution>
<id>yarn build</id> <id>npm build</id>
<goals> <goals>
<goal>yarn</goal> <goal>npm</goal>
</goals> </goals>
<configuration> <configuration>
<arguments>build</arguments> <arguments>run build</arguments>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
@@ -469,7 +469,7 @@
<configuration> <configuration>
<target> <target>
<copy todir="${project.build.directory}/classes/public"> <copy todir="${project.build.directory}/classes/public">
<fileset dir="${project.basedir}/frontend/build" /> <fileset dir="${project.basedir}/frontend-new/build" />
</copy> </copy>
</target> </target>
</configuration> </configuration>

View File

@@ -55,11 +55,6 @@ public class TopicController {
return topicService.fetchAllTopicList(skipSysProcess, skipRetryAndDlq); return topicService.fetchAllTopicList(skipSysProcess, skipRetryAndDlq);
} }
@RequestMapping(value = "/refresh", method = {RequestMethod.POST})
@ResponseBody
public Object refresh() {
return topicService.refreshTopicList();
}
@RequestMapping(value = "/list.queryTopicType", method = RequestMethod.GET) @RequestMapping(value = "/list.queryTopicType", method = RequestMethod.GET)
@ResponseBody @ResponseBody

View File

@@ -19,6 +19,7 @@ package org.apache.rocketmq.dashboard.permisssion;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import org.apache.rocketmq.dashboard.config.RMQConfigure; import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.exception.ServiceException;
import org.apache.rocketmq.dashboard.model.UserInfo; import org.apache.rocketmq.dashboard.model.UserInfo;
import org.apache.rocketmq.dashboard.service.PermissionService; import org.apache.rocketmq.dashboard.service.PermissionService;
import org.apache.rocketmq.dashboard.util.WebUtil; import org.apache.rocketmq.dashboard.util.WebUtil;
@@ -55,13 +56,13 @@ public class PermissionAspect {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String url = request.getRequestURI(); String url = request.getRequestURI();
UserInfo userInfo = (UserInfo) request.getSession().getAttribute(WebUtil.USER_INFO); UserInfo userInfo = (UserInfo) request.getSession().getAttribute(WebUtil.USER_INFO);
// if (userInfo == null || userInfo.getUser() == null) { if (userInfo == null || userInfo.getUser() == null) {
// throw new ServiceException(-1, "user not login"); throw new ServiceException(-1, "user not login");
// } }
// boolean checkResult = permissionService.checkUrlAvailable(userInfo, url); boolean checkResult = permissionService.checkUrlAvailable(userInfo, url);
// if (!checkResult) { if (!checkResult) {
// throw new ServiceException(-1, "no permission"); throw new ServiceException(-1, "no permission");
// } }
} }
return joinPoint.proceed(); return joinPoint.proceed();
} }

View File

@@ -17,8 +17,8 @@
package org.apache.rocketmq.dashboard.permisssion; package org.apache.rocketmq.dashboard.permisssion;
public enum UserRoleEnum { public enum UserRoleEnum {
ADMIN(1, "admin"), SUPER(1, "Super"),
ORDINARY(0, "ordinary"); NORMAL(2, "Normal");
private int roleType; private int roleType;
private String roleName; private String roleName;

View File

@@ -54,5 +54,4 @@ public interface TopicService {
SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest); SendResult sendTopicMessageRequest(SendTopicMessageRequest sendTopicMessageRequest);
boolean refreshTopicList();
} }

View File

@@ -63,10 +63,12 @@ import org.apache.rocketmq.remoting.protocol.body.TopicConfigSerializeWrapper;
import org.apache.rocketmq.remoting.protocol.body.TopicList; import org.apache.rocketmq.remoting.protocol.body.TopicList;
import org.apache.rocketmq.remoting.protocol.body.UserInfo; import org.apache.rocketmq.remoting.protocol.body.UserInfo;
import org.apache.rocketmq.remoting.protocol.header.ExportRocksDBConfigToJsonRequestHeader; import org.apache.rocketmq.remoting.protocol.header.ExportRocksDBConfigToJsonRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.GetTopicConfigRequestHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader; import org.apache.rocketmq.remoting.protocol.header.controller.ElectMasterResponseHeader;
import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader; import org.apache.rocketmq.remoting.protocol.header.controller.GetMetaDataResponseHeader;
import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData; import org.apache.rocketmq.remoting.protocol.heartbeat.SubscriptionData;
import org.apache.rocketmq.remoting.protocol.route.TopicRouteData; import org.apache.rocketmq.remoting.protocol.route.TopicRouteData;
import org.apache.rocketmq.remoting.protocol.statictopic.TopicConfigAndQueueMapping;
import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingDetail; import org.apache.rocketmq.remoting.protocol.statictopic.TopicQueueMappingDetail;
import org.apache.rocketmq.remoting.protocol.subscription.GroupForbidden; import org.apache.rocketmq.remoting.protocol.subscription.GroupForbidden;
import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig; import org.apache.rocketmq.remoting.protocol.subscription.SubscriptionGroupConfig;
@@ -84,8 +86,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static org.apache.rocketmq.remoting.protocol.RemotingSerializable.decode; import static org.apache.rocketmq.remoting.protocol.RemotingSerializable.decode;
@@ -93,14 +93,9 @@ import static org.apache.rocketmq.remoting.protocol.RemotingSerializable.decode;
public class MQAdminExtImpl implements MQAdminExt { public class MQAdminExtImpl implements MQAdminExt {
private Logger logger = LoggerFactory.getLogger(MQAdminExtImpl.class); private Logger logger = LoggerFactory.getLogger(MQAdminExtImpl.class);
private static final ConcurrentMap<String, TopicConfigSerializeWrapper> TOPIC_CONFIG_CACHE = new ConcurrentHashMap<>();
public MQAdminExtImpl() {} public MQAdminExtImpl() {}
public static void clearTopicConfigCache() {
TOPIC_CONFIG_CACHE.clear();
}
@Override @Override
public void updateBrokerConfig(String brokerAddr, Properties properties) public void updateBrokerConfig(String brokerAddr, Properties properties)
@@ -157,15 +152,11 @@ public class MQAdminExtImpl implements MQAdminExt {
@Override @Override
public TopicConfig examineTopicConfig(String addr, String topic) throws MQBrokerException { public TopicConfig examineTopicConfig(String addr, String topic) throws MQBrokerException {
TopicConfigSerializeWrapper cachedWrapper = TOPIC_CONFIG_CACHE.get(addr);
if (cachedWrapper != null && cachedWrapper.getTopicConfigTable().containsKey(topic)) {
return cachedWrapper.getTopicConfigTable().get(topic);
}
RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient(); RemotingClient remotingClient = MQAdminInstance.threadLocalRemotingClient();
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_ALL_TOPIC_CONFIG, null); GetTopicConfigRequestHeader header = new GetTopicConfigRequestHeader();
RemotingCommand response = null; header.setTopic(topic);
RemotingCommand request = RemotingCommand.createRequestCommand(RequestCode.GET_TOPIC_CONFIG, header);
RemotingCommand response;
try { try {
response = remotingClient.invokeSync(addr, request, 3000); response = remotingClient.invokeSync(addr, request, 3000);
} catch (Exception err) { } catch (Exception err) {
@@ -174,11 +165,11 @@ public class MQAdminExtImpl implements MQAdminExt {
} }
switch (response.getCode()) { switch (response.getCode()) {
case ResponseCode.SUCCESS: { case ResponseCode.SUCCESS: {
TopicConfigSerializeWrapper topicConfigSerializeWrapper = TopicConfigAndQueueMapping topicConfigAndQueueMapping = decode(response.getBody(), TopicConfigAndQueueMapping.class);
decode(response.getBody(), TopicConfigSerializeWrapper.class); if (topicConfigAndQueueMapping == null) {
throw new MQBrokerException(ResponseCode.TOPIC_NOT_EXIST, "Topic not exist: " + topic);
TOPIC_CONFIG_CACHE.put(addr, topicConfigSerializeWrapper); }
return topicConfigSerializeWrapper.getTopicConfigTable().get(topic); return topicConfigAndQueueMapping;
} }
default: default:
throw new MQBrokerException(response.getCode(), response.getRemark()); throw new MQBrokerException(response.getCode(), response.getRemark());

View File

@@ -56,6 +56,7 @@ public class LoginServiceImpl implements LoginService {
if (username != null) { if (username != null) {
UserInfo userInfo = userInfoProvider.getUserInfoByUsername(username); UserInfo userInfo = userInfoProvider.getUserInfoByUsername(username);
if (userInfo == null) { if (userInfo == null) {
auth(request, response);
return false; return false;
} }
UserInfoContext.set(WebUtil.USER_NAME, userInfo); UserInfoContext.set(WebUtil.USER_NAME, userInfo);

View File

@@ -33,8 +33,9 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.ADMIN; import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.NORMAL;
import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.ORDINARY; import static org.apache.rocketmq.dashboard.permisssion.UserRoleEnum.SUPER;
@Service @Service
public class PermissionServiceImpl implements PermissionService, InitializingBean { public class PermissionServiceImpl implements PermissionService, InitializingBean {
@@ -55,10 +56,10 @@ public class PermissionServiceImpl implements PermissionService, InitializingBea
public boolean checkUrlAvailable(UserInfo userInfo, String url) { public boolean checkUrlAvailable(UserInfo userInfo, String url) {
int type = userInfo.getUser().getType(); int type = userInfo.getUser().getType();
// if it is admin, it could access all resources // if it is admin, it could access all resources
if (type == ADMIN.getRoleType()) { if (type == SUPER.getRoleType()) {
return true; return true;
} }
String loginUserRole = ORDINARY.getRoleName(); String loginUserRole = NORMAL.getRoleName();
Map<String, List<String>> rolePerms = PermissionFileStore.rolePerms; Map<String, List<String>> rolePerms = PermissionFileStore.rolePerms;
List<String> perms = rolePerms.get(loginUserRole); List<String> perms = rolePerms.get(loginUserRole);
for (String perm : perms) { for (String perm : perms) {

View File

@@ -45,7 +45,6 @@ import org.apache.rocketmq.dashboard.model.request.TopicTypeMeta;
import org.apache.rocketmq.dashboard.service.AbstractCommonService; import org.apache.rocketmq.dashboard.service.AbstractCommonService;
import org.apache.rocketmq.dashboard.service.ClusterInfoService; import org.apache.rocketmq.dashboard.service.ClusterInfoService;
import org.apache.rocketmq.dashboard.service.TopicService; import org.apache.rocketmq.dashboard.service.TopicService;
import org.apache.rocketmq.dashboard.service.client.MQAdminExtImpl;
import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler; import org.apache.rocketmq.dashboard.support.GlobalExceptionHandler;
import org.apache.rocketmq.remoting.RPCHook; import org.apache.rocketmq.remoting.RPCHook;
import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable; import org.apache.rocketmq.remoting.protocol.admin.TopicStatsTable;
@@ -71,7 +70,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -85,9 +83,6 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
@Autowired @Autowired
private ClusterInfoService clusterInfoService; private ClusterInfoService clusterInfoService;
private final ConcurrentMap<String, TopicRouteData> routeCache = new ConcurrentHashMap<>();
private final Object cacheLock = new Object();
private transient DefaultMQProducer systemTopicProducer; private transient DefaultMQProducer systemTopicProducer;
private final Object producerLock = new Object(); private final Object producerLock = new Object();
@@ -195,24 +190,11 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
@Override @Override
public TopicRouteData route(String topic) { public TopicRouteData route(String topic) {
TopicRouteData cachedData = routeCache.get(topic); try {
if (cachedData != null) { return mqAdminExt.examineTopicRouteInfo(topic);
return cachedData; } catch (Exception ex) {
} Throwables.throwIfUnchecked(ex);
throw new RuntimeException(ex);
synchronized (cacheLock) {
cachedData = routeCache.get(topic);
if (cachedData != null) {
return cachedData;
}
try {
TopicRouteData freshData = mqAdminExt.examineTopicRouteInfo(topic);
routeCache.put(topic, freshData);
return freshData;
} catch (Exception ex) {
Throwables.throwIfUnchecked(ex);
throw new RuntimeException(ex);
}
} }
} }
@@ -228,7 +210,6 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
@Override @Override
public void createOrUpdate(TopicConfigInfo topicCreateOrUpdateRequest) { public void createOrUpdate(TopicConfigInfo topicCreateOrUpdateRequest) {
MQAdminExtImpl.clearTopicConfigCache();
TopicConfig topicConfig = new TopicConfig(); TopicConfig topicConfig = new TopicConfig();
BeanUtils.copyProperties(topicCreateOrUpdateRequest, topicConfig); BeanUtils.copyProperties(topicCreateOrUpdateRequest, topicConfig);
String messageType = topicCreateOrUpdateRequest.getMessageType(); String messageType = topicCreateOrUpdateRequest.getMessageType();
@@ -455,13 +436,6 @@ public class TopicServiceImpl extends AbstractCommonService implements TopicServ
} }
@Override
public boolean refreshTopicList() {
routeCache.clear();
clusterInfoService.refresh();
MQAdminExtImpl.clearTopicConfigCache();
return true;
}
private void waitSendTraceFinish(DefaultMQProducer producer, boolean traceEnabled) { private void waitSendTraceFinish(DefaultMQProducer producer, boolean traceEnabled) {
if (!traceEnabled) { if (!traceEnabled) {

View File

@@ -24,13 +24,12 @@ import org.apache.rocketmq.dashboard.config.RMQConfigure;
import org.apache.rocketmq.dashboard.model.User; import org.apache.rocketmq.dashboard.model.User;
import org.apache.rocketmq.dashboard.service.UserService; import org.apache.rocketmq.dashboard.service.UserService;
import org.apache.rocketmq.dashboard.service.provider.UserInfoProvider; import org.apache.rocketmq.dashboard.service.provider.UserInfoProvider;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.protocol.body.UserInfo; import org.apache.rocketmq.remoting.protocol.body.UserInfo;
import org.apache.rocketmq.tools.admin.MQAdminExt; import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service @Service
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {

View File

@@ -17,15 +17,14 @@
package org.apache.rocketmq.dashboard.service.provider; package org.apache.rocketmq.dashboard.service.provider;
import org.apache.rocketmq.dashboard.service.ClusterInfoService; import org.apache.rocketmq.dashboard.service.ClusterInfoService;
import org.apache.rocketmq.logging.org.slf4j.Logger;
import org.apache.rocketmq.logging.org.slf4j.LoggerFactory;
import org.apache.rocketmq.remoting.protocol.body.ClusterInfo; import org.apache.rocketmq.remoting.protocol.body.ClusterInfo;
import org.apache.rocketmq.remoting.protocol.body.UserInfo; import org.apache.rocketmq.remoting.protocol.body.UserInfo;
import org.apache.rocketmq.remoting.protocol.route.BrokerData; import org.apache.rocketmq.remoting.protocol.route.BrokerData;
import org.apache.rocketmq.tools.admin.MQAdminExt; import org.apache.rocketmq.tools.admin.MQAdminExt;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Service @Service
public class UserInfoProviderImpl implements UserInfoProvider { public class UserInfoProviderImpl implements UserInfoProvider {

View File

@@ -22,12 +22,13 @@
# **: Matches 0 or more characters. # **: Matches 0 or more characters.
rolePerms: rolePerms:
ordinary: Normal:
- /rocketmq/*.query - /rocketmq/*.query
- /ops/*.query - /ops/*.query
- /dashboard/*.query - /dashboard/*.query
- /topic/*.query - /topic/*.query
- /topic/sendTopicMessage.do - /topic/sendTopicMessage.do
- /topic/list.queryTopicType
- /producer/*.query - /producer/*.query
- /message/*.query - /message/*.query
- /messageTrace/*.query - /messageTrace/*.query