diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissionDefinitionProvider.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissionDefinitionProvider.cs index e9e5ba4d9..878780cf1 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissionDefinitionProvider.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissionDefinitionProvider.cs @@ -45,6 +45,7 @@ namespace LINGYUN.ApiGateway aggregateRoute.AddChild(ApiGatewayPermissions.AggregateRoute.Export, L("Permissions:Export"), MultiTenancySides.Host); aggregateRoute.AddChild(ApiGatewayPermissions.AggregateRoute.Import, L("Permissions:Import"), MultiTenancySides.Host); aggregateRoute.AddChild(ApiGatewayPermissions.AggregateRoute.Delete, L("Permissions:Delete"), MultiTenancySides.Host); + aggregateRoute.AddChild(ApiGatewayPermissions.AggregateRoute.ManageRouteConfig, L("Permissions:ManageRouteConfig"), MultiTenancySides.Host); } protected virtual LocalizableString L(string name) diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissions.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissions.cs index ca9e091f5..7289b771f 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissions.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/ApiGatewayPermissions.cs @@ -51,6 +51,7 @@ public const string Delete = Default + ".Delete"; public const string Export = Default + ".Export"; public const string Import = Default + ".Import"; + public const string ManageRouteConfig = Default + ".ManageRouteConfig"; } } } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/en.json b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/en.json index 5c7fbad97..3f738e9c2 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/en.json +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/en.json @@ -7,9 +7,11 @@ "Permissions:Route": "Route", "Permissions:DynamicRoute": "Dynamic", "Permissions:AggregateRoute": "Aggregate", + "Permissions:ManageRouteConfig": "Route config", "Permissions:Update": "Update", "Permissions:Export": "Export", "Permissions:Import": "Import", - "Permissions:Delete": "Delete" + "Permissions:Delete": "Delete", + "AggregateReRouteExists": "Aggregate name: {0} already exists!" } } \ No newline at end of file diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/zh-Hans.json b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/zh-Hans.json index 583a6da24..3866b0ed1 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/zh-Hans.json +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Localization/ApplicationContracts/zh-Hans.json @@ -7,10 +7,12 @@ "Permissions:Route": "路由配置", "Permissions:DynamicRoute": "动态路由", "Permissions:AggregateRoute": "路由聚合", + "Permissions:ManageRouteConfig": "管理路由配置", "Permissions:Create": "新增", "Permissions:Update": "编辑", "Permissions:Export": "导出", "Permissions:Import": "导入", - "Permissions:Delete": "删除" + "Permissions:Delete": "删除", + "AggregateReRouteExists": "聚合名称: {0} 已存在!" } } \ No newline at end of file diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteConfigCreateDto.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteConfigCreateDto.cs new file mode 100644 index 000000000..5e7a8830e --- /dev/null +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteConfigCreateDto.cs @@ -0,0 +1,20 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.ApiGateway.Ocelot +{ + public class AggregateReRouteConfigCreateDto + { + [Required] + public string RouteId { get; set; } + + [Required] + [StringLength(256)] + public string ReRouteKey { get; set; } + + [StringLength(1000)] + public string Parameter { get; set; } + + [StringLength(256)] + public string JsonPath { get; set; } + } +} diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteConfigGetByKeyInputDto.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteConfigGetByKeyInputDto.cs new file mode 100644 index 000000000..561d1408a --- /dev/null +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteConfigGetByKeyInputDto.cs @@ -0,0 +1,14 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.ApiGateway.Ocelot +{ + public class AggregateReRouteConfigGetByKeyInputDto + { + [Required] + public string RouteId { get; set; } + + [Required] + [StringLength(256)] + public string ReRouteKey { get; set; } + } +} diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteCreateDto.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteCreateDto.cs new file mode 100644 index 000000000..59cdba0ce --- /dev/null +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteCreateDto.cs @@ -0,0 +1,15 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.ApiGateway.Ocelot +{ + public class AggregateReRouteCreateDto : AggregateReRouteDtoBase + { + [Required] + [StringLength(50)] + public string AppId { get; set; } + + [Required] + [StringLength(50)] + public string Name { get; set; } + } +} diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteUpdateDto.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteUpdateDto.cs new file mode 100644 index 000000000..c4729d6f3 --- /dev/null +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateReRouteUpdateDto.cs @@ -0,0 +1,13 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.ApiGateway.Ocelot +{ + public class AggregateReRouteUpdateDto : AggregateReRouteDtoBase + { + [Required] + public string RouteId { get; set; } + + [Required] + public string ConcurrencyStamp { get; set; } + } +} diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateRouteGetByRouteIdInputDto.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateRouteGetByRouteIdInputDto.cs new file mode 100644 index 000000000..3e1a3c5c3 --- /dev/null +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/AggregateRouteGetByRouteIdInputDto.cs @@ -0,0 +1,10 @@ +using System.ComponentModel.DataAnnotations; + +namespace LINGYUN.ApiGateway.Ocelot +{ + public class AggregateRouteGetByRouteIdInputDto + { + [Required] + public string RouteId { get; set; } + } +} diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Base/AggregateReRouteDtoBase.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Base/AggregateReRouteDtoBase.cs index 16f3448c7..c58e30024 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Base/AggregateReRouteDtoBase.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Base/AggregateReRouteDtoBase.cs @@ -7,18 +7,16 @@ namespace LINGYUN.ApiGateway.Ocelot public class AggregateReRouteDtoBase { public List ReRouteKeys { get; set; } - public List ReRouteKeysConfig { get; set; } public string UpstreamPathTemplate { get; set; } public string UpstreamHost { get; set; } public bool ReRouteIsCaseSensitive { get; set; } public string Aggregator { get; set; } - public int Priority { get; set; } + public int? Priority { get; set; } public List UpstreamHttpMethod { get; set; } public AggregateReRouteDtoBase() { ReRouteKeys = new List(); UpstreamHttpMethod = new List(); - ReRouteKeysConfig = new List(); } } } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Result/AggregateReRouteDto.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Result/AggregateReRouteDto.cs index 53ead89cd..816c6b154 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Result/AggregateReRouteDto.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/Dto/Result/AggregateReRouteDto.cs @@ -1,16 +1,26 @@ using Newtonsoft.Json; using System; +using System.Collections.Generic; namespace LINGYUN.ApiGateway.Ocelot { [Serializable] public class AggregateReRouteDto : AggregateReRouteDtoBase { + public string AppId { get; set; } + [JsonConverter(typeof(HexLongConverter))] public long ReRouteId { get; set; } + public string Name { get; set; } + + public string ConcurrencyStamp { get; set; } + + public List ReRouteKeysConfig { get; set; } + public AggregateReRouteDto() { + ReRouteKeysConfig = new List(); } } } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/IAggregateReRouteAppService.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/IAggregateReRouteAppService.cs index fdfca3348..e5b788ca4 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/IAggregateReRouteAppService.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application.Contracts/LINGYUN/ApiGateway/Ocelot/IAggregateReRouteAppService.cs @@ -6,8 +6,20 @@ namespace LINGYUN.ApiGateway.Ocelot { public interface IAggregateReRouteAppService : IApplicationService { + Task GetAsync(AggregateRouteGetByRouteIdInputDto aggregateRouteGetByRouteId); + Task> GetAsync(AggregateRouteGetByAppIdInputDto aggregateRouteGetByAppId); Task> GetPagedListAsync(AggregateRouteGetByPagedInputDto aggregateRouteGetByPaged); + + Task CreateAsync(AggregateReRouteCreateDto aggregateReRouteCreate); + + Task UpdateAsync(AggregateReRouteUpdateDto aggregateReRouteUpdate); + + Task DeleteAsync(AggregateRouteGetByRouteIdInputDto aggregateRouteGetByRouteId); + + Task AddRouteConfigAsync(AggregateReRouteConfigCreateDto aggregateReRouteConfigCreate); + + Task DeleteRouteConfigAsync(AggregateReRouteConfigGetByKeyInputDto aggregateReRouteConfigGetByKey); } } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/ApiGatewayApplicationAutoMapperProfile.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/ApiGatewayApplicationAutoMapperProfile.cs index c898fc2ec..1ddc617f4 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/ApiGatewayApplicationAutoMapperProfile.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/ApiGatewayApplicationAutoMapperProfile.cs @@ -64,12 +64,18 @@ namespace LINGYUN.ApiGateway CreateMap(); CreateMap() - .ForMember(dto => dto.ReRouteKeys, map => map.MapFrom(m => !m.ReRouteKeys.IsNullOrWhiteSpace() && m.ReRouteKeys.Contains(",") - ? m.ReRouteKeys.Split(',').ToList() - : new List())) - .ForMember(dto => dto.UpstreamHttpMethod, map => map.MapFrom(m => !m.UpstreamHttpMethod.IsNullOrWhiteSpace() && m.UpstreamHttpMethod.Contains(",") - ? m.UpstreamHttpMethod.Split(',').ToList() - : new List())); + .ForMember(dto => dto.ReRouteKeys, map => map.MapFrom(m => MapperList(m.ReRouteKeys))) + .ForMember(dto => dto.UpstreamHttpMethod, map => map.MapFrom(m => MapperList(m.UpstreamHttpMethod))); + + CreateMap() + .ForCtorParam("name", x => x.MapFrom(m => m.Name)) + .ForCtorParam("routeId", x => x.MapFrom(m => snowflakeIdGenerator.NextId())) + .ForCtorParam("aggregator", x => x.MapFrom(m => m.Aggregator)) + .ForCtorParam("appId", x => x.MapFrom(m => m.AppId)) + .ForMember(src => src.ExtraProperties, x => x.Ignore()) + .ForMember(src => src.ReRouteKeys, x => x.Ignore()) + .ForMember(src => src.ReRouteKeysConfig, x => x.Ignore()) + .ForMember(src => src.UpstreamHttpMethod, x => x.Ignore()); CreateMap(); diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs index 78e28383b..1f742719e 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/AggregateReRouteAppService.cs @@ -1,21 +1,40 @@ -using Microsoft.AspNetCore.Authorization; +using DotNetCore.CAP; +using LINGYUN.ApiGateway.EventBus; +using LINGYUN.ApiGateway.Snowflake; +using Microsoft.AspNetCore.Authorization; using System.Collections.Generic; using System.Threading.Tasks; +using Volo.Abp; using Volo.Abp.Application.Dtos; namespace LINGYUN.ApiGateway.Ocelot { + // 2020-05-20 15:00 + // TODO 重构项目 规范化实体的存储形式,数组类型分为多张表存储 + // TODO 取消long类型的实体主键 改用GUID + [Authorize(ApiGatewayPermissions.AggregateRoute.Default)] public class AggregateReRouteAppService : ApiGatewayApplicationServiceBase, IAggregateReRouteAppService { + private readonly ICapPublisher _eventPublisher; private readonly IAggregateReRouteRepository _aggregateReRouteRepository; public AggregateReRouteAppService( + ICapPublisher eventPublisher, IAggregateReRouteRepository aggregateReRouteRepository) { + _eventPublisher = eventPublisher; _aggregateReRouteRepository = aggregateReRouteRepository; } + public virtual async Task GetAsync(AggregateRouteGetByRouteIdInputDto aggregateRouteGetByRouteId) + { + var routeId = long.Parse(aggregateRouteGetByRouteId.RouteId); + var reroute = await _aggregateReRouteRepository.GetByRouteIdAsync(routeId); + + return ObjectMapper.Map(reroute); + } + [Authorize(ApiGatewayPermissions.AggregateRoute.Export)] public async Task> GetAsync(AggregateRouteGetByAppIdInputDto aggregateRouteGetByAppId) { @@ -34,5 +53,105 @@ namespace LINGYUN.ApiGateway.Ocelot return new PagedResultDto(reroutesTuple.total, ObjectMapper.Map, List>(reroutesTuple.routes)); } + + [Authorize(ApiGatewayPermissions.AggregateRoute.Create)] + public virtual async Task CreateAsync(AggregateReRouteCreateDto aggregateReRouteCreate) + { + var aggregateNameExists = await _aggregateReRouteRepository + .AggregateReRouteNameExistsAsync(aggregateReRouteCreate.Name); + if (aggregateNameExists) + { + throw new UserFriendlyException(L["AggregateReRouteExists", aggregateReRouteCreate.Name]); + } + var aggregateRoute = ObjectMapper.Map(aggregateReRouteCreate); + aggregateRoute.SetUpstream(aggregateReRouteCreate.UpstreamHost, aggregateReRouteCreate.UpstreamPathTemplate); + foreach (var httpMethod in aggregateReRouteCreate.UpstreamHttpMethod) + { + aggregateRoute.AddUpstreamHttpMethod(httpMethod); + } + foreach (var routeKey in aggregateReRouteCreate.ReRouteKeys) + { + aggregateRoute.AddRouteKey(routeKey); + } + aggregateRoute = await _aggregateReRouteRepository.InsertAsync(aggregateRoute); + + await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, + new ApigatewayConfigChangeCommand("AggregateRoute", "Create")); + + return ObjectMapper.Map(aggregateRoute); + } + + [Authorize(ApiGatewayPermissions.AggregateRoute.Update)] + public virtual async Task UpdateAsync(AggregateReRouteUpdateDto aggregateReRouteUpdate) + { + var routeId = long.Parse(aggregateReRouteUpdate.RouteId); + var aggregateRoute = await _aggregateReRouteRepository.GetByRouteIdAsync(routeId); + aggregateRoute.Priority = aggregateReRouteUpdate.Priority; + aggregateRoute.ConcurrencyStamp = aggregateReRouteUpdate.ConcurrencyStamp; + aggregateRoute.ReRouteIsCaseSensitive = aggregateReRouteUpdate.ReRouteIsCaseSensitive; + aggregateRoute.Aggregator = aggregateReRouteUpdate.Aggregator; + aggregateRoute.SetUpstream(aggregateReRouteUpdate.UpstreamHost, aggregateReRouteUpdate.UpstreamPathTemplate); + + aggregateRoute.RemoveAllUpstreamHttpMethod(); + foreach (var httpMethod in aggregateReRouteUpdate.UpstreamHttpMethod) + { + aggregateRoute.AddUpstreamHttpMethod(httpMethod); + } + + aggregateRoute.RemoveAllRouteKey(); + foreach (var routeKey in aggregateReRouteUpdate.ReRouteKeys) + { + aggregateRoute.AddRouteKey(routeKey); + } + + aggregateRoute = await _aggregateReRouteRepository.UpdateAsync(aggregateRoute, true); + + await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, + new ApigatewayConfigChangeCommand("AggregateRoute", "Update")); + + return ObjectMapper.Map(aggregateRoute); + } + + [Authorize(ApiGatewayPermissions.AggregateRoute.Delete)] + public virtual async Task DeleteAsync(AggregateRouteGetByRouteIdInputDto aggregateRouteGetByRouteId) + { + var routeId = long.Parse(aggregateRouteGetByRouteId.RouteId); + var aggregateRoute = await _aggregateReRouteRepository.GetByRouteIdAsync(routeId); + await _aggregateReRouteRepository.DeleteAsync(aggregateRoute); + + await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, + new ApigatewayConfigChangeCommand("AggregateRoute", "Delete")); + } + + [Authorize(ApiGatewayPermissions.AggregateRoute.ManageRouteConfig)] + public virtual async Task AddRouteConfigAsync(AggregateReRouteConfigCreateDto aggregateReRouteConfigCreate) + { + var routeId = long.Parse(aggregateReRouteConfigCreate.RouteId); + var aggregateRoute = await _aggregateReRouteRepository.GetByRouteIdAsync(routeId); + aggregateRoute.RemoveReRouteConfig(aggregateReRouteConfigCreate.ReRouteKey) + .AddReRouteConfig(aggregateReRouteConfigCreate.ReRouteKey, aggregateReRouteConfigCreate.Parameter, + aggregateReRouteConfigCreate.JsonPath); + var aggregateRouteConfig = aggregateRoute.FindReRouteConfig(aggregateReRouteConfigCreate.ReRouteKey); + + await _aggregateReRouteRepository.UpdateAsync(aggregateRoute); + + await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, + new ApigatewayConfigChangeCommand("AggregateRoute", "AddRouteConfig")); + + return ObjectMapper.Map(aggregateRouteConfig); + } + + [Authorize(ApiGatewayPermissions.AggregateRoute.ManageRouteConfig)] + public virtual async Task DeleteRouteConfigAsync(AggregateReRouteConfigGetByKeyInputDto aggregateReRouteConfigGetByKey) + { + var routeId = long.Parse(aggregateReRouteConfigGetByKey.RouteId); + var aggregateRoute = await _aggregateReRouteRepository.GetByRouteIdAsync(routeId); + aggregateRoute.RemoveReRouteConfig(aggregateReRouteConfigGetByKey.ReRouteKey); + + await _aggregateReRouteRepository.UpdateAsync(aggregateRoute); + + await _eventPublisher.PublishAsync(ApigatewayConfigChangeCommand.EventName, + new ApigatewayConfigChangeCommand("AggregateRoute", "DeleteRouteConfig")); + } } } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs index 643002669..03f81cb6c 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Application/LINGYUN/ApiGateway/Ocelot/ReRouteAppService.cs @@ -46,7 +46,7 @@ namespace LINGYUN.ApiGateway.Ocelot public async Task UpdateAsync(ReRouteUpdateDto routeUpdateDto) { var reRoute = await _reRouteRepository.GetByReRouteIdAsync(long.Parse(routeUpdateDto.ReRouteId)); - + reRoute.SetRouteName(routeUpdateDto.ReRouteName); reRoute.DangerousAcceptAnyServerCertificateValidator = routeUpdateDto.DangerousAcceptAnyServerCertificateValidator; reRoute.DownstreamScheme = routeUpdateDto.DownstreamScheme; reRoute.Key = routeUpdateDto.Key; diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/AggregateReRoute.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/AggregateReRoute.cs index fd524324e..393326a0e 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/AggregateReRoute.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/AggregateReRoute.cs @@ -16,8 +16,8 @@ namespace LINGYUN.ApiGateway.Ocelot public virtual string ReRouteKeys { get; private set; } public virtual string UpstreamPathTemplate { get; private set; } public virtual string UpstreamHost { get; private set; } - public virtual bool ReRouteIsCaseSensitive { get; private set; } - public virtual string Aggregator { get; private set; } + public virtual bool ReRouteIsCaseSensitive { get; set; } + public virtual string Aggregator { get; set; } public virtual int? Priority { get; set; } public virtual string UpstreamHttpMethod { get; private set; } public virtual ICollection ReRouteKeysConfig { get; private set; } @@ -26,26 +26,27 @@ namespace LINGYUN.ApiGateway.Ocelot ReRouteKeysConfig = new List(); } - public AggregateReRoute SetUpstreamPath(string host, string path, string appId) + public AggregateReRoute(string name, long routeId, string aggregator, string appId) : this() { AppId = appId; - UpstreamHost = host; - UpstreamPathTemplate = path; - return this; - } - - public AggregateReRoute(string name, long routeId, string aggregator) : this() - { Name = name; ReRouteId = routeId; Aggregator = aggregator; + ReRouteKeys = ""; + UpstreamHttpMethod = ""; + } + + public void SetUpstream(string host, string template) + { + UpstreamHost = host; + UpstreamPathTemplate = template; } public AggregateReRoute AddUpstreamHttpMethod(string method) { if (!UpstreamHttpMethod.Contains(method)) { - UpstreamHttpMethod += "," + method; + UpstreamHttpMethod += method + ","; } return this; } @@ -60,11 +61,17 @@ namespace LINGYUN.ApiGateway.Ocelot return this; } + public AggregateReRoute RemoveAllUpstreamHttpMethod() + { + UpstreamHttpMethod = ""; + return this; + } + public AggregateReRoute AddRouteKey(string key) { if (!ReRouteKeys.Contains(key)) { - ReRouteKeys += "," + key; + ReRouteKeys += key + ","; } return this; } @@ -79,6 +86,17 @@ namespace LINGYUN.ApiGateway.Ocelot return this; } + public AggregateReRoute RemoveAllRouteKey() + { + ReRouteKeys = ""; + return this; + } + + public AggregateReRouteConfig FindReRouteConfig(string routeKey) + { + return ReRouteKeysConfig.FirstOrDefault(cfg => cfg.ReRouteKey.Equals(routeKey)); + } + public AggregateReRoute AddReRouteConfig(string routeKey, string paramter, string jsonPath) { if (!ReRouteKeysConfig.Any(k => k.ReRouteKey.Equals(routeKey))) @@ -95,5 +113,11 @@ namespace LINGYUN.ApiGateway.Ocelot ReRouteKeysConfig.RemoveAll(k => k.ReRouteKey.Equals(routeKey)); return this; } + + public AggregateReRoute RemoveAllReRouteConfig() + { + ReRouteKeysConfig.Clear(); + return this; + } } } diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/IAggregateReRouteRepository.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/IAggregateReRouteRepository.cs index 79191a444..c350591e1 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/IAggregateReRouteRepository.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.Domain/LINGYUN/ApiGateway/Ocelot/Aggregate/IAggregateReRouteRepository.cs @@ -6,6 +6,10 @@ namespace LINGYUN.ApiGateway.Ocelot { public interface IAggregateReRouteRepository : IBasicRepository { + Task AggregateReRouteNameExistsAsync(string name); + + Task GetByRouteIdAsync(long routeId); + Task> GetByAppIdAsync(string appId); Task<(List routes, long total)> GetPagedListAsync(string appId, string filter = "", string sorting = "", int skipCount = 1, int maxResultCount = 100); diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/Ocelot/EfCoreAggregateReRouteRepository.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/Ocelot/EfCoreAggregateReRouteRepository.cs index fa69a11d3..1320dda17 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/Ocelot/EfCoreAggregateReRouteRepository.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.EntityFrameworkCore/LINGYUN/ApiGateway/Ocelot/EfCoreAggregateReRouteRepository.cs @@ -15,6 +15,16 @@ namespace LINGYUN.ApiGateway.Ocelot { } + public async Task AggregateReRouteNameExistsAsync(string name) + { + return await DbSet.AnyAsync(ar => ar.Name.Equals(name)); + } + + public async Task GetByRouteIdAsync(long routeId) + { + return await WithDetails().Where(ar => ar.ReRouteId.Equals(routeId)).FirstOrDefaultAsync(); + } + public async Task> GetByAppIdAsync(string appId) { return await WithDetails().Where(ar => ar.AppId.Equals(appId)).ToListAsync(); diff --git a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi/LINGYUN/ApiGateway/Ocelot/AggregateReRouteController.cs b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi/LINGYUN/ApiGateway/Ocelot/AggregateReRouteController.cs index 1ba22e8b5..e43842b8d 100644 --- a/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi/LINGYUN/ApiGateway/Ocelot/AggregateReRouteController.cs +++ b/aspnet-core/modules/apigateway/LINGYUN.ApiGateway.HttpApi/LINGYUN/ApiGateway/Ocelot/AggregateReRouteController.cs @@ -29,5 +29,44 @@ namespace LINGYUN.ApiGateway.Ocelot { return await AggregateReRouteAppService.GetPagedListAsync(aggregateRouteGetByPaged); } + + [HttpGet] + [Route("{RouteId}")] + public async Task GetAsync(AggregateRouteGetByRouteIdInputDto aggregateRouteGetByRouteId) + { + return await AggregateReRouteAppService.GetAsync(aggregateRouteGetByRouteId); + } + + [HttpPost] + public async Task CreateAsync(AggregateReRouteCreateDto aggregateReRouteCreate) + { + return await AggregateReRouteAppService.CreateAsync(aggregateReRouteCreate); + } + + [HttpPut] + public async Task UpdateAsync(AggregateReRouteUpdateDto aggregateReRouteUpdate) + { + return await AggregateReRouteAppService.UpdateAsync(aggregateReRouteUpdate); + } + + [HttpDelete] + public async Task DeleteAsync(AggregateRouteGetByRouteIdInputDto aggregateRouteGetByRouteId) + { + await AggregateReRouteAppService.DeleteAsync(aggregateRouteGetByRouteId); + } + + [HttpPost] + [Route("RouteConfig")] + public async Task AddRouteConfigAsync(AggregateReRouteConfigCreateDto aggregateReRouteConfigCreate) + { + return await AggregateReRouteAppService.AddRouteConfigAsync(aggregateReRouteConfigCreate); + } + + [HttpDelete] + [Route("RouteConfig")] + public async Task DeleteRouteConfigAsync(AggregateReRouteConfigGetByKeyInputDto aggregateReRouteConfigGetByKey) + { + await AggregateReRouteAppService.DeleteRouteConfigAsync(aggregateReRouteConfigGetByKey); + } } } diff --git a/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application.Contracts/LINGYUN.TenantManagement.Application.Contracts.csproj b/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application.Contracts/LINGYUN.TenantManagement.Application.Contracts.csproj index 4d405ac17..b631f522e 100644 --- a/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application.Contracts/LINGYUN.TenantManagement.Application.Contracts.csproj +++ b/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application.Contracts/LINGYUN.TenantManagement.Application.Contracts.csproj @@ -5,12 +5,9 @@ - - - - + diff --git a/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/LINGYUN.TenantManagement.Application.csproj b/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/LINGYUN.TenantManagement.Application.csproj index 83d348032..a0fdc715c 100644 --- a/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/LINGYUN.TenantManagement.Application.csproj +++ b/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/LINGYUN.TenantManagement.Application.csproj @@ -5,4 +5,12 @@ + + + + + + + + diff --git a/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/obj/Debug/netstandard2.0/LINGYUN.TenantManagement.Application.csprojAssemblyReference.cache b/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/obj/Debug/netstandard2.0/LINGYUN.TenantManagement.Application.csprojAssemblyReference.cache index 79a6a84b1..2b5c4715b 100644 Binary files a/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/obj/Debug/netstandard2.0/LINGYUN.TenantManagement.Application.csprojAssemblyReference.cache and b/aspnet-core/modules/tenants/LINGYUN.TenantManagement.Application/obj/Debug/netstandard2.0/LINGYUN.TenantManagement.Application.csprojAssemblyReference.cache differ diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs index 1b62a10ee..5a5666258 100644 --- a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/LINGYUN/ApiGateway/ApiGatewayHostModule.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Options; using Ocelot.Configuration.Repository; using Ocelot.DependencyInjection; using Ocelot.Extenssions; +using Ocelot.Middleware.Multiplexer; using Ocelot.Provider.Polly; using Volo.Abp; using Volo.Abp.AspNetCore; @@ -54,7 +55,10 @@ namespace LINGYUN.ApiGateway options.ApiSecret = configuration["AuthServer:ApiSecret"]; }); - context.Services.AddOcelot().AddPolly(); + context.Services + .AddOcelot() + .AddPolly() + .AddSingletonDefinedAggregator(); } public override void OnApplicationInitialization(ApplicationInitializationContext context) diff --git a/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionResponseAggregator.cs b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionResponseAggregator.cs new file mode 100644 index 000000000..651dffc9d --- /dev/null +++ b/aspnet-core/services/apigateway/LINGYUN.ApiGateway.Host/Ocelot/Middleware/Multiplexer/AbpApiDefinitionResponseAggregator.cs @@ -0,0 +1,152 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Text; +using System.Threading.Tasks; + +namespace Ocelot.Middleware.Multiplexer +{ + public class AbpApiDefinitionAggregator : IDefinedAggregator + { + public async Task Aggregate(List responses) + { + var isAbpResponse = responses.Any(response => response.DownstreamResponse.Headers.Any(h => h.Key.Equals("_abperrorformat"))); + return await MapAbpApiDefinitionAggregateContentAsync(responses); + //if (isAbpResponse) + //{ + // return await MapAbpApiDefinitionAggregateContentAsync(responses); + //} + //else + //{ + // return await MapSimpleJsonAggregateContentAsync(responses); + //} + } + + protected virtual async Task MapAbpApiDefinitionAggregateContentAsync(List downstreamContexts) + { + var responseKeys = downstreamContexts.Select(s => s.DownstreamReRoute.Key).Distinct().ToList(); + JObject responseObject = null; + for (var k = 0; k < responseKeys.Count; k++) + { + var contexts = downstreamContexts.Where(w => w.DownstreamReRoute.Key == responseKeys[k]).ToList(); + if (contexts.Count == 1) + { + if (contexts[0].IsError) + { + return contexts[0].DownstreamResponse; + } + + var content = await contexts[0].DownstreamResponse.Content.ReadAsStringAsync(); + var contentObject = JsonConvert.DeserializeObject(content); + if (responseObject == null) + { + responseObject = JObject.FromObject(contentObject); + } + else + { + responseObject.Merge(contentObject); + } + } + else + { + for (var i = 0; i < contexts.Count; i++) + { + if (contexts[i].IsError) + { + return contexts[i].DownstreamResponse; + } + + var content = await contexts[i].DownstreamResponse.Content.ReadAsStringAsync(); + var contentObject = JsonConvert.DeserializeObject(content); + if (responseObject == null) + { + responseObject = JObject.FromObject(contentObject); + } + else + { + responseObject.Merge(contentObject); + } + } + } + } + + var stringContent = new StringContent(responseObject.ToString()) + { + Headers = { ContentType = new MediaTypeHeaderValue("application/json") } + }; + stringContent.Headers.Add("_abperrorformat", "true"); + return new DownstreamResponse(stringContent, HttpStatusCode.OK, new List>>(), "cannot return from aggregate..which reason phrase would you use?"); + } + + protected virtual async Task MapSimpleJsonAggregateContentAsync(List downstreamContexts) + { + var contentBuilder = new StringBuilder(); + + contentBuilder.Append("{"); + + var responseKeys = downstreamContexts.Select(s => s.DownstreamReRoute.Key).Distinct().ToList(); + + for (var k = 0; k < responseKeys.Count; k++) + { + var contexts = downstreamContexts.Where(w => w.DownstreamReRoute.Key == responseKeys[k]).ToList(); + if (contexts.Count == 1) + { + if (contexts[0].IsError) + { + return contexts[0].DownstreamResponse; + } + + var content = await contexts[0].DownstreamResponse.Content.ReadAsStringAsync(); + contentBuilder.Append($"\"{responseKeys[k]}\":{content}"); + } + else + { + contentBuilder.Append($"\"{responseKeys[k]}\":"); + contentBuilder.Append("["); + + for (var i = 0; i < contexts.Count; i++) + { + if (contexts[i].IsError) + { + return contexts[i].DownstreamResponse; + } + + var content = await contexts[i].DownstreamResponse.Content.ReadAsStringAsync(); + if (string.IsNullOrWhiteSpace(content)) + { + continue; + } + + contentBuilder.Append($"{content}"); + + if (i + 1 < contexts.Count) + { + contentBuilder.Append(","); + } + } + + contentBuilder.Append("]"); + } + + if (k + 1 < responseKeys.Count) + { + contentBuilder.Append(","); + } + } + + contentBuilder.Append("}"); + + var stringContent = new StringContent(contentBuilder.ToString()) + { + Headers = { ContentType = new MediaTypeHeaderValue("application/json") } + }; + + return new DownstreamResponse(stringContent, HttpStatusCode.OK, new List>>(), "cannot return from aggregate..which reason phrase would you use?"); + } + + } +} diff --git a/vueJs/src/api/apigateway.ts b/vueJs/src/api/apigateway.ts index 72efb3516..801abb2b5 100644 --- a/vueJs/src/api/apigateway.ts +++ b/vueJs/src/api/apigateway.ts @@ -120,6 +120,50 @@ export default class ApiGateWay { _url += '?appId=' + appId return ApiService.Delete(_url, serviceUrl) } + + public static getAggregateReRoutes(payload: AggregateReRouteGetByPaged) { + let _url = '/api/ApiGateway/Aggregates' + _url += '?appId=' + payload.appId + _url += '&filter=' + payload.filter + _url += '&sorting=' + payload.sorting + _url += '&skipCount=' + payload.skipCount + _url += '&maxResultCount=' + payload.maxResultCount + return ApiService.Get>(_url, serviceUrl) + } + + public static getAggregateReRouteByRouteId(routeId: string) { + let _url = '/api/ApiGateway/Aggregates/' + _url += routeId + return ApiService.Get(_url, serviceUrl) + } + + public static createAggregateReRoute(payload: AggregateReRouteCreate) { + const _url = '/api/ApiGateway/Aggregates' + return ApiService.Post(_url, payload, serviceUrl) + } + + public static updateAggregateReRoute(payload: AggregateReRouteUpdate) { + const _url = '/api/ApiGateway/Aggregates' + return ApiService.Put(_url, payload, serviceUrl) + } + + public static deleteAggregateReRoute(routeId: string) { + let _url = '/api/ApiGateway/Aggregates' + _url += '?routeId=' + routeId + return ApiService.Delete(_url, serviceUrl) + } + + public static createAggregateRouteConfig(payload: AggregateReRouteConfigCreate) { + const _url = '/api/ApiGateway/Aggregates/RouteConfig' + return ApiService.Post(_url, payload, serviceUrl) + } + + public static deleteAggregateRouteConfig(routeId: string, routeKey: string) { + let _url = '/api/ApiGateway/Aggregates/RouteConfig' + _url += '?routeId=' + routeId + _url += '&ReRouteKey=' + routeKey + return ApiService.Delete(_url, serviceUrl) + } } export class ServiceDiscoveryProvider { @@ -412,3 +456,100 @@ export class ReRouteGetByPagedDto extends PagedAndSortedResultRequestDto { this.sorting = 'ReRouteName' } } + +export class AggregateReRouteConfig { + reRouteKey = '' + parameter = '' + jsonPath = '' +} + +export class AggregateReRouteConfigCreate extends AggregateReRouteConfig { + routeId = '' +} + +export class AggregateReRouteBase { + reRouteKeys!: string[] + upstreamPathTemplate = '' + upstreamHost = '' + reRouteIsCaseSensitive = true + aggregator = '' + priority?: number + upstreamHttpMethod!: string[] + + constructor() { + this.reRouteKeys = new Array() + this.upstreamHttpMethod = new Array() + } +} + +export class AggregateReRoute extends AggregateReRouteBase { + appId = '' + name = '' + reRouteId = '' + concurrencyStamp = '' + reRouteKeysConfig!: AggregateReRouteConfig[] + + constructor() { + super() + this.reRouteKeysConfig = new Array() + } + + public static empty() { + return new AggregateReRoute() + } +} + +export class AggregateReRouteCreate extends AggregateReRouteBase { + appId = '' + name = '' + + public static empty() { + return new AggregateReRouteCreate() + } + + public static create(route: AggregateReRoute) { + const aggregateRoute = new AggregateReRouteCreate() + aggregateRoute.appId = route.appId + aggregateRoute.name = route.name + aggregateRoute.aggregator = route.aggregator + aggregateRoute.priority = route.priority + aggregateRoute.reRouteIsCaseSensitive = route.reRouteIsCaseSensitive + aggregateRoute.reRouteKeys = route.reRouteKeys + aggregateRoute.upstreamHost = route.upstreamHost + aggregateRoute.upstreamHttpMethod = route.upstreamHttpMethod + aggregateRoute.upstreamPathTemplate = route.upstreamPathTemplate + return aggregateRoute + } +} + +export class AggregateReRouteUpdate extends AggregateReRouteBase { + routeId = '' + concurrencyStamp = '' + + public static empty() { + return new AggregateReRouteUpdate() + } + + public static create(route: AggregateReRoute) { + const aggregateRoute = new AggregateReRouteUpdate() + aggregateRoute.aggregator = route.aggregator + aggregateRoute.concurrencyStamp = route.concurrencyStamp + aggregateRoute.priority = route.priority + aggregateRoute.reRouteIsCaseSensitive = route.reRouteIsCaseSensitive + aggregateRoute.reRouteKeys = route.reRouteKeys + aggregateRoute.routeId = route.reRouteId + aggregateRoute.upstreamHost = route.upstreamHost + aggregateRoute.upstreamHttpMethod = route.upstreamHttpMethod + aggregateRoute.upstreamPathTemplate = route.upstreamPathTemplate + return aggregateRoute + } +} + +export class AggregateReRouteGetByPaged extends PagedAndSortedResultRequestDto { + appId = '' + filter = '' + + public static empty() { + return new AggregateReRouteGetByPaged() + } +} diff --git a/vueJs/src/lang/zh.ts b/vueJs/src/lang/zh.ts index 3474d241d..6896f5d09 100644 --- a/vueJs/src/lang/zh.ts +++ b/vueJs/src/lang/zh.ts @@ -72,6 +72,7 @@ export default { group: '路由分组', global: '全局配置', route: '路由配置', + aggregateRoute: '聚合路由', identityServer: '身份认证服务器', clients: '客户端管理', apiresources: 'Api资源管理', @@ -343,6 +344,7 @@ export default { appIdHasRequired: '应用标识不能为空!', upstreamPathTemplate: '上游请求路径', upstreamHttpMethod: '上游请求方式', + upstreamHost: '上游主机地址', downstreamHostAndPorts: '下游请求地址', downstreamPathTemplate: '下游请求路径', serviceName: '服务名称', @@ -369,7 +371,20 @@ export default { ipAllowedList: 'Ip白名单', ipBlockedList: 'Ip黑名单', authenticationProviderKey: '身份认证程序', - allowedScopes: '允许认证范围' + allowedScopes: '允许认证范围', + createAggregateRoute: '新建聚合', + aggregateRouteName: '聚合名称', + reRouteKeys: '路由标识列表', + aggregateOptions: '聚合选项', + updateAggregateRoute: '编辑聚合', + updateAggregateRouteByName: '编辑聚合 {name}', + deleteAggregateRoute: '删除聚合', + deleteAggregateRouteByName: '删除聚合 {name}', + deleteAggregateRouteSuccess: '聚合路由 {name} 已删除!', + createAggregateRouteKey: '新建聚合参数', + aggregateRouteKey: '聚合路由标识', + aggregateParameter: '聚合参数', + aggregateJsonPath: 'Json路径' }, identityServer: { otherOpera: '更多操作', diff --git a/vueJs/src/router/index.ts b/vueJs/src/router/index.ts index 916b00ea8..bd6001224 100644 --- a/vueJs/src/router/index.ts +++ b/vueJs/src/router/index.ts @@ -290,6 +290,16 @@ export const asyncRoutes: RouteConfig[] = [ icon: 'route', roles: ['ApiGateway.Route'] } + }, + { + path: 'aggregateRoute', + component: () => import('@/views/admin/apigateway/aggregateRoute.vue'), + name: 'aggregateRoute', + meta: { + title: 'aggregateRoute', + icon: 'aggregateRoute', + roles: ['ApiGateway.AggregateRoute'] + } } ] }, diff --git a/vueJs/src/views/admin/apigateway/aggregateRoute.vue b/vueJs/src/views/admin/apigateway/aggregateRoute.vue index e69de29bb..4a2febdc2 100644 --- a/vueJs/src/views/admin/apigateway/aggregateRoute.vue +++ b/vueJs/src/views/admin/apigateway/aggregateRoute.vue @@ -0,0 +1,295 @@ + + + diff --git a/vueJs/src/views/admin/apigateway/components/AggregateRouteCreateOrEditForm.vue b/vueJs/src/views/admin/apigateway/components/AggregateRouteCreateOrEditForm.vue new file mode 100644 index 000000000..00e2da463 --- /dev/null +++ b/vueJs/src/views/admin/apigateway/components/AggregateRouteCreateOrEditForm.vue @@ -0,0 +1,197 @@ + + + diff --git a/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue b/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue index c52e9bec0..baad2603c 100644 --- a/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue +++ b/vueJs/src/views/admin/apigateway/components/RouteCreateOrEditForm.vue @@ -34,7 +34,6 @@