This is an automated email from the ASF dual-hosted git repository. lizhimins pushed a commit to branch rocketmq-studio in repository https://gitbox.apache.org/repos/asf/rocketmq-dashboard.git
commit cc81e4feaba9f2df1640b3f9c3b831b7e8e48be4 Author: aias00 <[email protected]> AuthorDate: Thu Jul 23 22:51:25 2026 -0700 feat: add proxy address endpoints (#505) Add proxy address list and add-address endpoints supporting Studio frontend form submission. --- .../studio/cluster/proxy/ProxyAddressService.java | 58 +++++++++++++++++ .../cluster/proxy/ProxyCompatController.java | 46 ++++++++++++++ .../rocketmq/studio/cluster/proxy/ProxyHomeVO.java | 30 +++++++++ .../cluster/proxy/ProxyAddressServiceTest.java | 55 ++++++++++++++++ .../cluster/proxy/ProxyCompatControllerTest.java | 73 ++++++++++++++++++++++ 5 files changed, 262 insertions(+) diff --git a/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyAddressService.java b/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyAddressService.java new file mode 100644 index 00000000..d2e30a56 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyAddressService.java @@ -0,0 +1,58 @@ +/* + * 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 com.rocketmq.studio.cluster.proxy; + +import com.rocketmq.studio.common.exception.BusinessException; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +@Slf4j +@Service +public class ProxyAddressService { + + private final Set<String> proxyAddrs = new LinkedHashSet<>(List.of("127.0.0.1:8081")); + private String currentProxyAddr = "127.0.0.1:8081"; + + public synchronized ProxyHomeVO getHomePage() { + return ProxyHomeVO.builder() + .proxyAddrList(new ArrayList<>(proxyAddrs)) + .currentProxyAddr(currentProxyAddr) + .build(); + } + + public synchronized void addProxyAddr(String newProxyAddr) { + String normalized = normalizeProxyAddr(newProxyAddr); + proxyAddrs.add(normalized); + if (currentProxyAddr == null || currentProxyAddr.isBlank()) { + currentProxyAddr = normalized; + } + log.info("Added Proxy address {}", normalized); + } + + private String normalizeProxyAddr(String proxyAddr) { + if (proxyAddr == null || proxyAddr.trim().isEmpty()) { + throw new BusinessException(400, "newProxyAddr is required"); + } + return proxyAddr.trim(); + } +} diff --git a/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyCompatController.java b/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyCompatController.java new file mode 100644 index 00000000..48c15445 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyCompatController.java @@ -0,0 +1,46 @@ +/* + * 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 com.rocketmq.studio.cluster.proxy; + +import com.rocketmq.studio.common.domain.Result; +import lombok.RequiredArgsConstructor; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/proxy") +@RequiredArgsConstructor +public class ProxyCompatController { + + private final ProxyAddressService proxyAddressService; + + @GetMapping("/homePage.query") + public Result<ProxyHomeVO> homePage() { + return Result.ok(proxyAddressService.getHomePage()); + } + + @PostMapping(value = "/addProxyAddr.do", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + public Result<Void> addProxyAddr(@RequestParam String newProxyAddr) { + proxyAddressService.addProxyAddr(newProxyAddr); + return Result.ok(); + } +} diff --git a/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyHomeVO.java b/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyHomeVO.java new file mode 100644 index 00000000..426f65e1 --- /dev/null +++ b/server/src/main/java/com/rocketmq/studio/cluster/proxy/ProxyHomeVO.java @@ -0,0 +1,30 @@ +/* + * 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 com.rocketmq.studio.cluster.proxy; + +import lombok.Builder; +import lombok.Data; + +import java.util.List; + +@Data +@Builder +public class ProxyHomeVO { + private List<String> proxyAddrList; + private String currentProxyAddr; +} diff --git a/server/src/test/java/com/rocketmq/studio/cluster/proxy/ProxyAddressServiceTest.java b/server/src/test/java/com/rocketmq/studio/cluster/proxy/ProxyAddressServiceTest.java new file mode 100644 index 00000000..44b7e72e --- /dev/null +++ b/server/src/test/java/com/rocketmq/studio/cluster/proxy/ProxyAddressServiceTest.java @@ -0,0 +1,55 @@ +/* + * 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 com.rocketmq.studio.cluster.proxy; + +import com.rocketmq.studio.common.exception.BusinessException; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class ProxyAddressServiceTest { + + private final ProxyAddressService proxyAddressService = new ProxyAddressService(); + + @Test + void homePageShouldReturnDefaultProxyAddress() { + ProxyHomeVO home = proxyAddressService.getHomePage(); + + assertThat(home.getProxyAddrList()).containsExactly("127.0.0.1:8081"); + assertThat(home.getCurrentProxyAddr()).isEqualTo("127.0.0.1:8081"); + } + + @Test + void addProxyAddrShouldTrimAndKeepUniqueAddresses() { + proxyAddressService.addProxyAddr(" 10.0.0.1:8081 "); + proxyAddressService.addProxyAddr("10.0.0.1:8081"); + + ProxyHomeVO home = proxyAddressService.getHomePage(); + assertThat(home.getProxyAddrList()).containsExactly("127.0.0.1:8081", "10.0.0.1:8081"); + assertThat(home.getCurrentProxyAddr()).isEqualTo("127.0.0.1:8081"); + } + + @Test + void addProxyAddrShouldRejectBlankAddress() { + assertThatThrownBy(() -> proxyAddressService.addProxyAddr(" ")) + .isInstanceOf(BusinessException.class) + .hasMessage("newProxyAddr is required") + .satisfies(ex -> assertThat(((BusinessException) ex).getCode()).isEqualTo(400)); + } +} diff --git a/server/src/test/java/com/rocketmq/studio/cluster/proxy/ProxyCompatControllerTest.java b/server/src/test/java/com/rocketmq/studio/cluster/proxy/ProxyCompatControllerTest.java new file mode 100644 index 00000000..1268fbb9 --- /dev/null +++ b/server/src/test/java/com/rocketmq/studio/cluster/proxy/ProxyCompatControllerTest.java @@ -0,0 +1,73 @@ +/* + * 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 com.rocketmq.studio.cluster.proxy; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(ProxyCompatController.class) +@AutoConfigureMockMvc(addFilters = false) +class ProxyCompatControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private ProxyAddressService proxyAddressService; + + @Test + void homePageShouldReturnProxyAddressState() throws Exception { + ProxyHomeVO home = ProxyHomeVO.builder() + .proxyAddrList(List.of("127.0.0.1:8081", "10.0.0.1:8081")) + .currentProxyAddr("127.0.0.1:8081") + .build(); + when(proxyAddressService.getHomePage()).thenReturn(home); + + mockMvc.perform(get("/api/proxy/homePage.query")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)) + .andExpect(jsonPath("$.data.proxyAddrList[0]").value("127.0.0.1:8081")) + .andExpect(jsonPath("$.data.currentProxyAddr").value("127.0.0.1:8081")); + } + + @Test + void addProxyAddrShouldAcceptFormEncodedPayload() throws Exception { + mockMvc.perform(post("/api/proxy/addProxyAddr.do") + .contentType(MediaType.APPLICATION_FORM_URLENCODED) + .param("newProxyAddr", "10.0.0.1:8081")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value(200)); + + verify(proxyAddressService).addProxyAddr(eq("10.0.0.1:8081")); + } +}
