diff --git a/CHANGES.md b/CHANGES.md index 8dc0dea8d05..c584794bdc7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -16,6 +16,12 @@ Apollo 2.4.0 * [Feature: Add ConfigService cache record stats function](https://github.com/apolloconfig/apollo/pull/5247) * [RefreshAdminServerAddressTask supports dynamic configuration of time interval](https://github.com/apolloconfig/apollo/pull/5248) * [Refactor: Configuration files uniformly use Kebab style](https://github.com/apolloconfig/apollo/pull/5262) +* [Feature: openapi query namespace support not fill item](https://github.com/apolloconfig/apollo/pull/5249) +* [Refactor: align database ClusterName and NamespaceName fields lengths](https://github.com/apolloconfig/apollo/pull/5263) +* [Feature: Added the value length limit function for AppId-level configuration items](https://github.com/apolloconfig/apollo/pull/5264) +* [Fix: ensure clusters order in envClusters open api](https://github.com/apolloconfig/apollo/pull/5277) +* [Fix: bump xstream from 1.4.20 to 1.4.21 to fix CVE-2024-47072](https://github.com/apolloconfig/apollo/pull/5280) +* [Feature: highlight diffs for properties](https://github.com/apolloconfig/apollo/pull/5282) ------------------ All issues and pull requests are [here](https://github.com/apolloconfig/apollo/milestone/15?closed=1) diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java index f2b6dc9fc98..0746a7be45b 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/config/BizConfig.java @@ -30,12 +30,16 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; +import java.util.function.Predicate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class BizConfig extends RefreshableConfig { + private final static Logger logger = LoggerFactory.getLogger(BizConfig.class); + private static final int DEFAULT_ITEM_KEY_LENGTH = 128; private static final int DEFAULT_ITEM_VALUE_LENGTH = 20000; @@ -58,6 +62,9 @@ public class BizConfig extends RefreshableConfig { private static final Gson GSON = new Gson(); + private static final Type appIdValueLengthOverrideTypeReference = + new TypeToken>() { + }.getType(); private static final Type namespaceValueLengthOverrideTypeReference = new TypeToken>() { }.getType(); @@ -106,6 +113,16 @@ public int itemValueLengthLimit() { return checkInt(limit, 5, Integer.MAX_VALUE, DEFAULT_ITEM_VALUE_LENGTH); } + public Map appIdValueLengthLimitOverride() { + String appIdValueLengthOverrideString = getValue("appid.value.length.limit.override"); + return parseOverrideConfig(appIdValueLengthOverrideString, appIdValueLengthOverrideTypeReference, value -> value > 0); + } + + public Map namespaceValueLengthLimitOverride() { + String namespaceValueLengthOverrideString = getValue("namespace.value.length.limit.override"); + return parseOverrideConfig(namespaceValueLengthOverrideString, namespaceValueLengthOverrideTypeReference, value -> value > 0); + } + public boolean isNamespaceNumLimitEnabled() { return getBooleanProperty("namespace.num.limit.enabled", false); } @@ -128,17 +145,6 @@ public int itemNumLimit() { return checkInt(limit, 5, Integer.MAX_VALUE, DEFAULT_MAX_ITEM_NUM); } - public Map namespaceValueLengthLimitOverride() { - String namespaceValueLengthOverrideString = getValue("namespace.value.length.limit.override"); - Map namespaceValueLengthOverride = Maps.newHashMap(); - if (!Strings.isNullOrEmpty(namespaceValueLengthOverrideString)) { - namespaceValueLengthOverride = - GSON.fromJson(namespaceValueLengthOverrideString, namespaceValueLengthOverrideTypeReference); - } - - return namespaceValueLengthOverride; - } - public boolean isNamespaceLockSwitchOff() { return !getBooleanProperty("namespace.lock.switch", false); } @@ -195,15 +201,7 @@ public int releaseHistoryRetentionSize() { public Map releaseHistoryRetentionSizeOverride() { String overrideString = getValue("apollo.release-history.retention.size.override"); - Map releaseHistoryRetentionSizeOverride = Maps.newHashMap(); - if (!Strings.isNullOrEmpty(overrideString)) { - releaseHistoryRetentionSizeOverride = - GSON.fromJson(overrideString, releaseHistoryRetentionSizeOverrideTypeReference); - } - return releaseHistoryRetentionSizeOverride.entrySet() - .stream() - .filter(entry -> entry.getValue() >= 1) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + return parseOverrideConfig(overrideString, releaseHistoryRetentionSizeOverrideTypeReference, value -> value > 0); } public int releaseMessageCacheScanInterval() { @@ -261,4 +259,22 @@ public boolean isAdminServiceAccessControlEnabled() { public String getAdminServiceAccessTokens() { return getValue("admin-service.access.tokens"); } + + private Map parseOverrideConfig(String configValue, Type typeReference, Predicate valueFilter) { + Map result = Maps.newHashMap(); + if (!Strings.isNullOrEmpty(configValue)) { + try { + Map parsed = GSON.fromJson(configValue, typeReference); + for (Map.Entry entry : parsed.entrySet()) { + if (entry.getValue() != null && valueFilter.test(entry.getValue())) { + result.put(entry.getKey(), entry.getValue()); + } + } + } catch (Exception e) { + logger.error("Invalid override config value: {}", configValue, e); + } + } + return Collections.unmodifiableMap(result); + } + } diff --git a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ItemService.java b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ItemService.java index 0fd9199ab65..975b9814fbe 100644 --- a/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ItemService.java +++ b/apollo-biz/src/main/java/com/ctrip/framework/apollo/biz/service/ItemService.java @@ -217,8 +217,8 @@ public Item update(Item item) { } private boolean checkItemValueLength(long namespaceId, String value) { - int limit = getItemValueLengthLimit(namespaceId); Namespace currentNamespace = namespaceService.findOne(namespaceId); + int limit = getItemValueLengthLimit(currentNamespace); if(currentNamespace != null) { Matcher m = clusterPattern.matcher(currentNamespace.getClusterName()); boolean isGray = m.matches(); @@ -235,7 +235,7 @@ private boolean checkItemValueLength(long namespaceId, String value) { private int getGrayNamespaceItemValueLengthLimit(Namespace grayNamespace, int grayNamespaceLimit) { Namespace parentNamespace = namespaceService.findParentNamespace(grayNamespace); if (parentNamespace != null) { - int parentLimit = getItemValueLengthLimit(parentNamespace.getId()); + int parentLimit = getItemValueLengthLimit(grayNamespace); if (parentLimit > grayNamespaceLimit) { return parentLimit; } @@ -257,11 +257,17 @@ private boolean checkItemType(int type) { return true; } - private int getItemValueLengthLimit(long namespaceId) { + private int getItemValueLengthLimit(Namespace namespace) { Map namespaceValueLengthOverride = bizConfig.namespaceValueLengthLimitOverride(); - if (namespaceValueLengthOverride != null && namespaceValueLengthOverride.containsKey(namespaceId)) { - return namespaceValueLengthOverride.get(namespaceId); + if (namespaceValueLengthOverride != null && namespaceValueLengthOverride.containsKey(namespace.getId())) { + return namespaceValueLengthOverride.get(namespace.getId()); } + + Map appIdValueLengthOverride = bizConfig.appIdValueLengthLimitOverride(); + if (appIdValueLengthOverride != null && appIdValueLengthOverride.containsKey(namespace.getAppId())) { + return appIdValueLengthOverride.get(namespace.getAppId()); + } + return bizConfig.itemValueLengthLimit(); } diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java index 7c7b1ea484a..c6420f187f5 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/config/BizConfigTest.java @@ -18,13 +18,13 @@ import com.ctrip.framework.apollo.biz.repository.ServerConfigRepository; import com.ctrip.framework.apollo.biz.service.BizDBPropertySource; +import java.util.Map; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.core.env.ConfigurableEnvironment; -import org.springframework.core.env.Environment; import org.springframework.test.util.ReflectionTestUtils; import javax.sql.DataSource; @@ -93,7 +93,7 @@ public void testReleaseHistoryRetentionSizeOverride() { int someOverrideLimit = 10; String overrideValueString = "{'a+b+c+b':10}"; when(environment.getProperty("apollo.release-history.retention.size.override")).thenReturn(overrideValueString); - int overrideValue = bizConfig.releaseHistoryRetentionSizeOverride().get("a+b+c+b"); + int overrideValue = bizConfig.releaseHistoryRetentionSizeOverride().get("a+b+c+b"); assertEquals(someOverrideLimit, overrideValue); overrideValueString = "{'a+b+c+b':0,'a+b+d+b':2}"; @@ -107,6 +107,48 @@ public void testReleaseHistoryRetentionSizeOverride() { assertEquals(0, bizConfig.releaseHistoryRetentionSizeOverride().size()); } + @Test + public void testAppIdValueLengthLimitOverride() { + when(environment.getProperty("appid.value.length.limit.override")).thenReturn(null); + Map result = bizConfig.appIdValueLengthLimitOverride(); + assertTrue(result.isEmpty()); + + String input = "{}"; + when(environment.getProperty("appid.value.length.limit.override")).thenReturn(input); + result = bizConfig.appIdValueLengthLimitOverride(); + assertTrue(result.isEmpty()); + + input = "invalid json"; + when(environment.getProperty("appid.value.length.limit.override")).thenReturn(input); + result = bizConfig.appIdValueLengthLimitOverride(); + assertTrue(result.isEmpty()); + + input = "{'appid1':555}"; + when(environment.getProperty("appid.value.length.limit.override")).thenReturn(input); + int overrideValue = bizConfig.appIdValueLengthLimitOverride().get("appid1"); + assertEquals(1, bizConfig.appIdValueLengthLimitOverride().size()); + assertEquals(555, overrideValue); + + input = "{'appid1':555,'appid2':666}"; + when(environment.getProperty("appid.value.length.limit.override")).thenReturn(input); + overrideValue = bizConfig.appIdValueLengthLimitOverride().get("appid2"); + assertEquals(2, bizConfig.appIdValueLengthLimitOverride().size()); + assertEquals(666, overrideValue); + + input = "{'appid1':555,'appid2':666,'appid3':0,'appid4':-1}"; + when(environment.getProperty("appid.value.length.limit.override")).thenReturn(input); + result = bizConfig.appIdValueLengthLimitOverride(); + + assertTrue(result.containsKey("appid1")); + assertTrue(result.containsKey("appid2")); + assertFalse(result.containsKey("appid3")); + assertFalse(result.containsKey("appid4")); + assertEquals(2, result.size()); + + overrideValue = result.get("appid2"); + assertEquals(666, overrideValue); + } + @Test public void testReleaseMessageNotificationBatchWithNAN() throws Exception { String someNAN = "someNAN"; diff --git a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/service/ItemServiceTest.java b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/service/ItemServiceTest.java index 6d8003f1d58..efc4f477bdd 100644 --- a/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/service/ItemServiceTest.java +++ b/apollo-biz/src/test/java/com/ctrip/framework/apollo/biz/service/ItemServiceTest.java @@ -16,12 +16,20 @@ */ package com.ctrip.framework.apollo.biz.service; +import static org.mockito.Mockito.when; + import com.ctrip.framework.apollo.biz.AbstractIntegrationTest; +import com.ctrip.framework.apollo.biz.config.BizConfig; import com.ctrip.framework.apollo.biz.entity.Item; +import com.ctrip.framework.apollo.biz.repository.ItemRepository; import com.ctrip.framework.apollo.common.dto.ItemInfoDTO; import com.ctrip.framework.apollo.common.exception.BadRequestException; +import java.util.HashMap; +import java.util.Map; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import org.mockito.Mock; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -32,18 +40,28 @@ public class ItemServiceTest extends AbstractIntegrationTest { @Autowired private ItemService itemService; + @Autowired + private ItemRepository itemRepository; + @Autowired + private NamespaceService namespaceService; + @Autowired + private AuditService auditService; + + @Mock + private BizConfig bizConfig; + + private ItemService itemService2; + + @Before + public void setUp() throws Exception { + itemService2 = new ItemService(itemRepository, namespaceService, auditService, bizConfig); + } + @Test - @Sql(scripts = "/sql/item-test.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = {"/sql/namespace-test.sql","/sql/item-test.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testSaveItem() { - Item item = new Item(); - item.setNamespaceId(3); - item.setKey("k3"); - item.setType(-1); - item.setValue("v3"); - item.setComment(""); - item.setLineNum(3); - + Item item = createItem(1L, "k3", "v3", -1); try { itemService.save(item); Assert.fail(); @@ -57,16 +75,56 @@ public void testSaveItem() { } @Test - @Sql(scripts = "/sql/item-test.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = {"/sql/namespace-test.sql", "/sql/item-test.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + public void testSaveItemWithNamespaceValueLengthLimitOverride() { + + long namespaceId = 1L; + String itemValue = "test-demo"; + + Map namespaceValueLengthOverride = new HashMap<>(); + namespaceValueLengthOverride.put(namespaceId, itemValue.length() - 1); + when(bizConfig.namespaceValueLengthLimitOverride()).thenReturn(namespaceValueLengthOverride); + when(bizConfig.itemKeyLengthLimit()).thenReturn(100); + + Item item = createItem(namespaceId, "k3", itemValue, 2); + try { + itemService2.save(item); + Assert.fail(); + } catch (Exception e) { + Assert.assertTrue(e instanceof BadRequestException && e.getMessage().contains("value too long")); + } + } + + @Test + @Sql(scripts = {"/sql/namespace-test.sql", "/sql/item-test.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + @Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) + public void testSaveItemWithAppIdValueLengthLimitOverride() { + + String appId = "testApp"; + long namespaceId = 1L; + String itemValue = "test-demo"; + + Map appIdValueLengthOverride = new HashMap<>(); + appIdValueLengthOverride.put(appId, itemValue.length() - 1); + when(bizConfig.appIdValueLengthLimitOverride()).thenReturn(appIdValueLengthOverride); + when(bizConfig.itemKeyLengthLimit()).thenReturn(100); + + Item item = createItem(namespaceId, "k3", itemValue, 2); + try { + itemService2.save(item); + Assert.fail(); + } catch (Exception e) { + Assert.assertTrue(e instanceof BadRequestException && e.getMessage().contains("value too long")); + } + } + + @Test + @Sql(scripts = {"/sql/namespace-test.sql","/sql/item-test.sql"}, executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) @Sql(scripts = "/sql/clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD) public void testUpdateItem() { - Item item = new Item(); + Item item = createItem(1, "k1", "v1-new", 2); item.setId(9901); - item.setNamespaceId(1); - item.setKey("k1"); - item.setType(2); - item.setValue("v1-new"); - item.setComment(""); item.setLineNum(1); Item dbItem = itemService.update(item); @@ -96,4 +154,15 @@ public void testSearchItem() { } + private Item createItem(long namespaceId, String key, String value, int type) { + Item item = new Item(); + item.setNamespaceId(namespaceId); + item.setKey(key); + item.setValue(value); + item.setType(type); + item.setComment(""); + item.setLineNum(3); + return item; + } + } diff --git a/apollo-common/pom.xml b/apollo-common/pom.xml index 6fed9bf01ca..b061f7e002d 100644 --- a/apollo-common/pom.xml +++ b/apollo-common/pom.xml @@ -94,7 +94,7 @@ commons-lang3 - + io.micrometer micrometer-core diff --git a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java index ef636615b6b..160066b41aa 100644 --- a/apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java +++ b/apollo-common/src/main/java/com/ctrip/framework/apollo/common/utils/BeanUtils.java @@ -28,6 +28,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -164,7 +165,7 @@ public static Map> aggByKeyToList(String key, List list) { */ @SuppressWarnings("unchecked") public static Set toPropertySet(String key, List list) { - Set set = new HashSet<>(); + Set set = new LinkedHashSet<>(); if (CollectionUtils.isEmpty(list)) {// 防止外面传入空list return set; } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/PortalOpenApiConfig.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/PortalOpenApiConfig.java index ece1147e44f..f39893c23ea 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/PortalOpenApiConfig.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/PortalOpenApiConfig.java @@ -34,11 +34,11 @@ static class PortalWebMvcConfig extends WebMvcConfig { @Override public void customize(TomcatServletWebServerFactory factory) { final String relaxedChars = "<>[\\]^`{|}"; - final String tomcatRelaxedpathcharsProperty = "relaxedPathChars"; - final String tomcatRelaxedquerycharsProperty = "relaxedQueryChars"; + final String tomcatRelaxedPathCharsProperty = "relaxedPathChars"; + final String tomcatRelaxedQueryCharsProperty = "relaxedQueryChars"; factory.addConnectorCustomizers(connector -> { - connector.setProperty(tomcatRelaxedpathcharsProperty, relaxedChars); - connector.setProperty(tomcatRelaxedquerycharsProperty, relaxedChars); + connector.setProperty(tomcatRelaxedPathCharsProperty, relaxedChars); + connector.setProperty(tomcatRelaxedQueryCharsProperty, relaxedChars); }); } } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/server/service/ServerNamespaceOpenApiService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/server/service/ServerNamespaceOpenApiService.java index cc2cf13f829..5ae1ebbdf6f 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/server/service/ServerNamespaceOpenApiService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/server/service/ServerNamespaceOpenApiService.java @@ -58,9 +58,9 @@ public ServerNamespaceOpenApiService( @Override public OpenNamespaceDTO getNamespace(String appId, String env, String clusterName, - String namespaceName) { + String namespaceName, boolean fillItemDetail) { NamespaceBO namespaceBO = namespaceService.loadNamespaceBO(appId, Env.valueOf - (env), clusterName, namespaceName, false); + (env), clusterName, namespaceName, fillItemDetail, false); if (namespaceBO == null) { return null; } @@ -68,10 +68,10 @@ public OpenNamespaceDTO getNamespace(String appId, String env, String clusterNam } @Override - public List getNamespaces(String appId, String env, String clusterName) { + public List getNamespaces(String appId, String env, String clusterName, boolean fillItemDetail) { return OpenApiBeanUtils .batchTransformFromNamespaceBOs(namespaceService.findNamespaceBOs(appId, Env - .valueOf(env), clusterName, false)); + .valueOf(env), clusterName, fillItemDetail, false)); } @Override diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/NamespaceController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/NamespaceController.java index bbe3ba8e422..a3cf2ce5054 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/NamespaceController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/openapi/v1/controller/NamespaceController.java @@ -30,6 +30,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletRequest; @@ -81,21 +82,22 @@ public OpenAppNamespaceDTO createNamespace(@PathVariable String appId, @GetMapping(value = "/openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces") public List findNamespaces(@PathVariable String appId, @PathVariable String env, - @PathVariable String clusterName) { - return this.namespaceOpenApiService.getNamespaces(appId, env, clusterName); + @PathVariable String clusterName, + @RequestParam(defaultValue = "true") boolean fillItemDetail) { + return this.namespaceOpenApiService.getNamespaces(appId, env, clusterName, fillItemDetail); } @GetMapping(value = "/openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName:.+}") public OpenNamespaceDTO loadNamespace(@PathVariable String appId, @PathVariable String env, - @PathVariable String clusterName, @PathVariable String - namespaceName) { - return this.namespaceOpenApiService.getNamespace(appId, env, clusterName, namespaceName); + @PathVariable String clusterName, @PathVariable String namespaceName, + @RequestParam(defaultValue = "true") boolean fillItemDetail) { + return this.namespaceOpenApiService.getNamespace(appId, env, clusterName, namespaceName, fillItemDetail); } @GetMapping(value = "/openapi/v1/envs/{env}/apps/{appId}/clusters/{clusterName}/namespaces/{namespaceName}/lock") public OpenNamespaceLockDTO getNamespaceLock(@PathVariable String appId, @PathVariable String env, @PathVariable String clusterName, @PathVariable - String namespaceName) { + String namespaceName) { return this.namespaceOpenApiService.getNamespaceLock(appId, env, clusterName, namespaceName); } diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConfigsExportController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConfigsExportController.java index 1d3c7d79c2d..fc6ae086f4d 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConfigsExportController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ConfigsExportController.java @@ -93,7 +93,7 @@ public void exportItems(@PathVariable String appId, @PathVariable String env, } NamespaceBO namespaceBO = namespaceService.loadNamespaceBO(appId, Env.valueOf - (env), clusterName, namespaceName, false); + (env), clusterName, namespaceName, true, false); //generate a file. res.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + fileName); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsExportService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsExportService.java index aa524105169..1dc32fd4586 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsExportService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/ConfigsExportService.java @@ -235,7 +235,7 @@ private void exportNamespaces(final Env env, final App exportApp, final ClusterD ZipOutputStream zipOutputStream) { String clusterName = exportCluster.getName(); - List namespaceBOS = namespaceService.findNamespaceBOs(exportApp.getAppId(), env, clusterName, false); + List namespaceBOS = namespaceService.findNamespaceBOs(exportApp.getAppId(), env, clusterName, true, false); if (CollectionUtils.isEmpty(namespaceBOS)) { return; diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java index 183a58b891e..3d3e56c0a3a 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/NamespaceService.java @@ -186,7 +186,7 @@ public NamespaceDTO loadNamespaceBaseInfo(String appId, Env env, String clusterN /** * load cluster all namespace info with items */ - public List findNamespaceBOs(String appId, Env env, String clusterName, boolean includeDeletedItems) { + public List findNamespaceBOs(String appId, Env env, String clusterName, boolean fillItemDetail, boolean includeDeletedItems) { List namespaces = namespaceAPI.findNamespaceByCluster(appId, env, clusterName); if (namespaces == null || namespaces.size() == 0) { @@ -200,7 +200,7 @@ public List findNamespaceBOs(String appId, Env env, String clusterN executorService.submit(() -> { NamespaceBO namespaceBO; try { - namespaceBO = transformNamespace2BO(env, namespace, includeDeletedItems); + namespaceBO = transformNamespace2BO(env, namespace, fillItemDetail, includeDeletedItems); namespaceBOs.add(namespaceBO); } catch (Exception e) { LOGGER.error("parse namespace error. app id:{}, env:{}, clusterName:{}, namespace:{}", @@ -229,7 +229,7 @@ public List findNamespaceBOs(String appId, Env env, String clusterN } public List findNamespaceBOs(String appId, Env env, String clusterName) { - return findNamespaceBOs(appId, env, clusterName, true); + return findNamespaceBOs(appId, env, clusterName, true, true); } public List findNamespaces(String appId, Env env, String clusterName) { @@ -250,17 +250,17 @@ public List getPublicAppNamespaceAllNamespaces(Env env, String pub } public NamespaceBO loadNamespaceBO(String appId, Env env, String clusterName, - String namespaceName, boolean includeDeletedItems) { + String namespaceName, boolean fillItemDetail, boolean includeDeletedItems) { NamespaceDTO namespace = namespaceAPI.loadNamespace(appId, env, clusterName, namespaceName); if (namespace == null) { throw BadRequestException.namespaceNotExists(appId, clusterName, namespaceName); } - return transformNamespace2BO(env, namespace, includeDeletedItems); + return transformNamespace2BO(env, namespace, fillItemDetail, includeDeletedItems); } public NamespaceBO loadNamespaceBO(String appId, Env env, String clusterName, String namespaceName) { - return loadNamespaceBO(appId, env, clusterName, namespaceName, true); + return loadNamespaceBO(appId, env, clusterName, namespaceName, true, true); } public boolean publicAppNamespaceHasAssociatedNamespace(String publicNamespaceName, Env env) { @@ -293,7 +293,7 @@ public Map> getNamespacesPublishInfo(String appId) return result; } - private NamespaceBO transformNamespace2BO(Env env, NamespaceDTO namespace, boolean includeDeletedItems) { + private NamespaceBO transformNamespace2BO(Env env, NamespaceDTO namespace, boolean fillItemDetail, boolean includeDeletedItems) { NamespaceBO namespaceBO = new NamespaceBO(); namespaceBO.setBaseInfo(namespace); @@ -306,6 +306,10 @@ private NamespaceBO transformNamespace2BO(Env env, NamespaceDTO namespace, boole List itemBOs = new LinkedList<>(); namespaceBO.setItems(itemBOs); + if (!fillItemDetail) { + return namespaceBO; + } + //latest Release ReleaseDTO latestRelease; Map releaseItems = new HashMap<>(); @@ -347,7 +351,7 @@ private NamespaceBO transformNamespace2BO(Env env, NamespaceDTO namespace, boole } private NamespaceBO transformNamespace2BO(Env env, NamespaceDTO namespace) { - return transformNamespace2BO(env, namespace, true); + return transformNamespace2BO(env, namespace, true, true); } private void fillAppNamespaceProperties(NamespaceBO namespace) { diff --git a/apollo-portal/src/main/resources/static/config/diff.html b/apollo-portal/src/main/resources/static/config/diff.html index bbfc3098ee5..08ecbacea9d 100644 --- a/apollo-portal/src/main/resources/static/config/diff.html +++ b/apollo-portal/src/main/resources/static/config/diff.html @@ -127,31 +127,38 @@