diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java index a86e09d086d8ac7ae05d0fda95a4b0da9730b739..ddab546fc25ad4bb267278931d8724f3039d10a9 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceController.java @@ -161,16 +161,18 @@ public class NamespaceController { @PreAuthorize(value = "@permissionValidator.hasCreateAppNamespacePermission(#appId, #appNamespace)") @RequestMapping(value = "/apps/{appId}/appnamespaces", method = RequestMethod.POST) - public AppNamespace createAppNamespace(@PathVariable String appId, @RequestBody AppNamespace appNamespace) { + public AppNamespace createAppNamespace(@PathVariable String appId, + @RequestParam(defaultValue = "true") boolean appendNamespacePrefix, + @RequestBody AppNamespace appNamespace) { RequestPrecondition.checkArgumentsNotEmpty(appNamespace.getAppId(), appNamespace.getName()); if (!InputValidator.isValidAppNamespace(appNamespace.getName())) { throw new BadRequestException(String.format("Namespace格式错误: %s", - InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " - + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE)); + InputValidator.INVALID_CLUSTER_NAMESPACE_MESSAGE + " & " + + InputValidator.INVALID_NAMESPACE_NAMESPACE_MESSAGE)); } - AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace); + AppNamespace createdAppNamespace = appNamespaceService.createAppNamespaceInLocal(appNamespace, appendNamespacePrefix); if (portalConfig.canAppAdminCreatePrivateNamespace() || createdAppNamespace.isPublic()) { assignNamespaceRoleToOperator(appId, appNamespace.getName()); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/AppNamespaceRepository.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/AppNamespaceRepository.java index fa7c58b959c808e4f120a309761991d1b9365577..9e3b2966ebe86901c7177621e21f1dc5a96ba532 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/AppNamespaceRepository.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/repository/AppNamespaceRepository.java @@ -12,7 +12,7 @@ public interface AppNamespaceRepository extends PagingAndSortingRepository findByNameAndIsPublic(String namespaceName, boolean isPublic); List findByIsPublicTrue(); diff --git a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AppNamespaceService.java b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AppNamespaceService.java index d36b405279ab1c859c8df803c13f4f7c38bc58f7..b9cae5b4fd6db1d7575a0467c1105085a6b477d4 100644 --- a/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AppNamespaceService.java +++ b/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/service/AppNamespaceService.java @@ -9,16 +9,23 @@ import com.ctrip.framework.apollo.core.utils.StringUtils; import com.ctrip.framework.apollo.portal.repository.AppNamespaceRepository; import com.ctrip.framework.apollo.portal.spi.UserInfoHolder; +import com.google.common.base.Joiner; +import com.google.common.collect.Sets; +import java.util.Set; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.Objects; +import org.springframework.util.CollectionUtils; @Service public class AppNamespaceService { + private static final int PRIVATE_APP_NAMESPACE_NOTIFICATION_COUNT = 5; + private static final Joiner APP_NAMESPACE_JOINER = Joiner.on(",").skipNulls(); + @Autowired private UserInfoHolder userInfoHolder; @Autowired @@ -38,7 +45,17 @@ public class AppNamespaceService { } public AppNamespace findPublicAppNamespace(String namespaceName) { - return appNamespaceRepository.findByNameAndIsPublic(namespaceName, true); + List appNamespaces = appNamespaceRepository.findByNameAndIsPublic(namespaceName, true); + + if (CollectionUtils.isEmpty(appNamespaces)) { + return null; + } + + return appNamespaces.get(0); + } + + private List findAllPrivateAppNamespaces(String namespaceName) { + return appNamespaceRepository.findByNameAndIsPublic(namespaceName, false); } public AppNamespace findByAppIdAndName(String appId, String namespaceName) { @@ -69,8 +86,12 @@ public class AppNamespaceService { return Objects.isNull(appNamespaceRepository.findByAppIdAndName(appId, namespaceName)); } - @Transactional public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace) { + return createAppNamespaceInLocal(appNamespace, true); + } + + @Transactional + public AppNamespace createAppNamespaceInLocal(AppNamespace appNamespace, boolean appendNamespacePrefix) { String appId = appNamespace.getAppId(); //add app org id as prefix @@ -82,7 +103,7 @@ public class AppNamespaceService { StringBuilder appNamespaceName = new StringBuilder(); //add prefix postfix appNamespaceName - .append(appNamespace.isPublic() ? app.getOrgId() + "." : "") + .append(appNamespace.isPublic() && appendNamespacePrefix ? app.getOrgId() + "." : "") .append(appNamespace.getName()) .append(appNamespace.formatAsEnum() == ConfigFileFormat.Properties ? "" : "." + appNamespace.getFormat()); appNamespace.setName(appNamespaceName.toString()); @@ -103,12 +124,9 @@ public class AppNamespaceService { appNamespace.setDataChangeLastModifiedBy(operator); - // unique check + // globally uniqueness check if (appNamespace.isPublic()) { - AppNamespace publicAppNamespace = findPublicAppNamespace(appNamespace.getName()); - if (publicAppNamespace != null) { - throw new BadRequestException("Public AppNamespace " + appNamespace.getName() + " already exists in appId: " + publicAppNamespace.getAppId() + "!"); - } + checkAppNamespaceGlobalUniqueness(appNamespace); } if (!appNamespace.isPublic() && @@ -124,6 +142,30 @@ public class AppNamespaceService { return createdAppNamespace; } + private void checkAppNamespaceGlobalUniqueness(AppNamespace appNamespace) { + AppNamespace publicAppNamespace = findPublicAppNamespace(appNamespace.getName()); + if (publicAppNamespace != null) { + throw new BadRequestException("Public AppNamespace " + appNamespace.getName() + " already exists in appId: " + publicAppNamespace.getAppId() + "!"); + } + + List privateAppNamespaces = findAllPrivateAppNamespaces(appNamespace.getName()); + + if (!CollectionUtils.isEmpty(privateAppNamespaces)) { + Set appIds = Sets.newHashSet(); + for (AppNamespace ans : privateAppNamespaces) { + appIds.add(ans.getAppId()); + if (appIds.size() == PRIVATE_APP_NAMESPACE_NOTIFICATION_COUNT) { + break; + } + } + + throw new BadRequestException( + "Public AppNamespace " + appNamespace.getName() + " already exists as private AppNamespace in appId: " + + APP_NAMESPACE_JOINER.join(appIds) + ", etc. Please select another name!"); + } + } + + @Transactional public AppNamespace deleteAppNamespace(String appId, String namespaceName) { AppNamespace appNamespace = appNamespaceRepository.findByAppIdAndName(appId, namespaceName); diff --git a/apollo-portal/src/main/resources/static/namespace.html b/apollo-portal/src/main/resources/static/namespace.html index 4e6c3275e89b2dff1da7e4d4644f730ba2b007f5..fbdf2ce13bf485bd588afa082cb2b39f05f182d8 100644 --- a/apollo-portal/src/main/resources/static/namespace.html +++ b/apollo-portal/src/main/resources/static/namespace.html @@ -95,9 +95,9 @@ -
-
- +
+ @@ -116,9 +116,25 @@
   -
+ +
+ +
+
+ +
+ (公共Namespace的名称需要全局唯一,添加部门前缀有助于保证全局唯一性) +
+
+