mirror of
https://gitee.com/ccnetcore/Yi
synced 2026-04-16 22:26:37 +08:00
Compare commits
11 Commits
multipleDb
...
dev-Entity
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5dfaf75440 | ||
|
|
6be5398114 | ||
|
|
3932b24fda | ||
|
|
356938d6d3 | ||
|
|
1090907178 | ||
|
|
da2f7073f9 | ||
|
|
f656ec32c1 | ||
|
|
1cc0ef916f | ||
|
|
5d793344cd | ||
|
|
bcaca0b782 | ||
|
|
5cee7319c6 |
@@ -9,84 +9,89 @@ using Microsoft.OpenApi.Any;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Volo.Abp.AspNetCore.Mvc;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Options;
|
||||
|
||||
namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
public static class SwaggerAddExtensions
|
||||
{
|
||||
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services, Action<SwaggerGenOptions>? action=null)
|
||||
public static IServiceCollection AddYiSwaggerGen<Program>(this IServiceCollection services,
|
||||
Action<SwaggerGenOptions>? action = null)
|
||||
{
|
||||
|
||||
var serviceProvider = services.BuildServiceProvider();
|
||||
var mvcOptions = serviceProvider.GetRequiredService<IOptions<AbpAspNetCoreMvcOptions>>();
|
||||
|
||||
var mvcSettings = mvcOptions.Value.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
|
||||
var mvcOptions = services.GetPreConfigureActions<AbpAspNetCoreMvcOptions>().Configure();
|
||||
|
||||
var mvcSettings =
|
||||
mvcOptions.ConventionalControllers.ConventionalControllerSettings.DistinctBy(x => x.RemoteServiceName);
|
||||
|
||||
|
||||
services.AddAbpSwaggerGen(
|
||||
options =>
|
||||
{
|
||||
if (action is not null)
|
||||
options =>
|
||||
{
|
||||
action.Invoke(options);
|
||||
}
|
||||
|
||||
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
|
||||
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
|
||||
{
|
||||
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
|
||||
if (action is not null)
|
||||
{
|
||||
options.SwaggerDoc(setting.RemoteServiceName, new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
|
||||
action.Invoke(options);
|
||||
}
|
||||
}
|
||||
|
||||
// 根据分组名称过滤 API 文档
|
||||
options.DocInclusionPredicate((docName, apiDesc) =>
|
||||
{
|
||||
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
|
||||
// 配置分组,还需要去重,支持重写,如果外部传入后,将以外部为准
|
||||
foreach (var setting in mvcSettings.OrderBy(x => x.RemoteServiceName))
|
||||
{
|
||||
var settingOrNull = mvcSettings.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly).FirstOrDefault();
|
||||
if (settingOrNull is not null)
|
||||
if (!options.SwaggerGeneratorOptions.SwaggerDocs.ContainsKey(setting.RemoteServiceName))
|
||||
{
|
||||
return docName == settingOrNull.RemoteServiceName;
|
||||
options.SwaggerDoc(setting.RemoteServiceName,
|
||||
new OpenApiInfo { Title = setting.RemoteServiceName, Version = "v1" });
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
options.CustomSchemaIds(type => type.FullName);
|
||||
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
|
||||
if (basePath is not null)
|
||||
{
|
||||
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
|
||||
// 根据分组名称过滤 API 文档
|
||||
options.DocInclusionPredicate((docName, apiDesc) =>
|
||||
{
|
||||
options.IncludeXmlComments(item, true);
|
||||
if (apiDesc.ActionDescriptor is ControllerActionDescriptor controllerActionDescriptor)
|
||||
{
|
||||
var settingOrNull = mvcSettings
|
||||
.Where(x => x.Assembly == controllerActionDescriptor.ControllerTypeInfo.Assembly)
|
||||
.FirstOrDefault();
|
||||
if (settingOrNull is not null)
|
||||
{
|
||||
return docName == settingOrNull.RemoteServiceName;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
options.CustomSchemaIds(type => type.FullName);
|
||||
var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);
|
||||
if (basePath is not null)
|
||||
{
|
||||
foreach (var item in Directory.GetFiles(basePath, "*.xml"))
|
||||
{
|
||||
options.IncludeXmlComments(item, true);
|
||||
}
|
||||
}
|
||||
|
||||
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
|
||||
{
|
||||
Description = "直接输入Token即可",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.Http,
|
||||
Scheme = "bearer"
|
||||
});
|
||||
var scheme = new OpenApiSecurityScheme()
|
||||
{
|
||||
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
|
||||
};
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||
{
|
||||
[scheme] = new string[0]
|
||||
});
|
||||
|
||||
options.OperationFilter<AddRequiredHeaderParameter>();
|
||||
options.SchemaFilter<EnumSchemaFilter>();
|
||||
}
|
||||
);
|
||||
|
||||
options.AddSecurityDefinition("JwtBearer", new OpenApiSecurityScheme()
|
||||
{
|
||||
Description = "直接输入Token即可",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.Http,
|
||||
Scheme = "bearer"
|
||||
});
|
||||
var scheme = new OpenApiSecurityScheme()
|
||||
{
|
||||
Reference = new OpenApiReference() { Type = ReferenceType.SecurityScheme, Id = "JwtBearer" }
|
||||
};
|
||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement()
|
||||
{
|
||||
[scheme] = new string[0]
|
||||
});
|
||||
|
||||
options.OperationFilter<AddRequiredHeaderParameter>();
|
||||
options.SchemaFilter<EnumSchemaFilter>();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
@@ -103,7 +108,6 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||
/// </summary>
|
||||
/// <param name="model"></param>
|
||||
/// <param name="context"></param>
|
||||
|
||||
public void Apply(OpenApiSchema model, SchemaFilterContext context)
|
||||
{
|
||||
if (context.Type.IsEnum)
|
||||
@@ -112,7 +116,7 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||
model.Type = "string";
|
||||
model.Format = null;
|
||||
|
||||
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
Enum.GetNames(context.Type)
|
||||
.ToList()
|
||||
@@ -121,9 +125,10 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||
Enum e = (Enum)Enum.Parse(context.Type, name);
|
||||
var descrptionOrNull = GetEnumDescription(e);
|
||||
model.Enum.Add(new OpenApiString(name));
|
||||
stringBuilder.Append($"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
|
||||
stringBuilder.Append(
|
||||
$"【枚举:{name}{(descrptionOrNull is null ? string.Empty : $"({descrptionOrNull})")}={Convert.ToInt64(Enum.Parse(context.Type, name))}】<br />");
|
||||
});
|
||||
model.Description= stringBuilder.ToString();
|
||||
model.Description = stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,13 +138,13 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||
var attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
|
||||
return attributes.Length > 0 ? attributes[0].Description : null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class AddRequiredHeaderParameter : IOperationFilter
|
||||
{
|
||||
public static string HeaderKey { get; set; } = "__tenant";
|
||||
|
||||
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||
{
|
||||
if (operation.Parameters == null)
|
||||
@@ -150,8 +155,8 @@ namespace Yi.Framework.AspNetCore.Microsoft.Extensions.DependencyInjection
|
||||
In = ParameterLocation.Header,
|
||||
Required = false,
|
||||
AllowEmptyValue = true,
|
||||
Description="租户id或者租户名称(可空为默认租户)"
|
||||
Description = "租户id或者租户名称(可空为默认租户)"
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace Yi.Framework.SqlSugarCore.Abstractions
|
||||
/// SqlSugarDb
|
||||
/// </summary>
|
||||
ISqlSugarClient SqlSugarClient { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 数据库备份
|
||||
/// </summary>
|
||||
|
||||
@@ -12,6 +12,7 @@ using Volo.Abp.Domain.Entities;
|
||||
using Volo.Abp.Domain.Entities.Events;
|
||||
using Volo.Abp.Guids;
|
||||
using Volo.Abp.MultiTenancy;
|
||||
using Volo.Abp.Uow;
|
||||
using Volo.Abp.Users;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
@@ -19,19 +20,23 @@ namespace Yi.Framework.SqlSugarCore;
|
||||
|
||||
public class DefaultSqlSugarDbContext : SqlSugarDbContext
|
||||
{
|
||||
|
||||
protected DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
|
||||
protected ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
|
||||
protected IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
|
||||
protected ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
|
||||
protected ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
|
||||
protected IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
|
||||
public IUnitOfWorkManager UnitOfWorkManager => LazyServiceProvider.LazyGetRequiredService<IUnitOfWorkManager>();
|
||||
protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
|
||||
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
|
||||
|
||||
protected IEntityChangeEventHelper EntityChangeEventHelper =>
|
||||
LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
|
||||
|
||||
public DefaultSqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
|
||||
{
|
||||
if (IsSoftDeleteFilterEnabled)
|
||||
@@ -120,7 +125,7 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
|
||||
}
|
||||
|
||||
|
||||
//领域事件
|
||||
//实体变更领域事件
|
||||
switch (entityInfo.OperationType)
|
||||
{
|
||||
case DataFilterType.InsertByObject:
|
||||
@@ -163,6 +168,14 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
//实体领域事件-所有操作类型
|
||||
if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
|
||||
{
|
||||
var eventReport = CreateEventReport(entityInfo.EntityValue);
|
||||
PublishEntityEvents(eventReport);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnLogExecuting(string sql, SugarParameter[] pars)
|
||||
@@ -204,4 +217,74 @@ public class DefaultSqlSugarDbContext : SqlSugarDbContext
|
||||
entityColumnInfo.IsPrimarykey = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建领域事件报告
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual EntityEventReport? CreateEventReport(object entity)
|
||||
{
|
||||
var eventReport = new EntityEventReport();
|
||||
|
||||
//判断是否为领域事件-聚合根
|
||||
var generatesDomainEventsEntity = entity as IGeneratesDomainEvents;
|
||||
if (generatesDomainEventsEntity == null)
|
||||
{
|
||||
return eventReport;
|
||||
}
|
||||
|
||||
var localEvents = generatesDomainEventsEntity.GetLocalEvents()?.ToArray();
|
||||
if (localEvents != null && localEvents.Any())
|
||||
{
|
||||
eventReport.DomainEvents.AddRange(
|
||||
localEvents.Select(
|
||||
eventRecord => new DomainEventEntry(
|
||||
entity,
|
||||
eventRecord.EventData,
|
||||
eventRecord.EventOrder
|
||||
)
|
||||
)
|
||||
);
|
||||
generatesDomainEventsEntity.ClearLocalEvents();
|
||||
}
|
||||
|
||||
var distributedEvents = generatesDomainEventsEntity.GetDistributedEvents()?.ToArray();
|
||||
if (distributedEvents != null && distributedEvents.Any())
|
||||
{
|
||||
eventReport.DistributedEvents.AddRange(
|
||||
distributedEvents.Select(
|
||||
eventRecord => new DomainEventEntry(
|
||||
entity,
|
||||
eventRecord.EventData,
|
||||
eventRecord.EventOrder)
|
||||
)
|
||||
);
|
||||
generatesDomainEventsEntity.ClearDistributedEvents();
|
||||
}
|
||||
|
||||
return eventReport;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发布领域事件
|
||||
/// </summary>
|
||||
/// <param name="changeReport"></param>
|
||||
private void PublishEntityEvents(EntityEventReport changeReport)
|
||||
{
|
||||
foreach (var localEvent in changeReport.DomainEvents)
|
||||
{
|
||||
UnitOfWorkManager.Current?.AddOrReplaceLocalEvent(
|
||||
new UnitOfWorkEventRecord(localEvent.EventData.GetType(), localEvent.EventData, localEvent.EventOrder)
|
||||
);
|
||||
}
|
||||
|
||||
foreach (var distributedEvent in changeReport.DistributedEvents)
|
||||
{
|
||||
UnitOfWorkManager.Current?.AddOrReplaceDistributedEvent(
|
||||
new UnitOfWorkEventRecord(distributedEvent.EventData.GetType(), distributedEvent.EventData, distributedEvent.EventOrder)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,14 @@ namespace Yi.Framework.SqlSugarCore;
|
||||
|
||||
public abstract class SqlSugarDbContext : ISqlSugarDbContextDependencies
|
||||
{
|
||||
//属性注入
|
||||
public IAbpLazyServiceProvider LazyServiceProvider { get; set; }
|
||||
protected IAbpLazyServiceProvider LazyServiceProvider { get; }
|
||||
|
||||
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
|
||||
{
|
||||
this.LazyServiceProvider = lazyServiceProvider;
|
||||
}
|
||||
|
||||
|
||||
protected ISqlSugarClient SqlSugarClient { get;private set; }
|
||||
public int ExecutionOrder => 0;
|
||||
|
||||
|
||||
@@ -37,14 +37,18 @@ namespace Yi.Framework.SqlSugarCore
|
||||
LazyServiceProvider = lazyServiceProvider;
|
||||
|
||||
var connectionString = GetCurrentConnectionString();
|
||||
|
||||
//获取连接配置操作,需要进行缓存
|
||||
var connectionConfig = ConnectionConfigCache.GetOrAdd(connectionString, (_) =>
|
||||
BuildConnectionConfig(action: options =>
|
||||
{
|
||||
options.ConnectionString = connectionString;
|
||||
options.DbType = GetCurrentDbType();
|
||||
}));
|
||||
|
||||
var connectionConfig =BuildConnectionConfig(action: options =>
|
||||
{
|
||||
options.ConnectionString = connectionString;
|
||||
options.DbType = GetCurrentDbType();
|
||||
});
|
||||
// var connectionConfig = ConnectionConfigCache.GetOrAdd(connectionString, (_) =>
|
||||
// BuildConnectionConfig(action: options =>
|
||||
// {
|
||||
// options.ConnectionString = connectionString;
|
||||
// options.DbType = GetCurrentDbType();
|
||||
// }));
|
||||
SqlSugarClient = new SqlSugarClient(connectionConfig);
|
||||
//生命周期,以下都可以直接使用sqlsugardb了
|
||||
|
||||
@@ -247,7 +251,6 @@ namespace Yi.Framework.SqlSugarCore
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public virtual void BackupDataBase()
|
||||
{
|
||||
string directoryName = "database_backup";
|
||||
|
||||
@@ -17,4 +17,4 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
||||
DbContext = dbContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,8 +35,7 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
||||
CurrentTenant = currentTenant;
|
||||
Logger = NullLogger<UnitOfWorkSqlsugarDbContextProvider<TDbContext>>.Instance;
|
||||
}
|
||||
|
||||
//private static object _databaseApiLock = new object();
|
||||
|
||||
public virtual async Task<TDbContext> GetDbContextAsync()
|
||||
{
|
||||
|
||||
@@ -48,19 +47,16 @@ namespace Yi.Framework.SqlSugarCore.Uow
|
||||
|
||||
|
||||
var unitOfWork = UnitOfWorkManager.Current;
|
||||
if (unitOfWork == null /*|| unitOfWork.Options.IsTransactional == false*/)
|
||||
if (unitOfWork == null )
|
||||
{
|
||||
var dbContext = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
|
||||
//提高体验,取消工作单元强制性
|
||||
//throw new AbpException("A DbContext can only be created inside a unit of work!");
|
||||
//var dbContext = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
|
||||
//如果不启用工作单元,创建一个新的db,不开启事务即可
|
||||
return dbContext;
|
||||
//return dbContext;
|
||||
|
||||
//2024-11-30,改回强制性使用工作单元,否则容易造成歧义
|
||||
throw new AbpException("DbContext 只能在工作单元内工作,当前DbContext没有工作单元,如需创建新线程并发操作,请手动创建工作单元");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//尝试当前工作单元获取db
|
||||
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
|
||||
|
||||
|
||||
@@ -53,10 +53,10 @@ public class AuditingStore : IAuditingStore, ITransientDependency
|
||||
protected virtual async Task SaveLogAsync(AuditLogInfo auditInfo)
|
||||
{
|
||||
Logger.LogDebug("Yi-请求追踪:" + JsonHelper.ObjToStr(auditInfo, "yyyy-MM-dd HH:mm:ss"));
|
||||
// using (var uow = UnitOfWorkManager.Begin(true,isTransactional:false))
|
||||
// {
|
||||
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
|
||||
// await uow.CompleteAsync();
|
||||
// }
|
||||
using (var uow = UnitOfWorkManager.Begin())
|
||||
{
|
||||
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
|
||||
await uow.CompleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,7 +110,9 @@ namespace Yi.Framework.Bbs.Application.Services.Analyses
|
||||
)
|
||||
.ToPageListAsync(pageIndex, input.MaxResultCount, total);
|
||||
|
||||
output.ForEach(x => { x.LevelName = _bbsUserManager._levelCacheDic[x.Level].Name; });
|
||||
var levelCache = await _bbsUserManager.GetLevelCacheMapAsync();
|
||||
|
||||
output.ForEach(x => { x.LevelName = levelCache[x.Level].Name; });
|
||||
return new PagedResultDto<MoneyTopUserDto>
|
||||
{
|
||||
Items = output,
|
||||
|
||||
@@ -158,10 +158,11 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
||||
//查询完主题之后,要过滤一下私有的主题信息
|
||||
items.ApplyPermissionTypeFilter(CurrentUser.Id ?? Guid.Empty);
|
||||
|
||||
var levelCacheDic= await _bbsUserManager.GetLevelCacheMapAsync();
|
||||
//等级、是否点赞赋值
|
||||
items?.ForEach(x =>
|
||||
{
|
||||
x.User.LevelName = _bbsUserManager._levelCacheDic[x.User.Level].Name;
|
||||
x.User.LevelName = levelCacheDic[x.User.Level].Name;
|
||||
if (CurrentUser.Id is not null)
|
||||
{
|
||||
//默认fasle
|
||||
@@ -212,7 +213,8 @@ namespace Yi.Framework.Bbs.Application.Services.Forum
|
||||
}
|
||||
}, true)
|
||||
.ToListAsync();
|
||||
output?.ForEach(x => x.User.LevelName = _bbsUserManager._levelCacheDic[x.User.Level].Name);
|
||||
var levelCacheDic= await _bbsUserManager.GetLevelCacheMapAsync();
|
||||
output?.ForEach(x => x.User.LevelName = levelCacheDic[x.User.Level].Name);
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
||||
{
|
||||
public ISqlSugarRepository<UserAggregateRoot> _userRepository;
|
||||
public ISqlSugarRepository<BbsUserExtraInfoEntity> _bbsUserInfoRepository;
|
||||
public Dictionary<int, LevelCacheItem> _levelCacheDic;
|
||||
// public Dictionary<int, LevelCacheItem> _levelCacheDic;
|
||||
private LevelManager _levelManager;
|
||||
|
||||
public BbsUserManager(ISqlSugarRepository<UserAggregateRoot> userRepository,
|
||||
ISqlSugarRepository<BbsUserExtraInfoEntity> bbsUserInfoRepository,
|
||||
@@ -23,7 +24,12 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_bbsUserInfoRepository = bbsUserInfoRepository;
|
||||
_levelCacheDic = levelManager.GetCacheMapAsync().Result;
|
||||
_levelManager = levelManager;
|
||||
}
|
||||
|
||||
public async Task<Dictionary<int, LevelCacheItem>> GetLevelCacheMapAsync()
|
||||
{
|
||||
return await _levelManager.GetCacheMapAsync();
|
||||
}
|
||||
|
||||
public async Task<BbsUserInfoDto?> GetBbsUserInfoAsync(Guid userId)
|
||||
@@ -44,7 +50,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
||||
}, true)
|
||||
.FirstAsync(user => user.Id == userId);
|
||||
|
||||
userInfo.LevelName = _levelCacheDic[userInfo.Level].Name;
|
||||
var levelCacheDic= await GetLevelCacheMapAsync();
|
||||
userInfo.LevelName = levelCacheDic[userInfo.Level].Name;
|
||||
return userInfo;
|
||||
}
|
||||
|
||||
@@ -66,7 +73,8 @@ namespace Yi.Framework.Bbs.Domain.Managers
|
||||
DiscussNumber = info.DiscussNumber
|
||||
}, true)
|
||||
.ToListAsync();
|
||||
userInfos?.ForEach(userInfo => userInfo.LevelName = _levelCacheDic[userInfo.Level].Name);
|
||||
var levelCacheDic= await GetLevelCacheMapAsync();
|
||||
userInfos?.ForEach(userInfo => userInfo.LevelName =levelCacheDic[userInfo.Level].Name);
|
||||
|
||||
return userInfos ?? new List<BbsUserInfoDto>();
|
||||
}
|
||||
|
||||
@@ -355,13 +355,13 @@ namespace Yi.Framework.Rbac.Application.Services
|
||||
{
|
||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||
output =
|
||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus).Vue3RuoYiRouterBuild();
|
||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Ruoyi).ToList()).Vue3RuoYiRouterBuild();
|
||||
}
|
||||
else if (routerType == "pure")
|
||||
{
|
||||
//将后端菜单转换成前端路由,组件级别需要过滤
|
||||
output =
|
||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus).Vue3PureRouterBuild();
|
||||
ObjectMapper.Map<List<MenuDto>, List<MenuAggregateRoot>>(menus.Where(x=>x.MenuSource==MenuSourceEnum.Pure).ToList()).Vue3PureRouterBuild();
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Yi.Framework.Rbac.Application.Services.Monitor
|
||||
{
|
||||
private ILogger<OnlineService> _logger;
|
||||
private IHubContext<OnlineHub> _hub;
|
||||
|
||||
public OnlineService(ILogger<OnlineService> logger, IHubContext<OnlineHub> hub)
|
||||
{
|
||||
_logger = logger;
|
||||
@@ -26,18 +27,21 @@ namespace Yi.Framework.Rbac.Application.Services.Monitor
|
||||
/// <returns></returns>
|
||||
public Task<PagedResultDto<OnlineUserModel>> GetListAsync([FromQuery] OnlineUserModel online)
|
||||
{
|
||||
var data = OnlineHub.clientUsers;
|
||||
IEnumerable<OnlineUserModel> dataWhere = data.AsEnumerable();
|
||||
var data = OnlineHub.ClientUsersDic;
|
||||
IEnumerable<OnlineUserModel> dataWhere = data.Values.AsEnumerable();
|
||||
|
||||
if (!string.IsNullOrEmpty(online.Ipaddr))
|
||||
{
|
||||
dataWhere = dataWhere.Where((u) => u.Ipaddr!.Contains(online.Ipaddr));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(online.UserName))
|
||||
{
|
||||
dataWhere = dataWhere.Where((u) => u.UserName!.Contains(online.UserName));
|
||||
}
|
||||
return Task.FromResult(new PagedResultDto<OnlineUserModel>() { TotalCount = data.Count, Items = dataWhere.ToList() });
|
||||
|
||||
return Task.FromResult(new PagedResultDto<OnlineUserModel>()
|
||||
{ TotalCount = data.Count, Items = dataWhere.ToList() });
|
||||
}
|
||||
|
||||
|
||||
@@ -50,13 +54,14 @@ namespace Yi.Framework.Rbac.Application.Services.Monitor
|
||||
[Route("online/{connnectionId}")]
|
||||
public async Task<bool> ForceOut(string connnectionId)
|
||||
{
|
||||
if (OnlineHub.clientUsers.Exists(u => u.ConnnectionId == connnectionId))
|
||||
if (OnlineHub.ClientUsersDic.ContainsKey(connnectionId))
|
||||
{
|
||||
//前端接受到这个事件后,触发前端自动退出
|
||||
await _hub.Clients.Client(connnectionId).SendAsync("forceOut", "你已被强制退出!");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@@ -13,53 +14,54 @@ namespace Yi.Framework.Rbac.Application.SignalRHubs
|
||||
//[Authorize]
|
||||
public class OnlineHub : AbpHub
|
||||
{
|
||||
public static readonly List<OnlineUserModel> clientUsers = new();
|
||||
private readonly static object objLock = new object();
|
||||
public static ConcurrentDictionary<string, OnlineUserModel> ClientUsersDic { get; set; } = new();
|
||||
|
||||
private HttpContext? _httpContext;
|
||||
private readonly HttpContext? _httpContext;
|
||||
private ILogger<OnlineHub> _logger => LoggerFactory.CreateLogger<OnlineHub>();
|
||||
|
||||
public OnlineHub(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContext = httpContextAccessor?.HttpContext;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 成功连接
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Task OnConnectedAsync()
|
||||
{
|
||||
lock (objLock)
|
||||
if (_httpContext is null)
|
||||
{
|
||||
var name = CurrentUser.UserName;
|
||||
var loginUser = new LoginLogAggregateRoot().GetInfoByHttpContext(_httpContext);
|
||||
|
||||
OnlineUserModel user = new(Context.ConnectionId)
|
||||
{
|
||||
Browser = loginUser?.Browser,
|
||||
LoginLocation = loginUser?.LoginLocation,
|
||||
Ipaddr = loginUser?.LoginIp,
|
||||
LoginTime = DateTime.Now,
|
||||
Os = loginUser?.Os,
|
||||
UserName = name ?? "Null",
|
||||
UserId = CurrentUser.Id ?? Guid.Empty
|
||||
};
|
||||
|
||||
//已登录
|
||||
if (CurrentUser.Id is not null)
|
||||
{ //先移除之前的用户id,一个用户只能一个
|
||||
clientUsers.RemoveAll(u => u.UserId == CurrentUser.Id);
|
||||
_logger.LogInformation($"{DateTime.Now}:{name},{Context.ConnectionId}连接服务端success,当前已连接{clientUsers.Count}个");
|
||||
}
|
||||
//全部移除之后,再进行添加
|
||||
clientUsers.RemoveAll(u => u.ConnnectionId == Context.ConnectionId);
|
||||
|
||||
clientUsers.Add(user);
|
||||
//当有人加入,向全部客户端发送当前总数
|
||||
Clients.All.SendAsync("onlineNum", clientUsers.Count);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
var name = CurrentUser.UserName;
|
||||
var loginUser = new LoginLogAggregateRoot().GetInfoByHttpContext(_httpContext);
|
||||
|
||||
OnlineUserModel user = new(Context.ConnectionId)
|
||||
{
|
||||
Browser = loginUser?.Browser,
|
||||
LoginLocation = loginUser?.LoginLocation,
|
||||
Ipaddr = loginUser?.LoginIp,
|
||||
LoginTime = DateTime.Now,
|
||||
Os = loginUser?.Os,
|
||||
UserName = name ?? "Null",
|
||||
UserId = CurrentUser.Id ?? Guid.Empty
|
||||
};
|
||||
|
||||
//已登录
|
||||
if (CurrentUser.IsAuthenticated)
|
||||
{
|
||||
ClientUsersDic.RemoveAll(u => u.Value.UserId == CurrentUser.Id);
|
||||
_logger.LogDebug(
|
||||
$"{DateTime.Now}:{name},{Context.ConnectionId}连接服务端success,当前已连接{ClientUsersDic.Count}个");
|
||||
}
|
||||
|
||||
ClientUsersDic.AddOrUpdate(Context.ConnectionId, user, (_, _) => user);
|
||||
|
||||
//当有人加入,向全部客户端发送当前总数
|
||||
Clients.All.SendAsync("onlineNum", ClientUsersDic.Count);
|
||||
|
||||
return base.OnConnectedAsync();
|
||||
}
|
||||
|
||||
@@ -69,22 +71,17 @@ namespace Yi.Framework.Rbac.Application.SignalRHubs
|
||||
/// </summary>
|
||||
/// <param name="exception"></param>
|
||||
/// <returns></returns>
|
||||
public override Task OnDisconnectedAsync(Exception exception)
|
||||
public override Task OnDisconnectedAsync(Exception? exception)
|
||||
{
|
||||
lock (objLock)
|
||||
//已登录
|
||||
if (CurrentUser.IsAuthenticated)
|
||||
{
|
||||
//已登录
|
||||
if (CurrentUser.Id is not null)
|
||||
{
|
||||
clientUsers.RemoveAll(u => u.UserId == CurrentUser.Id);
|
||||
_logger.LogInformation($"用户{CurrentUser?.UserName}离开了,当前已连接{clientUsers.Count}个");
|
||||
}
|
||||
clientUsers.RemoveAll(u => u.ConnnectionId == Context.ConnectionId);
|
||||
Clients.All.SendAsync("onlineNum", clientUsers.Count);
|
||||
ClientUsersDic.RemoveAll(u => u.Value.UserId == CurrentUser.Id);
|
||||
_logger.LogDebug($"用户{CurrentUser?.UserName}离开了,当前已连接{ClientUsersDic.Count}个");
|
||||
}
|
||||
ClientUsersDic.Remove(Context.ConnectionId, out _);
|
||||
Clients.All.SendAsync("onlineNum", ClientUsersDic.Count);
|
||||
return base.OnDisconnectedAsync(exception);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,8 @@ namespace Yi.Framework.Rbac.Domain.Shared.Dtos
|
||||
public HashSet<RoleDto> Roles { get; set; } = new();
|
||||
public HashSet<MenuDto> Menus { get; set; } = new();
|
||||
|
||||
public List<string> RoleCodes { get; set; } = new();
|
||||
public List<string> PermissionCodes { get; set; } = new();
|
||||
public HashSet<string> RoleCodes { get; set; } = new();
|
||||
public HashSet<string> PermissionCodes { get; set; } = new();
|
||||
}
|
||||
|
||||
public class UserDto
|
||||
|
||||
@@ -217,8 +217,8 @@ namespace Yi.Framework.Rbac.Domain.Managers
|
||||
}
|
||||
else
|
||||
{
|
||||
dto.PermissionCodes?.ForEach(per => AddToClaim(claims, TokenTypeConst.Permission, per));
|
||||
dto.RoleCodes?.ForEach(role => AddToClaim(claims, AbpClaimTypes.Role, role));
|
||||
dto.PermissionCodes?.ToList()?.ForEach(per => AddToClaim(claims, TokenTypeConst.Permission, per));
|
||||
dto.RoleCodes?.ToList()?.ForEach(role => AddToClaim(claims, AbpClaimTypes.Role, role));
|
||||
}
|
||||
|
||||
return claims;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using SqlSugar;
|
||||
using Volo.Abp.Data;
|
||||
using Volo.Abp.DependencyInjection;
|
||||
using Volo.Abp.Users;
|
||||
using Yi.Framework.Rbac.Domain.Authorization;
|
||||
using Yi.Framework.Rbac.Domain.Entities;
|
||||
@@ -24,6 +25,9 @@ namespace Yi.Framework.Rbac.SqlSugarCore
|
||||
}
|
||||
|
||||
|
||||
public YiRbacDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// 数据权限过滤
|
||||
/// </summary>
|
||||
@@ -86,5 +90,6 @@ namespace Yi.Framework.Rbac.SqlSugarCore
|
||||
sqlSugarClient.QueryFilter.AddTableFilter(expUser.ToExpression());
|
||||
sqlSugarClient.QueryFilter.AddTableFilter(expRole.ToExpression());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ namespace Yi.Abp.Application.Services
|
||||
public async Task GetUowAsync()
|
||||
{
|
||||
//魔改
|
||||
// 用户体验优先,万金油模式,支持高并发。支持单、多线程并发安全,支持多线程工作单元,支持多线程无工作单元,支持。。。
|
||||
// 用户体验优先,万金油模式,支持高并发。支持单、多线程并发安全,支持多线程工作单元,支持。。。
|
||||
// 不支持多线程无工作单元,应由工作单元统一管理(来自abp工作单元设计)
|
||||
// 请注意,如果requiresNew: true只有在没有工作单元内使用,嵌套子工作单元,默认值false即可
|
||||
// 自动在各个情况处理db客户端最优解之一
|
||||
int i = 3;
|
||||
@@ -78,7 +79,8 @@ namespace Yi.Abp.Application.Services
|
||||
{
|
||||
tasks.Add(Task.Run(async () =>
|
||||
{
|
||||
await sqlSugarRepository.InsertAsync(new BannerAggregateRoot { Name = "插入2" });
|
||||
//以下操作是错误的,不允许在新线程中,直接操作db,所有db操作应放在工作单元内,应由工作单元统一管理-来自abp工作单元设计
|
||||
//await sqlSugarRepository.InsertAsync(new BannerAggregateRoot { Name = "插入2" });
|
||||
using (var uow = UnitOfWorkManager.Begin(requiresNew: true, isTransactional: true))
|
||||
{
|
||||
await sqlSugarRepository.InsertAsync(new BannerAggregateRoot { Name = "插入1" });
|
||||
@@ -173,6 +175,5 @@ namespace Yi.Abp.Application.Services
|
||||
|
||||
return result ?? string.Empty;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,5 +8,8 @@ namespace Yi.Abp.SqlSugarCore
|
||||
{
|
||||
public class YiDbContext : SqlSugarDbContext
|
||||
{
|
||||
public YiDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,30 @@ namespace Yi.Abp.Web
|
||||
{
|
||||
private const string DefaultCorsPolicyName = "Default";
|
||||
|
||||
public override void PreConfigureServices(ServiceConfigurationContext context)
|
||||
{
|
||||
//动态Api-改进在pre中配置,启动更快
|
||||
PreConfigure<AbpAspNetCoreMvcOptions>(options =>
|
||||
{
|
||||
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "default");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "rbac");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "bbs");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "chat-hub");
|
||||
options.ConventionalControllers.Create(
|
||||
typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "tenant-management");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "code-gen");
|
||||
|
||||
//统一前缀
|
||||
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
|
||||
});
|
||||
}
|
||||
|
||||
public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
|
||||
{
|
||||
var configuration = context.Services.GetConfiguration();
|
||||
@@ -91,28 +115,7 @@ namespace Yi.Abp.Web
|
||||
|
||||
//配置错误处理显示详情
|
||||
Configure<AbpExceptionHandlingOptions>(options => { options.SendExceptionsDetailsToClients = true; });
|
||||
|
||||
//动态Api
|
||||
Configure<AbpAspNetCoreMvcOptions>(options =>
|
||||
{
|
||||
options.ConventionalControllers.Create(typeof(YiAbpApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "default");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkRbacApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "rbac");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkBbsApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "bbs");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkChatHubApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "chat-hub");
|
||||
options.ConventionalControllers.Create(
|
||||
typeof(YiFrameworkTenantManagementApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "tenant-management");
|
||||
options.ConventionalControllers.Create(typeof(YiFrameworkCodeGenApplicationModule).Assembly,
|
||||
options => options.RemoteServiceName = "code-gen");
|
||||
|
||||
//统一前缀
|
||||
options.ConventionalControllers.ConventionalControllerSettings.ForEach(x => x.RootPath = "api/app");
|
||||
});
|
||||
|
||||
|
||||
//【NewtonsoftJson严重问题!!!!!逆天】设置api格式,留给后人铭记
|
||||
// service.AddControllers().AddNewtonsoftJson(options =>
|
||||
// {
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace Yi.Abp.Tool.Commands
|
||||
{
|
||||
application.OnExecute(() =>
|
||||
{
|
||||
Console.WriteLine("正在克隆,请耐心等待");
|
||||
StartCmd($"git clone {CloneAddress}");
|
||||
return 0;
|
||||
});
|
||||
|
||||
@@ -36,6 +36,9 @@ namespace Yi.Abp.Tool.Commands
|
||||
var soureOption = application.Option("-s|--soure", "模板来源,gitee模板库分支名称: 默认值`default`",
|
||||
CommandOptionType.SingleValue);
|
||||
|
||||
var dbmsOption = application.Option("-dbms|--dataBaseMs", "数据库类型,支持目前主流数据库",
|
||||
CommandOptionType.SingleValue);
|
||||
|
||||
var moduleNameArgument = application.Argument("moduleName", "模块名", (_) => { });
|
||||
|
||||
//子命令,new list
|
||||
@@ -58,6 +61,11 @@ namespace Yi.Abp.Tool.Commands
|
||||
|
||||
application.OnExecute(() =>
|
||||
{
|
||||
if (dbmsOption.HasValue())
|
||||
{
|
||||
Console.WriteLine($"检测到使用数据库类型-{dbmsOption.Value()},请在生成后,只需在配置文件中,更改DbConnOptions:Url及DbType即可,支持目前主流数据库20+");
|
||||
}
|
||||
|
||||
var path = string.Empty;
|
||||
if (pathOption.HasValue())
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<Version>2.0.4</Version>
|
||||
<Version>2.0.5</Version>
|
||||
<Authors>橙子老哥</Authors>
|
||||
<Description>yi-framework框架配套工具</Description>
|
||||
<PackageProjectUrl>https://ccnetcore.com</PackageProjectUrl>
|
||||
|
||||
Reference in New Issue
Block a user