添加项目文件。
This commit is contained in:
66
common/Tnb.Common.Core/EventBus/LogEventSubscriber.cs
Normal file
66
common/Tnb.Common.Core/EventBus/LogEventSubscriber.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using JNPF.Common.Configuration;
|
||||
using JNPF.DependencyInjection;
|
||||
using JNPF.EventBus;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 日记事件订阅.
|
||||
/// </summary>
|
||||
public class LogEventSubscriber : IEventSubscriber, ISingleton
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化客户端.
|
||||
/// </summary>
|
||||
private static SqlSugarScope? _sqlSugarClient;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
public LogEventSubscriber(ISqlSugarClient context)
|
||||
{
|
||||
_sqlSugarClient = (SqlSugarScope)context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建日记.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe("Log:CreateReLog")]
|
||||
[EventSubscribe("Log:CreateExLog")]
|
||||
[EventSubscribe("Log:CreateVisLog")]
|
||||
[EventSubscribe("Log:CreateOpLog")]
|
||||
public async Task CreateLog(EventHandlerExecutingContext context)
|
||||
{
|
||||
var log = (LogEventSource)context.Source;
|
||||
if (KeyVariable.MultiTenancy)
|
||||
{
|
||||
if (log.ConnectionConfig.ConfigId == null) return;
|
||||
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(log.ConnectionConfig));
|
||||
_sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId);
|
||||
}
|
||||
|
||||
await _sqlSugarClient.Insertable(log.Entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建任务日记.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe("Log:CreateTaskLog")]
|
||||
public async Task CreateTaskLog(EventHandlerExecutingContext context)
|
||||
{
|
||||
var log = (TaskLogEventSource)context.Source;
|
||||
if (KeyVariable.MultiTenancy)
|
||||
{
|
||||
if (log.ConnectionConfig.ConfigId == null) return;
|
||||
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(log.ConnectionConfig));
|
||||
_sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId);
|
||||
}
|
||||
|
||||
await _sqlSugarClient.Insertable(log.Entity).IgnoreColumns(ignoreNullColumn: true).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
19
common/Tnb.Common.Core/EventBus/RetryEventHandlerExecutor.cs
Normal file
19
common/Tnb.Common.Core/EventBus/RetryEventHandlerExecutor.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using JNPF.EventBus;
|
||||
using JNPF.FriendlyException;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 事件执行器-超时控制、失败重试熔断等等.
|
||||
/// </summary>
|
||||
public class RetryEventHandlerExecutor : IEventHandlerExecutor
|
||||
{
|
||||
public async Task ExecuteAsync(EventHandlerExecutingContext context, Func<EventHandlerExecutingContext, Task> handler)
|
||||
{
|
||||
// 如果执行失败,每隔 1s 重试,最多三次
|
||||
await Retry.InvokeAsync(async () =>
|
||||
{
|
||||
await handler(context);
|
||||
}, 3, 1000);
|
||||
}
|
||||
}
|
||||
55
common/Tnb.Common.Core/EventBus/Sources/LogEventSource.cs
Normal file
55
common/Tnb.Common.Core/EventBus/Sources/LogEventSource.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using JNPF.EventBus;
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 日记事件源(事件承载对象).
|
||||
/// </summary>
|
||||
public class LogEventSource : IEventSource
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
/// <param name="eventId">事件ID.</param>
|
||||
/// <param name="connectionConfig">数据库连接配置.</param>
|
||||
/// <param name="entity">实体.</param>
|
||||
public LogEventSource(string eventId, ConnectionConfigOptions connectionConfig, SysLogEntity entity)
|
||||
{
|
||||
EventId = eventId;
|
||||
ConnectionConfig = connectionConfig;
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接配置.
|
||||
/// </summary>
|
||||
public ConnectionConfigOptions ConnectionConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日记实体.
|
||||
/// </summary>
|
||||
public SysLogEntity Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件 Id.
|
||||
/// </summary>
|
||||
public string EventId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件承载(携带)数据.
|
||||
/// </summary>
|
||||
public object Payload { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 取消任务 Token.
|
||||
/// </summary>
|
||||
/// <remarks>用于取消本次消息处理.</remarks>
|
||||
public CancellationToken CancellationToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件创建时间.
|
||||
/// </summary>
|
||||
public DateTime CreatedTime { get; } = DateTime.UtcNow;
|
||||
}
|
||||
55
common/Tnb.Common.Core/EventBus/Sources/TaskEventSource.cs
Normal file
55
common/Tnb.Common.Core/EventBus/Sources/TaskEventSource.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using JNPF.EventBus;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 任务事件源.
|
||||
/// </summary>
|
||||
public class TaskEventSource : IEventSource
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
/// <param name="eventId">事件ID.</param>
|
||||
/// <param name="connectionConfig">数据库连接配置.</param>
|
||||
/// <param name="entity">实体.</param>
|
||||
public TaskEventSource(string eventId, ConnectionConfigOptions connectionConfig, TimeTaskEntity entity)
|
||||
{
|
||||
EventId = eventId;
|
||||
ConnectionConfig = connectionConfig;
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接配置.
|
||||
/// </summary>
|
||||
public ConnectionConfigOptions ConnectionConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务实体.
|
||||
/// </summary>
|
||||
public TimeTaskEntity Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件 Id.
|
||||
/// </summary>
|
||||
public string EventId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件承载(携带)数据.
|
||||
/// </summary>
|
||||
public object Payload { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 取消任务 Token.
|
||||
/// </summary>
|
||||
/// <remarks>用于取消本次消息处理.</remarks>
|
||||
public CancellationToken CancellationToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件创建时间.
|
||||
/// </summary>
|
||||
public DateTime CreatedTime { get; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using JNPF.EventBus;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 日记事件源(事件承载对象).
|
||||
/// </summary>
|
||||
public class TaskLogEventSource : IEventSource
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
/// <param name="eventId">事件ID.</param>
|
||||
/// <param name="connectionConfig">数据库连接配置.</param>
|
||||
/// <param name="entity">实体.</param>
|
||||
public TaskLogEventSource(string eventId, ConnectionConfigOptions connectionConfig, TimeTaskLogEntity entity)
|
||||
{
|
||||
EventId = eventId;
|
||||
ConnectionConfig = connectionConfig;
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接配置.
|
||||
/// </summary>
|
||||
public ConnectionConfigOptions ConnectionConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 日记实体.
|
||||
/// </summary>
|
||||
public TimeTaskLogEntity Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件 Id.
|
||||
/// </summary>
|
||||
public string EventId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件承载(携带)数据.
|
||||
/// </summary>
|
||||
public object Payload { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 取消任务 Token.
|
||||
/// </summary>
|
||||
/// <remarks>用于取消本次消息处理.</remarks>
|
||||
public CancellationToken CancellationToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件创建时间.
|
||||
/// </summary>
|
||||
public DateTime CreatedTime { get; } = DateTime.UtcNow;
|
||||
}
|
||||
55
common/Tnb.Common.Core/EventBus/Sources/UserEventSource.cs
Normal file
55
common/Tnb.Common.Core/EventBus/Sources/UserEventSource.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using JNPF.EventBus;
|
||||
using JNPF.Systems.Entitys.Permission;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 用户事件源.
|
||||
/// </summary>
|
||||
public class UserEventSource : IEventSource
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
/// <param name="eventId">事件ID.</param>
|
||||
/// <param name="connectionConfig">数据库连接配置.</param>
|
||||
/// <param name="entity">实体.</param>
|
||||
public UserEventSource(string eventId, ConnectionConfigOptions connectionConfig, UserEntity entity)
|
||||
{
|
||||
EventId = eventId;
|
||||
ConnectionConfig = connectionConfig;
|
||||
Entity = entity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接配置.
|
||||
/// </summary>
|
||||
public ConnectionConfigOptions ConnectionConfig { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户实体.
|
||||
/// </summary>
|
||||
public UserEntity Entity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件 Id.
|
||||
/// </summary>
|
||||
public string EventId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件承载(携带)数据.
|
||||
/// </summary>
|
||||
public object Payload { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 取消任务 Token.
|
||||
/// </summary>
|
||||
/// <remarks>用于取消本次消息处理.</remarks>
|
||||
public CancellationToken CancellationToken { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 事件创建时间.
|
||||
/// </summary>
|
||||
public DateTime CreatedTime { get; } = DateTime.UtcNow;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
using JNPF.Common.Security;
|
||||
using JNPF.EventBus;
|
||||
using JNPF.Logging;
|
||||
using RabbitMQ.Client;
|
||||
using RabbitMQ.Client.Events;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Channels;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// RabbitMQ 事件存储器.
|
||||
/// </summary>
|
||||
public sealed class RabbitMQEventSourceStorer : IEventSourceStorer, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// 内存通道事件源存储器.
|
||||
/// </summary>
|
||||
private readonly Channel<IEventSource> _channel;
|
||||
|
||||
/// <summary>
|
||||
/// 通道对象.
|
||||
/// </summary>
|
||||
private readonly IModel _model;
|
||||
|
||||
/// <summary>
|
||||
/// 连接对象.
|
||||
/// </summary>
|
||||
private readonly IConnection _connection;
|
||||
|
||||
/// <summary>
|
||||
/// 路由键.
|
||||
/// </summary>
|
||||
private readonly string _routeKey;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
/// <param name="factory">连接工厂.</param>
|
||||
/// <param name="routeKey">路由键.</param>
|
||||
/// <param name="capacity">存储器最多能够处理多少消息,超过该容量进入等待写入.</param>
|
||||
public RabbitMQEventSourceStorer(ConnectionFactory factory, string routeKey, int capacity)
|
||||
{
|
||||
// 配置通道,设置超出默认容量后进入等待
|
||||
var boundedChannelOptions = new BoundedChannelOptions(capacity)
|
||||
{
|
||||
FullMode = BoundedChannelFullMode.Wait
|
||||
};
|
||||
|
||||
// 创建有限容量通道
|
||||
_channel = Channel.CreateBounded<IEventSource>(boundedChannelOptions);
|
||||
|
||||
// 创建连接
|
||||
_connection = factory.CreateConnection();
|
||||
|
||||
_routeKey = routeKey;
|
||||
|
||||
// 创建通道
|
||||
_model = _connection.CreateModel();
|
||||
|
||||
string ExchangeName = "MXK_IDENTITY_MAIN_TOPIC";
|
||||
|
||||
/*
|
||||
* 声明路由队列
|
||||
* 队列可以重复声明,但是声明所使用的参数必须一致,否则会抛出异常
|
||||
* queue:队列名称
|
||||
* durable:持久化
|
||||
* exclusive:排他队列,如果一个队列被声明为排他队列,该队列仅对首次声明它的连接可见,
|
||||
* 并在连接断开时自动删除。这里需要注意三点:其一,排他队列是基于连接可见的,同一连接的不同信道是可
|
||||
* 以同时访问同一个连接创建的排他队列的。其二,“首次”,如果一个连接已经声明了一个排他队列,其他连
|
||||
* 接是不允许建立同名的排他队列的,这个与普通队列不同。其三,即使该队列是持久化的,一旦连接关闭或者
|
||||
* 客户端退出,该排他队列都会被自动删除的。这种队列适用于只限于一个客户端发送读取消息的应用场景。
|
||||
* autoDelete:自动删除
|
||||
* arguments:参数
|
||||
*/
|
||||
_model.QueueDeclare(queue: routeKey, durable: false, exclusive: false, autoDelete: false, arguments: null);
|
||||
|
||||
// 将MaxKey 交换机绑定到 路由中
|
||||
_model.QueueBind(queue: routeKey, exchange: ExchangeName, routingKey: "#");
|
||||
|
||||
// 字节限制,一次接收的消息数,全局/
|
||||
// 据说prefetchSize 和global这两项,rabbitmq没有实现,暂且不研究
|
||||
_model.BasicQos(prefetchSize: 0, prefetchCount: 1, false);
|
||||
|
||||
// 创建消息订阅者
|
||||
var consumer = new EventingBasicConsumer(_model);
|
||||
|
||||
// 订阅消息并写入内存 Channel
|
||||
consumer.Received += (ch, ea) =>
|
||||
{
|
||||
// 读取原始消息
|
||||
var stringEventSource = Encoding.UTF8.GetString(ea.Body.ToArray());
|
||||
|
||||
// 转换为 IEventSource,这里可以选择自己喜欢的序列化工具,如果自定义了 EventSource,注意属性是可读可写
|
||||
var eventSource = JsonSerializer.Deserialize<ChannelEventSource>(stringEventSource);
|
||||
|
||||
Log.Information($"- 接收到消息:{eventSource.ToJsonString()}");
|
||||
|
||||
// 写入内存管道存储器
|
||||
_channel.Writer.TryWrite(eventSource);
|
||||
|
||||
// 确认该消息已被消费
|
||||
_model.BasicAck(ea.DeliveryTag, false);
|
||||
};
|
||||
|
||||
// 启动消费者 设置为手动应答消息
|
||||
_model.BasicConsume(queue: routeKey, autoAck: true, consumer: consumer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将事件源写入存储器.
|
||||
/// </summary>
|
||||
/// <param name="eventSource">事件源对象.</param>
|
||||
/// <param name="cancellationToken">取消任务 Token.</param>
|
||||
/// <returns><see cref="ValueTask"/></returns>
|
||||
public async ValueTask WriteAsync(IEventSource eventSource, CancellationToken cancellationToken)
|
||||
{
|
||||
// 空检查
|
||||
if (eventSource == default)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(eventSource));
|
||||
}
|
||||
|
||||
// 这里判断是否是 ChannelEventSource 或者 自定义的 EventSouce
|
||||
if (eventSource is ChannelEventSource source)
|
||||
{
|
||||
// 序列化,这里可以选择自己喜欢的序列化工具
|
||||
var data = Encoding.UTF8.GetBytes(JsonSerializer.Serialize(source));
|
||||
|
||||
// 发布
|
||||
_model.BasicPublish(string.Empty, _routeKey, basicProperties: null, body: data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 这里处理动态订阅问题
|
||||
await _channel.Writer.WriteAsync(eventSource, cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 从存储器中读取一条事件源.
|
||||
/// </summary>
|
||||
/// <param name="cancellationToken">取消任务 Token.</param>
|
||||
/// <returns>事件源对象.</returns>
|
||||
public async ValueTask<IEventSource> ReadAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
// 读取一条事件源
|
||||
return await _channel.Reader.ReadAsync(cancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放非托管资源.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
_model.Dispose();
|
||||
_connection.Dispose();
|
||||
}
|
||||
}
|
||||
52
common/Tnb.Common.Core/EventBus/TaskEventSubscriber.cs
Normal file
52
common/Tnb.Common.Core/EventBus/TaskEventSubscriber.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using JNPF.Common.Configuration;
|
||||
using JNPF.DependencyInjection;
|
||||
using JNPF.EventBus;
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 任务事件订阅.
|
||||
/// </summary>
|
||||
public class TaskEventSubscriber : IEventSubscriber, ISingleton
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化客户端.
|
||||
/// </summary>
|
||||
private static SqlSugarScope? _sqlSugarClient;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
public TaskEventSubscriber(ISqlSugarClient context)
|
||||
{
|
||||
_sqlSugarClient = (SqlSugarScope)context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建任务日记.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe("Task:UpdateTask")]
|
||||
public async Task UpdateTask(EventHandlerExecutingContext context)
|
||||
{
|
||||
var log = (TaskEventSource)context.Source;
|
||||
if (KeyVariable.MultiTenancy)
|
||||
{
|
||||
if (log.ConnectionConfig.ConfigId == null) return;
|
||||
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(log.ConnectionConfig));
|
||||
_sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId);
|
||||
}
|
||||
|
||||
await _sqlSugarClient.Updateable<TimeTaskEntity>().SetColumns(x => new TimeTaskEntity()
|
||||
{
|
||||
RunCount = x.RunCount + 1,
|
||||
LastRunTime = DateTime.Now,
|
||||
NextRunTime = log.Entity.NextRunTime,
|
||||
LastModifyUserId = "admin",
|
||||
LastModifyTime = DateTime.Now
|
||||
}).Where(x => x.Id == log.Entity.Id).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
55
common/Tnb.Common.Core/EventBus/UserEventSubscriber.cs
Normal file
55
common/Tnb.Common.Core/EventBus/UserEventSubscriber.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using JNPF.Common.Configuration;
|
||||
using JNPF.DependencyInjection;
|
||||
using JNPF.EventBus;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.EventHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 用户事件订阅.
|
||||
/// </summary>
|
||||
public class UserEventSubscriber : IEventSubscriber, ISingleton
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化客户端.
|
||||
/// </summary>
|
||||
private static SqlSugarScope? _sqlSugarClient;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
public UserEventSubscriber(ISqlSugarClient context)
|
||||
{
|
||||
_sqlSugarClient = (SqlSugarScope)context;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改用户登录信息.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe("User:UpdateUserLogin")]
|
||||
public async Task UpdateUserLoginInfo(EventHandlerExecutingContext context)
|
||||
{
|
||||
var log = (UserEventSource)context.Source;
|
||||
if (KeyVariable.MultiTenancy)
|
||||
{
|
||||
if (log.ConnectionConfig.ConfigId == null) return;
|
||||
_sqlSugarClient.AddConnection(JNPFTenantExtensions.GetConfig(log.ConnectionConfig));
|
||||
_sqlSugarClient.ChangeDatabase(log.ConnectionConfig.ConfigId);
|
||||
}
|
||||
|
||||
await _sqlSugarClient.Updateable(log.Entity).UpdateColumns(m => new { m.FirstLogIP, m.FirstLogTime, m.PrevLogTime, m.PrevLogIP, m.LastLogTime, m.LastLogIP, m.LogSuccessCount }).ExecuteCommandAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单点登录同步用户信息.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
[EventSubscribe("User:maxkey_identity")]
|
||||
public async Task ReceiveUserInfo(EventHandlerExecutingContext context)
|
||||
{
|
||||
var log = (UserEventSource)context.Source;
|
||||
}
|
||||
}
|
||||
78
common/Tnb.Common.Core/Filter/LogExceptionHandler.cs
Normal file
78
common/Tnb.Common.Core/Filter/LogExceptionHandler.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using JNPF.Common.Const;
|
||||
using JNPF.Common.Extension;
|
||||
using JNPF.Common.Net;
|
||||
using JNPF.Common.Security;
|
||||
using JNPF.DataEncryption;
|
||||
using JNPF.DependencyInjection;
|
||||
using JNPF.EventBus;
|
||||
using JNPF.EventHandler;
|
||||
using JNPF.FriendlyException;
|
||||
using JNPF.Logging.Attributes;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using System.Security.Claims;
|
||||
using SqlSugar;
|
||||
using MimeKit;
|
||||
|
||||
namespace JNPF.Common.Core.Filter;
|
||||
|
||||
/// <summary>
|
||||
/// 全局异常处理.
|
||||
/// </summary>
|
||||
public class LogExceptionHandler : IGlobalExceptionHandler, ISingleton
|
||||
{
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
|
||||
public LogExceptionHandler(IEventPublisher eventPublisher)
|
||||
{
|
||||
_eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 异步写入异常日记.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OnExceptionAsync(ExceptionContext context)
|
||||
{
|
||||
var userContext = App.User;
|
||||
var httpContext = context.HttpContext;
|
||||
var httpRequest = httpContext?.Request;
|
||||
var headers = httpRequest?.Headers;
|
||||
UserAgent userAgent = new UserAgent(httpContext);
|
||||
|
||||
if (!context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(IgnoreLogAttribute)))
|
||||
{
|
||||
ConnectionConfigOptions options = userContext?.FindFirstValue(ClaimConst.CONNECTIONCONFIG)?.ToObject<ConnectionConfigOptions>();
|
||||
string userId = userContext?.FindFirstValue(ClaimConst.CLAINMUSERID);
|
||||
string userName = userContext?.FindFirstValue(ClaimConst.CLAINMREALNAME);
|
||||
|
||||
if (!App.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||||
{
|
||||
var bearer = App.HttpContext.Request.QueryString.Value.Matches(@"[?&]token=Bearer%20([\w\.-]+)($|&)");
|
||||
if (bearer.Count() > 0)
|
||||
{
|
||||
string token = bearer.Last();
|
||||
IEnumerable<Claim> claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims;
|
||||
options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject<ConnectionConfigOptions>();
|
||||
userId = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMUSERID)?.Value;
|
||||
userName = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMREALNAME)?.Value;
|
||||
}
|
||||
}
|
||||
|
||||
await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateExLog", options, new SysLogEntity
|
||||
{
|
||||
Id = SnowflakeIdHelper.NextId(),
|
||||
UserId = userId,
|
||||
UserName = userName,
|
||||
Category = 4,
|
||||
IPAddress = NetHelper.Ip,
|
||||
RequestURL = httpRequest.Path,
|
||||
RequestMethod = httpRequest.Method,
|
||||
Json = context.Exception.Message + "\n" + context.Exception.StackTrace + "\n" + context.Exception.TargetSite.GetParameters().ToString(),
|
||||
PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue),
|
||||
CreatorTime = DateTime.Now
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
115
common/Tnb.Common.Core/Filter/RequestActionFilter.cs
Normal file
115
common/Tnb.Common.Core/Filter/RequestActionFilter.cs
Normal file
@@ -0,0 +1,115 @@
|
||||
using JNPF.Common.Const;
|
||||
using JNPF.Common.Extension;
|
||||
using JNPF.Common.Net;
|
||||
using JNPF.Common.Security;
|
||||
using JNPF.DataEncryption;
|
||||
using JNPF.EventBus;
|
||||
using JNPF.EventHandler;
|
||||
using JNPF.Logging.Attributes;
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System.Diagnostics;
|
||||
using System.Security.Claims;
|
||||
using SqlSugar;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using JNPF.Logging;
|
||||
|
||||
namespace JNPF.Common.Core.Filter;
|
||||
|
||||
/// <summary>
|
||||
/// 请求日志拦截.
|
||||
/// </summary>
|
||||
public class RequestActionFilter : IAsyncActionFilter
|
||||
{
|
||||
private readonly IEventPublisher _eventPublisher;
|
||||
|
||||
public RequestActionFilter(IEventPublisher eventPublisher)
|
||||
{
|
||||
_eventPublisher = eventPublisher;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求日记写入.
|
||||
/// </summary>
|
||||
/// <param name="context"></param>
|
||||
/// <param name="next"></param>
|
||||
/// <returns></returns>
|
||||
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
|
||||
{
|
||||
var userContext = App.User;
|
||||
var httpContext = context.HttpContext;
|
||||
var httpRequest = httpContext.Request;
|
||||
UserAgent userAgent = new UserAgent(httpContext);
|
||||
var actionDes = (ControllerActionDescriptor)context.ActionDescriptor;
|
||||
var actionName = $"{actionDes.ControllerTypeInfo.FullName}.{actionDes.MethodInfo.Name}";
|
||||
|
||||
Stopwatch sw = new Stopwatch();
|
||||
Log.Information("Action Starting: {0}({1})", actionName, context.ActionArguments.ToJsonString());
|
||||
sw.Start();
|
||||
var actionContext = await next();
|
||||
sw.Stop();
|
||||
Log.Information("Action Finished: {0}() - Elapsed: {1:F2}ms", actionName, sw.ElapsedMilliseconds);
|
||||
|
||||
// 判断是否请求成功(没有异常就是请求成功)
|
||||
var isRequestSucceed = actionContext.Exception == null;
|
||||
var headers = httpRequest.Headers;
|
||||
if (!context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(IgnoreLogAttribute)))
|
||||
{
|
||||
ConnectionConfigOptions options = userContext?.FindFirstValue(ClaimConst.CONNECTIONCONFIG)?.ToObject<ConnectionConfigOptions>();
|
||||
var userId = userContext?.FindFirstValue(ClaimConst.CLAINMUSERID);
|
||||
var userName = userContext?.FindFirstValue(ClaimConst.CLAINMREALNAME);
|
||||
|
||||
if (!App.HttpContext.Request.Headers.ContainsKey("Authorization"))
|
||||
{
|
||||
var bearer = App.HttpContext.Request.QueryString.Value.Matches(@"[?&]token=Bearer%20([\w\.-]+)($|&)");
|
||||
if (bearer.Count() > 0)
|
||||
{
|
||||
string token = bearer.Last();
|
||||
IEnumerable<Claim> claims = JWTEncryption.ReadJwtToken(token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims;
|
||||
options = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG).ToObject<ConnectionConfigOptions>();
|
||||
userId = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMUSERID)?.Value;
|
||||
userName = claims.FirstOrDefault(e => e.Type == ClaimConst.CLAINMREALNAME)?.Value;
|
||||
}
|
||||
}
|
||||
|
||||
await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateReLog", options, new SysLogEntity
|
||||
{
|
||||
Id = SnowflakeIdHelper.NextId(),
|
||||
UserId = userId,
|
||||
UserName = userName,
|
||||
Category = 5,
|
||||
IPAddress = NetHelper.Ip,
|
||||
RequestURL = httpRequest.Path,
|
||||
RequestDuration = (int)sw.ElapsedMilliseconds,
|
||||
RequestMethod = httpRequest.Method,
|
||||
PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue),
|
||||
CreatorTime = DateTime.Now
|
||||
}));
|
||||
|
||||
if (context.ActionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(OperateLogAttribute)))
|
||||
{
|
||||
// 操作参数
|
||||
var args = context.ActionArguments.ToJsonString();
|
||||
var result = (actionContext.Result as JsonResult)?.Value;
|
||||
var module = context.ActionDescriptor.EndpointMetadata.Where(x => x.GetType() == typeof(OperateLogAttribute)).ToList().FirstOrDefault() as OperateLogAttribute;
|
||||
|
||||
await _eventPublisher.PublishAsync(new LogEventSource("Log:CreateOpLog", options, new SysLogEntity
|
||||
{
|
||||
Id = SnowflakeIdHelper.NextId(),
|
||||
UserId = userId,
|
||||
UserName = userName,
|
||||
Category = 3,
|
||||
IPAddress = NetHelper.Ip,
|
||||
RequestURL = httpRequest.Path,
|
||||
RequestDuration = (int)sw.ElapsedMilliseconds,
|
||||
RequestMethod = module.Action,
|
||||
PlatForm = string.Format("{0}-{1}", userAgent.OS.ToString(), userAgent.RawValue),
|
||||
CreatorTime = DateTime.Now,
|
||||
ModuleName = module.ModuleName,
|
||||
Json = string.Format("{0}应用【{1}】【{2}】", module.Action, args, result?.ToJsonString())
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
964
common/Tnb.Common.Core/Manager/DataBase/DataBaseManager.cs
Normal file
964
common/Tnb.Common.Core/Manager/DataBase/DataBaseManager.cs
Normal file
@@ -0,0 +1,964 @@
|
||||
using System.Data;
|
||||
using System.Dynamic;
|
||||
using System.Text;
|
||||
using JNPF.Common.Dtos.DataBase;
|
||||
using JNPF.Common.Enums;
|
||||
using JNPF.Common.Extension;
|
||||
using JNPF.Common.Filter;
|
||||
using JNPF.Common.Models;
|
||||
using JNPF.Common.Models.VisualDev;
|
||||
using JNPF.Common.Security;
|
||||
using JNPF.DependencyInjection;
|
||||
using JNPF.FriendlyException;
|
||||
using JNPF.Systems.Entitys.Dto.Database;
|
||||
using JNPF.Systems.Entitys.Model.DataBase;
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using JNPF.VisualDev.Entitys.Dto.VisualDevModelData;
|
||||
using Mapster;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.Common.Core.Manager;
|
||||
|
||||
/// <summary>
|
||||
/// 实现切换数据库后操作.
|
||||
/// </summary>
|
||||
public class DataBaseManager : IDataBaseManager, ITransient
|
||||
{
|
||||
/// <summary>
|
||||
/// 初始化客户端.
|
||||
/// </summary>
|
||||
private static SqlSugarScope? _sqlSugarClient;
|
||||
|
||||
/// <summary>
|
||||
/// 用户管理器.
|
||||
/// </summary>
|
||||
private readonly IUserManager _userManager;
|
||||
|
||||
/// <summary>
|
||||
/// 数据库配置选项.
|
||||
/// </summary>
|
||||
private readonly ConnectionStringsOptions _connectionStrings;
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数.
|
||||
/// </summary>
|
||||
public DataBaseManager(
|
||||
IOptions<ConnectionStringsOptions> connectionOptions,
|
||||
IUserManager userManager,
|
||||
ISqlSugarClient context)
|
||||
{
|
||||
_sqlSugarClient = (SqlSugarScope)context;
|
||||
_userManager = userManager;
|
||||
_connectionStrings = connectionOptions.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库切换.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns>切库后的SqlSugarClient.</returns>
|
||||
public SqlSugarScope ChangeDataBase(DbLinkEntity link)
|
||||
{
|
||||
if (_sqlSugarClient.AsTenant().IsAnyConnection(link.Id))
|
||||
{
|
||||
_sqlSugarClient.ChangeDatabase(link.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sqlSugarClient.AddConnection(new ConnectionConfig()
|
||||
{
|
||||
ConfigId = link.Id,
|
||||
DbType = ToDbType(link.DbType),
|
||||
ConnectionString = ToConnectionString(link),
|
||||
InitKeyType = InitKeyType.Attribute,
|
||||
IsAutoCloseConnection = true
|
||||
});
|
||||
_sqlSugarClient.ChangeDatabase(link.Id);
|
||||
}
|
||||
|
||||
return _sqlSugarClient;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取多租户Link.
|
||||
/// </summary>
|
||||
/// <param name="tenantId">租户ID.</param>
|
||||
/// <param name="tenantName">租户数据库.</param>
|
||||
/// <returns></returns>
|
||||
public DbLinkEntity GetTenantDbLink(string tenantId, string tenantName)
|
||||
{
|
||||
return new DbLinkEntity
|
||||
{
|
||||
Id = tenantId,
|
||||
ServiceName = tenantName,
|
||||
DbType = _connectionStrings.DBType,
|
||||
Host = _connectionStrings.Host,
|
||||
Port = _connectionStrings.Port,
|
||||
UserName = _connectionStrings.UserName,
|
||||
Password = _connectionStrings.Password
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行Sql(查询).
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">sql语句.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> ExecuteSql(DbLinkEntity link, string strSql)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
int flag = 0;
|
||||
if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle)
|
||||
flag = await _sqlSugarClient.Ado.ExecuteCommandAsync(strSql.TrimEnd(';'));
|
||||
else
|
||||
flag = await _sqlSugarClient.Ado.ExecuteCommandAsync(strSql);
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 条件动态过滤.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">sql语句.</param>
|
||||
/// <returns>条件是否成立.</returns>
|
||||
public bool WhereDynamicFilter(DbLinkEntity link, string strSql)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
return _sqlSugarClient.Ado.SqlQuery<dynamic>(strSql).Count > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行Sql(新增、修改).
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <param name="dicList">数据.</param>
|
||||
/// <param name="primaryField">主键字段.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<int> ExecuteSql(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "")
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
int flag = 0;
|
||||
if (string.IsNullOrEmpty(primaryField))
|
||||
{
|
||||
foreach (var item in dicList) flag = await _sqlSugarClient.Insertable(item).AS(table).ExecuteCommandAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var item in dicList) flag = await _sqlSugarClient.Updateable(item).AS(table).WhereColumns(primaryField).ExecuteCommandAsync();
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行Sql 新增 并返回自增长Id.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <param name="dicList">数据.</param>
|
||||
/// <param name="primaryField">主键字段.</param>
|
||||
/// <returns>id.</returns>
|
||||
public async Task<int> ExecuteReturnIdentityAsync(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "")
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
int flag = 0;
|
||||
if (string.IsNullOrEmpty(primaryField))
|
||||
flag = await _sqlSugarClient.Insertable(dicList).AS(table).ExecuteReturnIdentityAsync();
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableModel">表对象.</param>
|
||||
/// <param name="tableFieldList">字段对象.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> Create(DbLinkEntity link, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
CreateTable(tableModel, tableFieldList);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sqlsugar添加表字段.
|
||||
/// </summary>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <param name="tableFieldList">表字段集合.</param>
|
||||
public void AddTableColumn(DbLinkEntity link, string tableName, List<DbTableFieldModel> tableFieldList)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
var cloumnList = tableFieldList.Adapt<List<DbColumnInfo>>();
|
||||
DelDataLength(cloumnList);
|
||||
foreach (var item in cloumnList)
|
||||
{
|
||||
_sqlSugarClient.DbMaintenance.AddColumn(tableName, item);
|
||||
if (_sqlSugarClient.CurrentConnectionConfig.DbType != SqlSugar.DbType.MySql)
|
||||
_sqlSugarClient.DbMaintenance.AddColumnRemark(item.DbColumnName, tableName, item.ColumnDescription);
|
||||
}
|
||||
//if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.MySql)
|
||||
// AddColumnMySql(tableName, tableFieldList);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new Exception(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <returns></returns>
|
||||
public bool Delete(DbLinkEntity link, string table)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
try
|
||||
{
|
||||
_sqlSugarClient.DbMaintenance.DropTable(table);
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 修改表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="oldTable">原数据.</param>
|
||||
/// <param name="tableModel">表对象.</param>
|
||||
/// <param name="tableFieldList">字段对象.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> Update(DbLinkEntity link, string oldTable, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
_sqlSugarClient.DbMaintenance.DropTable(oldTable);
|
||||
try
|
||||
{
|
||||
CreateTable(tableModel, tableFieldList);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据链接获取分页数据.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public PageResult<Dictionary<string, object>> GetInterFaceData(DbLinkEntity link, string strSql, VisualDevModelListQueryInput pageInput, MainBeltViceQueryModel columnDesign, List<IConditionalModel> dataPermissions, Dictionary<string, string> outColumnName = null)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
try
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle) strSql = strSql.Replace(";", string.Empty);
|
||||
|
||||
var sidx = pageInput.sidx.IsNotEmptyOrNull() && pageInput.sort.IsNotEmptyOrNull(); // 按前端参数排序
|
||||
var defaultSidx = columnDesign.defaultSidx.IsNotEmptyOrNull() && columnDesign.sort.IsNotEmptyOrNull(); // 按模板默认排序
|
||||
|
||||
var querJson = new List<IConditionalModel>();
|
||||
if (pageInput.queryJson.IsNotEmptyOrNull()) querJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.queryJson);
|
||||
|
||||
var superQueryJson = new List<IConditionalModel>();
|
||||
if (pageInput.superQueryJson.IsNotEmptyOrNull()) superQueryJson = _sqlSugarClient.Utilities.JsonToConditionalModels(pageInput.superQueryJson);
|
||||
// var sql = _sqlSugarClient.SqlQueryable<object>(strSql)
|
||||
// .Where(querJson).Where(superQueryJson).Where(dataPermissions).ToSqlString();
|
||||
DataTable dt = _sqlSugarClient.SqlQueryable<object>(strSql)
|
||||
.Where(querJson).Where(superQueryJson).Where(dataPermissions)
|
||||
.OrderByIF(sidx, pageInput.sidx + " " + pageInput.sort).OrderByIF(!sidx && defaultSidx, columnDesign.defaultSidx + " " + columnDesign.sort)
|
||||
.ToDataTablePage(pageInput.currentPage, pageInput.pageSize, ref total);
|
||||
|
||||
// 如果有字段别名 替换 ColumnName
|
||||
if (outColumnName != null && outColumnName.Count > 0)
|
||||
{
|
||||
var resultKey = string.Empty;
|
||||
for (var i = 0; i < dt.Columns.Count; i++)
|
||||
dt.Columns[i].ColumnName = outColumnName.TryGetValue(dt.Columns[i].ColumnName.ToUpper(), out resultKey) == true ? outColumnName[dt.Columns[i].ColumnName.ToUpper()] : dt.Columns[i].ColumnName.ToUpper();
|
||||
}
|
||||
|
||||
return new PageResult<Dictionary<string, object>>()
|
||||
{
|
||||
pagination = new PageResult()
|
||||
{
|
||||
currentPage = pageInput.currentPage,
|
||||
pageSize = pageInput.pageSize,
|
||||
total = total
|
||||
},
|
||||
list = dt.ToObject<List<Dictionary<string, string>>>().ToObject<List<Dictionary<string, object>>>()
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表是否存在.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <returns></returns>
|
||||
public bool IsAnyTable(DbLinkEntity link, string table)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
return _sqlSugarClient.DbMaintenance.IsAnyTable(table, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 表字段是否存在.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <param name="column">表字段名.</param>
|
||||
/// <returns></returns>
|
||||
public bool IsAnyColumn(DbLinkEntity link, string table, string column)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
return _sqlSugarClient.DbMaintenance.IsAnyColumn(table, column, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取表字段列表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <returns>TableFieldListModel.</returns>
|
||||
public List<DbTableFieldModel> GetFieldList(DbLinkEntity? link, string? tableName)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id) _sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
var list = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(tableName, false);
|
||||
return list.Adapt<List<DbTableFieldModel>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取表数据.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <returns></returns>
|
||||
public DataTable GetData(DbLinkEntity link, string tableName)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
return _sqlSugarClient.Queryable<dynamic>().AS(tableName).ToDataTable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据链接获取数据.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">sql语句.</param>
|
||||
/// <param name="parameters">参数.</param>
|
||||
/// <returns></returns>
|
||||
public DataTable GetInterFaceData(DbLinkEntity link, string strSql, params SugarParameter[] parameters)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle)
|
||||
strSql = strSql.Replace(";", string.Empty);
|
||||
|
||||
return _sqlSugarClient.Ado.GetDataTable(strSql, parameters);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
throw Oops.Oh(ErrorCode.D1511);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行增删改sql.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">sql语句.</param>
|
||||
/// <param name="parameters">参数.</param>
|
||||
public void ExecuteCommand(DbLinkEntity link, string strSql, params SugarParameter[] parameters)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
if (_sqlSugarClient.CurrentConnectionConfig.DbType == SqlSugar.DbType.Oracle)
|
||||
strSql = strSql.Replace(";", string.Empty);
|
||||
|
||||
_sqlSugarClient.Ado.ExecuteCommand(strSql, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取表信息.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <returns></returns>
|
||||
public DatabaseTableInfoOutput GetDataBaseTableInfo(DbLinkEntity link, string tableName)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
var data = new DatabaseTableInfoOutput()
|
||||
{
|
||||
tableInfo = _sqlSugarClient.DbMaintenance.GetTableInfoList(false).Find(m => m.Name == tableName).Adapt<TableInfoOutput>(),
|
||||
tableFieldList = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(tableName, false).Adapt<List<TableFieldOutput>>()
|
||||
};
|
||||
|
||||
data.tableFieldList = ViewDataTypeConversion(data.tableFieldList, _sqlSugarClient.CurrentConnectionConfig.DbType);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库表信息.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
public List<DatabaseTableListOutput> GetDBTableList(DbLinkEntity link)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
var dbType = link.DbType;
|
||||
var sql = DBTableSql(dbType);
|
||||
var modelList = _sqlSugarClient.Ado.SqlQuery<DynamicDbTableModel>(sql).ToList();
|
||||
return modelList.Select(x => new DatabaseTableListOutput { table = x.F_TABLE, tableName = x.F_TABLENAME, sum = x.F_SUM.ParseToInt() }).ToList();
|
||||
//return modelList.Adapt<List<DatabaseTableListOutput>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库表信息.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
public List<DbTableInfo> GetTableInfos(DbLinkEntity link)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
return _sqlSugarClient.DbMaintenance.GetTableInfoList(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据表分页(SQL语句).
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="dbSql">数据SQL.</param>
|
||||
/// <param name="pageIndex">页数.</param>
|
||||
/// <param name="pageSize">条数.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<dynamic> GetDataTablePage(DbLinkEntity link, string dbSql, int pageIndex, int pageSize)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
RefAsync<int> totalNumber = 0;
|
||||
var list = await _sqlSugarClient.SqlQueryable<object>(dbSql).ToDataTablePageAsync(pageIndex, pageSize, totalNumber);
|
||||
|
||||
return PageResult<dynamic>.SqlSugarPageResult(new SqlSugarPagedList<dynamic>()
|
||||
{
|
||||
list = ToDynamicList(list),
|
||||
pagination = new Pagination()
|
||||
{
|
||||
CurrentPage = pageIndex,
|
||||
PageSize = pageSize,
|
||||
Total = totalNumber
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据表分页(实体).
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">T.</typeparam>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="pageIndex">页数.</param>
|
||||
/// <param name="pageSize">条数.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<TEntity>> GetDataTablePage<TEntity>(DbLinkEntity link, int pageIndex, int pageSize)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
return await _sqlSugarClient.Queryable<TEntity>().ToPageListAsync(pageIndex, pageSize);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步数据.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="dt">同步数据.</param>
|
||||
/// <param name="table">表.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> SyncData(DbLinkEntity link, DataTable dt, string table)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
List<Dictionary<string, object>> dc = _sqlSugarClient.Utilities.DataTableToDictionaryList(dt); // 5.0.23版本支持
|
||||
var isOk = await _sqlSugarClient.Insertable(dc).AS(table).ExecuteCommandAsync();
|
||||
return isOk > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 同步表操作.
|
||||
/// </summary>
|
||||
/// <param name="linkFrom">原数据库.</param>
|
||||
/// <param name="linkTo">目前数据库.</param>
|
||||
/// <param name="table">表名称.</param>
|
||||
/// <param name="type">操作类型.</param>
|
||||
/// <param name="fieldType">数据类型.</param>
|
||||
public void SyncTable(DbLinkEntity linkFrom, DbLinkEntity linkTo, string table, int type, Dictionary<string, string> fieldType)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case 2:
|
||||
{
|
||||
if (linkFrom != null)
|
||||
_sqlSugarClient = ChangeDataBase(linkFrom);
|
||||
var columns = _sqlSugarClient.DbMaintenance.GetColumnInfosByTableName(table, false);
|
||||
if (linkTo != null)
|
||||
_sqlSugarClient = ChangeDataBase(linkTo);
|
||||
DelDataLength(columns, fieldType);
|
||||
_sqlSugarClient.DbMaintenance.CreateTable(table, columns);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
if (linkTo != null)
|
||||
_sqlSugarClient = ChangeDataBase(linkTo);
|
||||
_sqlSugarClient.DbMaintenance.TruncateTable(table);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 使用存储过程.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="stored">存储过程名称.</param>
|
||||
/// <param name="parameters">参数.</param>
|
||||
public void UseStoredProcedure(DbLinkEntity link, string stored, List<SugarParameter> parameters)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
_sqlSugarClient.Ado.UseStoredProcedure().GetDataTable(stored, parameters);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 测试数据库连接.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
public bool IsConnection(DbLinkEntity link)
|
||||
{
|
||||
if (link != null && _sqlSugarClient.CurrentConnectionConfig.ConfigId != link.Id)
|
||||
_sqlSugarClient = ChangeDataBase(link);
|
||||
|
||||
if (_sqlSugarClient.Ado.IsValidConnection())
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 视图数据类型转换.
|
||||
/// </summary>
|
||||
/// <param name="fields">字段数据.</param>
|
||||
/// <param name="databaseType">数据库类型.</param>
|
||||
public List<TableFieldOutput> ViewDataTypeConversion(List<TableFieldOutput> fields, SqlSugar.DbType databaseType)
|
||||
{
|
||||
foreach (var item in fields)
|
||||
{
|
||||
item.dataType = item.dataType.ToLower();
|
||||
switch (item.dataType)
|
||||
{
|
||||
case "string":
|
||||
{
|
||||
item.dataType = "varchar";
|
||||
if (item.dataLength.ParseToInt() > 2000)
|
||||
{
|
||||
item.dataType = "text";
|
||||
item.dataLength = "50";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case "single":
|
||||
item.dataType = "decimal";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换数据库类型.
|
||||
/// </summary>
|
||||
/// <param name="dbType">数据库类型.</param>
|
||||
/// <returns></returns>
|
||||
public SqlSugar.DbType ToDbType(string dbType)
|
||||
{
|
||||
switch (dbType.ToLower())
|
||||
{
|
||||
case "sqlserver":
|
||||
return SqlSugar.DbType.SqlServer;
|
||||
case "mysql":
|
||||
return SqlSugar.DbType.MySql;
|
||||
case "oracle":
|
||||
return SqlSugar.DbType.Oracle;
|
||||
case "dm8":
|
||||
case "dm":
|
||||
return SqlSugar.DbType.Dm;
|
||||
case "kdbndp":
|
||||
case "kingbasees":
|
||||
return SqlSugar.DbType.Kdbndp;
|
||||
case "postgresql":
|
||||
return SqlSugar.DbType.PostgreSQL;
|
||||
default:
|
||||
throw Oops.Oh(ErrorCode.D1505);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 转换连接字符串.
|
||||
/// </summary>
|
||||
/// <param name="dbLinkEntity">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
public string ToConnectionString(DbLinkEntity dbLinkEntity)
|
||||
{
|
||||
switch (dbLinkEntity.DbType.ToLower())
|
||||
{
|
||||
case "sqlserver":
|
||||
return string.Format("Data Source={0},{4};Initial Catalog={1};User ID={2};Password={3};MultipleActiveResultSets=true", dbLinkEntity.Host, dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password, dbLinkEntity.Port);
|
||||
case "oracle":
|
||||
var oracleParam = dbLinkEntity.OracleParam.ToObject<OracleParamModel>();
|
||||
return string.Format("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST={0})(PORT={1}))(CONNECT_DATA=(SERVER = DEDICATED)(SERVICE_NAME={2})));User Id={3};Password={4}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), oracleParam.oracleService, dbLinkEntity.UserName, dbLinkEntity.Password);
|
||||
case "mysql":
|
||||
return string.Format("server={0};port={1};database={2};user={3};password={4};AllowLoadLocalInfile=true", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password);
|
||||
case "dm8":
|
||||
case "dm":
|
||||
return string.Format("server={0};port={1};database={2};User Id={3};PWD={4}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password);
|
||||
case "kdbndp":
|
||||
case "kingbasees":
|
||||
return string.Format("server={0};port={1};database={2};UID={3};PWD={4}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password);
|
||||
case "postgresql":
|
||||
return string.Format("server={0};port={1};Database={2};User Id={3};Password={4}", dbLinkEntity.Host, dbLinkEntity.Port.ToString(), dbLinkEntity.ServiceName, dbLinkEntity.UserName, dbLinkEntity.Password);
|
||||
default:
|
||||
throw Oops.Oh(ErrorCode.D1505);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// DataTable转DicList.
|
||||
/// </summary>
|
||||
/// <param name="dt"></param>
|
||||
/// <returns></returns>
|
||||
private List<Dictionary<string, object>> DataTableToDicList(DataTable dt)
|
||||
{
|
||||
return dt.AsEnumerable().Select(row => dt.Columns.Cast<DataColumn>().ToDictionary(column => column.ColumnName.ToLower(), column => row[column])).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将DataTable 转换成 List<dynamic>
|
||||
/// reverse 反转:控制返回结果中是只存在 FilterField 指定的字段,还是排除.
|
||||
/// [flase 返回FilterField 指定的字段]|[true 返回结果剔除 FilterField 指定的字段]
|
||||
/// FilterField 字段过滤,FilterField 为空 忽略 reverse 参数;返回DataTable中的全部数
|
||||
/// </summary>
|
||||
/// <param name="table">DataTable</param>
|
||||
/// <param name="reverse">
|
||||
/// 反转:控制返回结果中是只存在 FilterField 指定的字段,还是排除.
|
||||
/// [flase 返回FilterField 指定的字段]|[true 返回结果剔除 FilterField 指定的字段]
|
||||
/// </param>
|
||||
/// <param name="FilterField">字段过滤,FilterField 为空 忽略 reverse 参数;返回DataTable中的全部数据</param>
|
||||
/// <returns>List<dynamic></dynamic></returns>
|
||||
public static List<dynamic> ToDynamicList(DataTable table, bool reverse = true, params string[] FilterField)
|
||||
{
|
||||
var modelList = new List<dynamic>();
|
||||
foreach (DataRow row in table.Rows)
|
||||
{
|
||||
dynamic model = new ExpandoObject();
|
||||
var dict = (IDictionary<string, object>)model;
|
||||
foreach (DataColumn column in table.Columns)
|
||||
{
|
||||
if (FilterField.Length != 0)
|
||||
{
|
||||
if (reverse)
|
||||
{
|
||||
if (!FilterField.Contains(column.ColumnName))
|
||||
{
|
||||
dict[column.ColumnName] = row[column];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (FilterField.Contains(column.ColumnName))
|
||||
{
|
||||
dict[column.ColumnName] = row[column];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dict[column.ColumnName.ToLower()] = row[column];
|
||||
}
|
||||
}
|
||||
|
||||
modelList.Add(model);
|
||||
}
|
||||
|
||||
return modelList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库表SQL.
|
||||
/// </summary>
|
||||
/// <param name="dbType">数据库类型.</param>
|
||||
/// <returns></returns>
|
||||
private string DBTableSql(string dbType)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
switch (dbType.ToLower())
|
||||
{
|
||||
case "sqlserver":
|
||||
//sb.Append(@"DECLARE @TABLEINFO TABLE ( NAME VARCHAR(50) , SUMROWS VARCHAR(11) , RESERVED VARCHAR(50) , DATA VARCHAR(50) , INDEX_SIZE VARCHAR(50) , UNUSED VARCHAR(50) , PK VARCHAR(50) ) DECLARE @TABLENAME TABLE ( NAME VARCHAR(50) ) DECLARE @NAME VARCHAR(50) DECLARE @PK VARCHAR(50) INSERT INTO @TABLENAME ( NAME ) SELECT O.NAME FROM SYSOBJECTS O , SYSINDEXES I WHERE O.ID = I.ID AND O.XTYPE = 'U' AND I.INDID < 2 ORDER BY I.ROWS DESC , O.NAME WHILE EXISTS ( SELECT 1 FROM @TABLENAME ) BEGIN SELECT TOP 1 @NAME = NAME FROM @TABLENAME DELETE @TABLENAME WHERE NAME = @NAME DECLARE @OBJECTID INT SET @OBJECTID = OBJECT_ID(@NAME) SELECT @PK = COL_NAME(@OBJECTID, COLID) FROM SYSOBJECTS AS O INNER JOIN SYSINDEXES AS I ON I.NAME = O.NAME INNER JOIN SYSINDEXKEYS AS K ON K.INDID = I.INDID WHERE O.XTYPE = 'PK' AND PARENT_OBJ = @OBJECTID AND K.ID = @OBJECTID INSERT INTO @TABLEINFO ( NAME , SUMROWS , RESERVED , DATA , INDEX_SIZE , UNUSED ) EXEC SYS.SP_SPACEUSED @NAME UPDATE @TABLEINFO SET PK = @PK WHERE NAME = @NAME END SELECT F.NAME AS F_TABLE,ISNULL(P.TDESCRIPTION,F.NAME) AS F_TABLENAME, F.RESERVED AS F_SIZE, RTRIM(F.SUMROWS) AS F_SUM, F.PK AS F_PRIMARYKEY FROM @TABLEINFO F LEFT JOIN ( SELECT NAME = CASE WHEN A.COLORDER = 1 THEN D.NAME ELSE '' END , TDESCRIPTION = CASE WHEN A.COLORDER = 1 THEN ISNULL(F.VALUE, '') ELSE '' END FROM SYSCOLUMNS A LEFT JOIN SYSTYPES B ON A.XUSERTYPE = B.XUSERTYPE INNER JOIN SYSOBJECTS D ON A.ID = D.ID AND D.XTYPE = 'U' AND D.NAME <> 'DTPROPERTIES' LEFT JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID WHERE A.COLORDER = 1 AND F.MINOR_ID = 0 ) P ON F.NAME = P.NAME WHERE 1 = 1 ORDER BY F_TABLE");
|
||||
sb.Append(@"SELECT s.Name F_TABLE, Convert(nvarchar(max), tbp.value) as F_TABLENAME, b.ROWS F_SUM FROM sysobjects s LEFT JOIN sys.extended_properties as tbp ON s.id = tbp.major_id and tbp.minor_id = 0 AND ( tbp.Name = 'MS_Description' OR tbp.Name is null ) LEFT JOIN sysindexes AS b ON s.id = b.id WHERE s.xtype IN('U') AND (b.indid IN (0, 1))");
|
||||
break;
|
||||
case "oracle":
|
||||
//sb.Append(@"SELECT DISTINCT COL.TABLE_NAME AS F_TABLE,TAB.COMMENTS AS F_TABLENAME,0 AS F_SIZE,NVL(T.NUM_ROWS,0)AS F_SUM,COLUMN_NAME AS F_PRIMARYKEY FROM USER_CONS_COLUMNS COL INNER JOIN USER_CONSTRAINTS CON ON CON.CONSTRAINT_NAME=COL.CONSTRAINT_NAME INNER JOIN USER_TAB_COMMENTS TAB ON TAB.TABLE_NAME=COL.TABLE_NAME INNER JOIN USER_TABLES T ON T.TABLE_NAME=COL.TABLE_NAME WHERE CON.CONSTRAINT_TYPE NOT IN('C','R')ORDER BY COL.TABLE_NAME");
|
||||
sb.Append(@"SELECT table_name F_TABLE , (select COMMENTS from user_tab_comments where t.table_name=table_name ) as F_TABLENAME, T.NUM_ROWS F_SUM from user_tables t where table_name!='HELP' AND table_name NOT LIKE '%$%' AND table_name NOT LIKE 'LOGMNRC_%' AND table_name!='LOGMNRP_CTAS_PART_MAP' AND table_name!='LOGMNR_LOGMNR_BUILDLOG' AND table_name!='SQLPLUS_PRODUCT_PROFILE'");
|
||||
break;
|
||||
case "mysql":
|
||||
//sb.Append(@"SELECT T1.*,(SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.`COLUMNS`WHERE TABLE_SCHEMA=DATABASE()AND TABLE_NAME=T1.F_TABLE AND COLUMN_KEY='PRI')F_PRIMARYKEY FROM(SELECT TABLE_NAME F_TABLE,0 F_SIZE,TABLE_ROWS F_SUM,(SELECT IF(LENGTH(TRIM(TABLE_COMMENT))<1,TABLE_NAME,TABLE_COMMENT))F_TABLENAME FROM INFORMATION_SCHEMA.`TABLES`WHERE TABLE_SCHEMA=DATABASE())T1 ORDER BY T1.F_TABLE");
|
||||
sb.Append(@"select TABLE_NAME as F_TABLE,TABLE_ROWS as F_SUM ,TABLE_COMMENT as F_TABLENAME from information_schema.tables where TABLE_SCHEMA=(select database()) AND TABLE_TYPE='BASE TABLE'");
|
||||
break;
|
||||
case "dm8":
|
||||
case "dm":
|
||||
sb.Append(@"SELECT table_name F_TABLE , (select COMMENTS from user_tab_comments where t.table_name=table_name ) as F_TABLENAME, T.NUM_ROWS F_SUM from user_tables t where table_name!='HELP' AND table_name NOT LIKE '%$%' AND table_name NOT LIKE 'LOGMNRC_%' AND table_name!='LOGMNRP_CTAS_PART_MAP' AND table_name!='LOGMNR_LOGMNR_BUILDLOG' AND table_name!='SQLPLUS_PRODUCT_PROFILE'");
|
||||
break;
|
||||
case "kdbndp":
|
||||
case "kingbasees":
|
||||
sb.Append(@"select a.relname F_TABLE,a.n_live_tup F_SUM,b.description F_TABLENAME from sys_stat_user_tables a left outer join sys_description b on a.relid = b.objoid where a.schemaname='public' and b.objsubid='0'");
|
||||
break;
|
||||
case "postgresql":
|
||||
sb.Append(@"select cast(relname as varchar) as F_TABLE,reltuples as F_SUM, cast(obj_description(relfilenode,'pg_class') as varchar) as F_TABLENAME from pg_class c inner join pg_namespace n on n.oid = c.relnamespace and nspname='public' inner join pg_tables z on z.tablename=c.relname where relkind = 'r' and relname not like 'pg_%' and relname not like 'sql_%' and schemaname='public' order by relname");
|
||||
break;
|
||||
default:
|
||||
throw new Exception("不支持");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MySql创建表单+注释.
|
||||
/// </summary>
|
||||
/// <param name="tableModel">表.</param>
|
||||
/// <param name="tableFieldList">字段.</param>
|
||||
private async Task CreateTableMySql(DbTableModel tableModel, List<DbTableFieldModel> tableFieldList)
|
||||
{
|
||||
StringBuilder strSql = new StringBuilder();
|
||||
strSql.Append("CREATE TABLE `" + tableModel.table + "` (\r\n");
|
||||
foreach (var item in tableFieldList)
|
||||
{
|
||||
if (item.primaryKey && item.allowNull == 1)
|
||||
throw Oops.Oh(ErrorCode.D1509);
|
||||
strSql.Append(" `" + item.field + "` " + item.dataType.ToUpper() + "");
|
||||
if (item.dataType == "varchar" || item.dataType == "nvarchar" || item.dataType == "decimal")
|
||||
strSql.Append(" (" + item.dataLength + ") ");
|
||||
if (item.primaryKey)
|
||||
strSql.Append(" primary key ");
|
||||
if (item.allowNull != 1)
|
||||
strSql.Append(" NOT NULL ");
|
||||
else
|
||||
strSql.Append(" NULL ");
|
||||
if(item.identity)
|
||||
strSql.Append(" AUTO_INCREMENT ");
|
||||
strSql.Append("COMMENT '" + item.fieldName + "'");
|
||||
strSql.Append(",");
|
||||
}
|
||||
|
||||
strSql.Remove(strSql.Length - 1, 1);
|
||||
strSql.Append("\r\n");
|
||||
strSql.Append(") COMMENT = '" + tableModel.tableName + "';");
|
||||
await _sqlSugarClient.Ado.ExecuteCommandAsync(strSql.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// MySql创建表单+注释.
|
||||
/// </summary>
|
||||
/// <param name="table">表.</param>
|
||||
/// <param name="tableFieldList">字段.</param>
|
||||
private void AddColumnMySql(string table, List<DbTableFieldModel> tableFieldList)
|
||||
{
|
||||
StringBuilder strSql = new StringBuilder();
|
||||
foreach (var item in tableFieldList)
|
||||
{
|
||||
if (item.dataType == "varchar" || item.dataType == "nvarchar" || item.dataType == "decimal")
|
||||
strSql.AppendFormat("ALTER TABLE {0} MODIFY {1} {2}({3}) COMMENT '{4}';", table, item.field, item.dataType, item.dataLength, item.fieldName);
|
||||
else
|
||||
strSql.AppendFormat("ALTER TABLE {0} MODIFY {1} {2} COMMENT '{3}';", table, item.field, item.dataType, item.fieldName);
|
||||
}
|
||||
|
||||
_sqlSugarClient.Ado.ExecuteCommand(strSql.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// sqlsugar建表.
|
||||
/// </summary>
|
||||
/// <param name="tableModel">表.</param>
|
||||
/// <param name="tableFieldList">字段.</param>
|
||||
private void CreateTable(DbTableModel tableModel, List<DbTableFieldModel> tableFieldList)
|
||||
{
|
||||
var cloumnList = tableFieldList.Adapt<List<DbColumnInfo>>();
|
||||
DelDataLength(cloumnList);
|
||||
var isOk = _sqlSugarClient.DbMaintenance.CreateTable(tableModel.table, cloumnList);
|
||||
_sqlSugarClient.DbMaintenance.AddTableRemark(tableModel.table, tableModel.tableName);
|
||||
//mysql不需要单独添加字段注释
|
||||
if (_sqlSugarClient.CurrentConnectionConfig.DbType != SqlSugar.DbType.MySql)
|
||||
{
|
||||
foreach (var item in cloumnList)
|
||||
{
|
||||
_sqlSugarClient.DbMaintenance.AddColumnRemark(item.DbColumnName, tableModel.table, item.ColumnDescription);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除列长度(SqlSugar除了字符串其他不需要类型长度).
|
||||
/// </summary>
|
||||
/// <param name="dbColumnInfos"></param>
|
||||
private void DelDataLength(List<DbColumnInfo> dbColumnInfos, Dictionary<string, string> dataTypeDic = null)
|
||||
{
|
||||
foreach (var item in dbColumnInfos)
|
||||
{
|
||||
if (item.DataType.ToLower() != "varchar")
|
||||
item.Length = 0;
|
||||
if (item.DataType.ToLower() != "varchar")
|
||||
item.DecimalDigits = 0;
|
||||
if (dataTypeDic == null)
|
||||
{
|
||||
item.DataType = DataTypeConversion(item.DataType.ToLower(), _sqlSugarClient.CurrentConnectionConfig.DbType);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dataTypeDic.ContainsKey(item.DataType.ToLower()))
|
||||
{
|
||||
item.DataType = dataTypeDic[item.DataType.ToLower().Replace("(默认)",string.Empty)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据库数据类型转换.
|
||||
/// </summary>
|
||||
/// <param name="dataType">数据类型.</param>
|
||||
/// <param name="databaseType">数据库类型</param>
|
||||
/// <returns></returns>
|
||||
private string DataTypeConversion(string dataType, SqlSugar.DbType databaseType)
|
||||
{
|
||||
if (databaseType.Equals(SqlSugar.DbType.Oracle))
|
||||
{
|
||||
switch (dataType)
|
||||
{
|
||||
case "text":
|
||||
return "CLOB";
|
||||
case "decimal":
|
||||
return "DECIMAL(38,38)";
|
||||
case "datetime":
|
||||
return "DATE";
|
||||
case "bigint":
|
||||
return "NUMBER";
|
||||
default:
|
||||
return dataType.ToUpper();
|
||||
}
|
||||
}
|
||||
else if (databaseType.Equals(SqlSugar.DbType.Dm))
|
||||
{
|
||||
return dataType.ToUpper();
|
||||
}
|
||||
else if (databaseType.Equals(SqlSugar.DbType.Kdbndp))
|
||||
{
|
||||
switch (dataType)
|
||||
{
|
||||
case "int":
|
||||
return "NUMBER";
|
||||
case "datetime":
|
||||
return "DATE";
|
||||
case "bigint":
|
||||
return "INT8";
|
||||
default:
|
||||
return dataType.ToUpper();
|
||||
}
|
||||
}
|
||||
else if (databaseType.Equals(SqlSugar.DbType.PostgreSQL))
|
||||
{
|
||||
switch (dataType)
|
||||
{
|
||||
case "varchar":
|
||||
return "varchar";
|
||||
case "int":
|
||||
return "INT4";
|
||||
case "datetime":
|
||||
return "timestamp";
|
||||
case "decimal":
|
||||
return "DECIMAL";
|
||||
case "bigint":
|
||||
return "INT8";
|
||||
case "text":
|
||||
return "TEXT";
|
||||
default:
|
||||
return dataType;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return dataType;
|
||||
}
|
||||
}
|
||||
}
|
||||
261
common/Tnb.Common.Core/Manager/DataBase/IDataBaseManager.cs
Normal file
261
common/Tnb.Common.Core/Manager/DataBase/IDataBaseManager.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
using System.Data;
|
||||
using JNPF.Common.Dtos.DataBase;
|
||||
using JNPF.Common.Filter;
|
||||
using JNPF.Common.Models.VisualDev;
|
||||
using JNPF.Systems.Entitys.Dto.Database;
|
||||
using JNPF.Systems.Entitys.Model.DataBase;
|
||||
using JNPF.Systems.Entitys.System;
|
||||
using JNPF.VisualDev.Entitys.Dto.VisualDevModelData;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.Common.Core.Manager;
|
||||
|
||||
/// <summary>
|
||||
/// 切换数据库抽象.
|
||||
/// </summary>
|
||||
public interface IDataBaseManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取多租户Link.
|
||||
/// </summary>
|
||||
/// <param name="tenantId">租户ID.</param>
|
||||
/// <param name="tenantName">租户数据库.</param>
|
||||
/// <returns>租户的DBLink实体对象.</returns>
|
||||
DbLinkEntity GetTenantDbLink(string tenantId, string tenantName);
|
||||
|
||||
/// <summary>
|
||||
/// 数据库切换.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns>切库后的SqlSugarClient.</returns>
|
||||
SqlSugarScope ChangeDataBase(DbLinkEntity link);
|
||||
|
||||
/// <summary>
|
||||
/// 执行Sql(查询).
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">sql语句.</param>
|
||||
/// <returns></returns>
|
||||
Task<int> ExecuteSql(DbLinkEntity link, string strSql);
|
||||
|
||||
/// <summary>
|
||||
/// 条件动态过滤.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">sql语句.</param>
|
||||
/// <returns>条件是否成立.</returns>
|
||||
bool WhereDynamicFilter(DbLinkEntity link, string strSql);
|
||||
|
||||
/// <summary>
|
||||
/// 执行Sql(新增、修改).
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <param name="dicList">数据.</param>
|
||||
/// <param name="primaryField">主键字段.</param>
|
||||
/// <returns></returns>
|
||||
Task<int> ExecuteSql(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "");
|
||||
|
||||
/// <summary>
|
||||
/// 执行Sql 新增 并返回自增长Id.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <param name="dicList">数据.</param>
|
||||
/// <param name="primaryField">主键字段.</param>
|
||||
/// <returns></returns>
|
||||
Task<int> ExecuteReturnIdentityAsync(DbLinkEntity link, string table, List<Dictionary<string, object>> dicList, string primaryField = "");
|
||||
|
||||
/// <summary>
|
||||
/// 创建表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableModel">表对象.</param>
|
||||
/// <param name="tableFieldList">字段对象.</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> Create(DbLinkEntity link, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList);
|
||||
|
||||
/// <summary>
|
||||
/// sqlsugar添加表字段.
|
||||
/// </summary>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <param name="tableFieldList">表字段集合.</param>
|
||||
void AddTableColumn(DbLinkEntity link ,string tableName, List<DbTableFieldModel> tableFieldList);
|
||||
|
||||
/// <summary>
|
||||
/// 删除表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <returns></returns>
|
||||
bool Delete(DbLinkEntity link, string table);
|
||||
|
||||
/// <summary>
|
||||
/// 修改表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="oldTable">旧表名称.</param>
|
||||
/// <param name="tableModel">表对象.</param>
|
||||
/// <param name="tableFieldList">字段对象.</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> Update(DbLinkEntity link, string oldTable, DbTableModel tableModel, List<DbTableFieldModel> tableFieldList);
|
||||
|
||||
/// <summary>
|
||||
/// 根据链接获取分页数据.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">Sql语句.</param>
|
||||
/// <param name="pageInput">页数.</param>
|
||||
/// <param name="columnDesign">列配置.</param>
|
||||
/// <param name="dataPermissions">数据权限.</param>
|
||||
/// <param name="outColumnName">输出列名称.</param>
|
||||
/// <returns></returns>
|
||||
PageResult<Dictionary<string, object>> GetInterFaceData(DbLinkEntity link, string strSql, VisualDevModelListQueryInput pageInput, MainBeltViceQueryModel columnDesign, List<IConditionalModel> dataPermissions, Dictionary<string, string> outColumnName = null);
|
||||
|
||||
/// <summary>
|
||||
/// 表是否存在.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <returns></returns>
|
||||
bool IsAnyTable(DbLinkEntity link, string table);
|
||||
|
||||
/// <summary>
|
||||
/// 表字段是否存在.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="table">表名.</param>
|
||||
/// <param name="column">表字段名.</param>
|
||||
/// <returns></returns>
|
||||
bool IsAnyColumn(DbLinkEntity link, string table, string column);
|
||||
|
||||
/// <summary>
|
||||
/// 获取表字段列表.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <returns></returns>
|
||||
List<DbTableFieldModel> GetFieldList(DbLinkEntity? link, string? tableName);
|
||||
|
||||
/// <summary>
|
||||
/// 获取表数据.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <returns></returns>
|
||||
DataTable GetData(DbLinkEntity link, string tableName);
|
||||
|
||||
/// <summary>
|
||||
/// 根据链接获取数据.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">Sql语句.</param>
|
||||
/// <param name="parameters">参数.</param>
|
||||
/// <returns></returns>
|
||||
DataTable GetInterFaceData(DbLinkEntity link, string strSql, params SugarParameter[] parameters);
|
||||
|
||||
/// <summary>
|
||||
/// 获取表信息.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="tableName">表名.</param>
|
||||
/// <returns></returns>
|
||||
DatabaseTableInfoOutput GetDataBaseTableInfo(DbLinkEntity link, string tableName);
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库表信息.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
List<DatabaseTableListOutput> GetDBTableList(DbLinkEntity link);
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据库表信息.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
List<DbTableInfo> GetTableInfos(DbLinkEntity link);
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据表分页(SQL语句).
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="dbSql">数据SQL.</param>
|
||||
/// <param name="pageIndex">页数.</param>
|
||||
/// <param name="pageSize">条数.</param>
|
||||
/// <returns></returns>
|
||||
Task<dynamic> GetDataTablePage(DbLinkEntity link, string dbSql, int pageIndex, int pageSize);
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据表分页(实体).
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity">T.</typeparam>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="pageIndex">页数.</param>
|
||||
/// <param name="pageSize">条数.</param>
|
||||
/// <returns></returns>
|
||||
Task<List<TEntity>> GetDataTablePage<TEntity>(DbLinkEntity link, int pageIndex, int pageSize);
|
||||
|
||||
/// <summary>
|
||||
/// 使用存储过程.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="stored">存储过程名称.</param>
|
||||
/// <param name="parameters">参数.</param>
|
||||
void UseStoredProcedure(DbLinkEntity link, string stored, List<SugarParameter> parameters);
|
||||
|
||||
/// <summary>
|
||||
/// 测试数据库连接.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
bool IsConnection(DbLinkEntity link);
|
||||
|
||||
/// <summary>
|
||||
/// 同步数据.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="dt">同步数据.</param>
|
||||
/// <param name="table">表.</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> SyncData(DbLinkEntity link, DataTable dt, string table);
|
||||
|
||||
/// <summary>
|
||||
/// 同步表操作.
|
||||
/// </summary>
|
||||
/// <param name="linkFrom">原数据库.</param>
|
||||
/// <param name="linkTo">目前数据库.</param>
|
||||
/// <param name="table">表名称.</param>
|
||||
/// <param name="type">操作类型.</param>
|
||||
/// <param name="fieldType">数据类型.</param>
|
||||
void SyncTable(DbLinkEntity linkFrom, DbLinkEntity linkTo, string table, int type, Dictionary<string, string> fieldType);
|
||||
|
||||
/// <summary>
|
||||
/// 视图数据类型转换.
|
||||
/// </summary>
|
||||
/// <param name="fields">字段数据.</param>
|
||||
/// <param name="databaseType">数据库类型.</param>
|
||||
List<TableFieldOutput> ViewDataTypeConversion(List<TableFieldOutput> fields, SqlSugar.DbType databaseType);
|
||||
|
||||
/// <summary>
|
||||
/// 转换数据库类型.
|
||||
/// </summary>
|
||||
/// <param name="dbType">数据库类型.</param>
|
||||
/// <returns></returns>
|
||||
SqlSugar.DbType ToDbType(string dbType);
|
||||
|
||||
/// <summary>
|
||||
/// 转换连接字符串.
|
||||
/// </summary>
|
||||
/// <param name="dbLinkEntity">数据连接.</param>
|
||||
/// <returns></returns>
|
||||
string ToConnectionString(DbLinkEntity dbLinkEntity);
|
||||
|
||||
/// <summary>
|
||||
/// 执行增删改sql.
|
||||
/// </summary>
|
||||
/// <param name="link">数据连接.</param>
|
||||
/// <param name="strSql">sql语句.</param>
|
||||
/// <param name="parameters">参数.</param>
|
||||
void ExecuteCommand(DbLinkEntity link, string strSql, params SugarParameter[] parameters);
|
||||
}
|
||||
471
common/Tnb.Common.Core/Manager/Files/FileManager.cs
Normal file
471
common/Tnb.Common.Core/Manager/Files/FileManager.cs
Normal file
@@ -0,0 +1,471 @@
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using JNPF.Common.Configuration;
|
||||
using JNPF.Common.Enums;
|
||||
using JNPF.Common.Extension;
|
||||
using JNPF.Common.Manager;
|
||||
using JNPF.Common.Models;
|
||||
using JNPF.Common.Options;
|
||||
using JNPF.Common.Security;
|
||||
using JNPF.DataEncryption;
|
||||
using JNPF.DependencyInjection;
|
||||
using JNPF.FriendlyException;
|
||||
using JNPF.RemoteRequest.Extensions;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using OnceMi.AspNetCore.OSS;
|
||||
|
||||
namespace JNPF.Common.Core.Manager.Files
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件管理.
|
||||
/// </summary>
|
||||
public class FileManager : IFileManager, IScoped
|
||||
{
|
||||
private readonly IOSSServiceFactory _oSSServiceFactory;
|
||||
private readonly IUserManager _userManager;
|
||||
private readonly ICacheManager _cacheManager;
|
||||
|
||||
/// <summary>
|
||||
/// 文件服务.
|
||||
/// </summary>
|
||||
public FileManager(
|
||||
IUserManager userManager,
|
||||
ICacheManager cacheManager,
|
||||
IOSSServiceFactory oSSServiceFactory)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_cacheManager = cacheManager;
|
||||
_oSSServiceFactory = oSSServiceFactory;
|
||||
}
|
||||
|
||||
#region OSS
|
||||
|
||||
/// <summary>
|
||||
/// 根据存储类型上传文件.
|
||||
/// </summary>
|
||||
/// <param name="stream">文件流.</param>
|
||||
/// <param name="directoryPath">保存文件夹.</param>
|
||||
/// <param name="fileName">新文件名.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> UploadFileByType(Stream stream, string directoryPath, string fileName)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bucketName = KeyVariable.BucketName; // 桶名
|
||||
var fileStoreType = KeyVariable.FileStoreType; // 文件存储类型
|
||||
var uploadPath = string.Empty; // 上传路径
|
||||
|
||||
switch (fileStoreType)
|
||||
{
|
||||
case OSSProviderType.Invalid:
|
||||
uploadPath = Path.Combine(directoryPath, fileName);
|
||||
if (!Directory.Exists(directoryPath))
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
using (var streamLocal = File.Create(uploadPath))
|
||||
{
|
||||
await stream.CopyToAsync(streamLocal);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
uploadPath = string.Format("{0}/{1}", directoryPath, fileName);
|
||||
await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).PutObjectAsync(bucketName, uploadPath, stream);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D8001);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据存储类型下载文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件路径.</param>
|
||||
/// <param name="fileDownLoadName">文件下载名.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<FileStreamResult> DownloadFileByType(string filePath, string fileDownLoadName)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (KeyVariable.FileStoreType)
|
||||
{
|
||||
case OSSProviderType.Invalid:
|
||||
return new FileStreamResult(new FileStream(filePath, FileMode.Open), "application/octet-stream") { FileDownloadName = fileDownLoadName };
|
||||
default:
|
||||
filePath = filePath.Replace(@"\", "/");
|
||||
var url = await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).PresignedGetObjectAsync(KeyVariable.BucketName, filePath, 86400);
|
||||
var (stream, encoding) = await url.GetAsStreamAsync();
|
||||
return new FileStreamResult(stream, "application/octet-stream") { FileDownloadName = fileDownLoadName };
|
||||
}
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D8003);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件前缀.</param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task<List<AnnexModel>> GetObjList(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (KeyVariable.FileStoreType)
|
||||
{
|
||||
case OSSProviderType.Invalid:
|
||||
var files = FileHelper.GetAllFiles(filePath);
|
||||
List<AnnexModel> data = new List<AnnexModel>();
|
||||
if (files != null)
|
||||
{
|
||||
for (int i = 0; i < files.Count; i++)
|
||||
{
|
||||
var item = files[i];
|
||||
AnnexModel fileModel = new AnnexModel();
|
||||
fileModel.FileId = i.ToString();
|
||||
fileModel.FileName = item.Name;
|
||||
fileModel.FileType = FileHelper.GetFileType(item);
|
||||
fileModel.FileSize = FileHelper.GetFileSize(item.FullName).ToString();
|
||||
fileModel.FileTime = item.LastWriteTime;
|
||||
data.Add(fileModel);
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
default:
|
||||
var bucketName = KeyVariable.BucketName;
|
||||
var list = await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).ListObjectsAsync(bucketName, filePath);
|
||||
return list.Select(x => new AnnexModel()
|
||||
{
|
||||
FileId = x.ETag,
|
||||
FileName = x.Key.Replace(filePath + "/", string.Empty),
|
||||
FileType = x.Key.Substring(x.Key.LastIndexOf(".") + 1),
|
||||
FileSize = x.Size.ToString(),
|
||||
FileTime = x.LastModifiedDateTime.ParseToDateTime(),
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D8000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件地址.</param>
|
||||
/// <returns></returns>
|
||||
[NonAction]
|
||||
public async Task DeleteFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (KeyVariable.FileStoreType)
|
||||
{
|
||||
case OSSProviderType.Invalid:
|
||||
FileHelper.DeleteFile(filePath);
|
||||
break;
|
||||
default:
|
||||
filePath = filePath.Replace(@"\", "/");
|
||||
var bucketName = KeyVariable.BucketName;
|
||||
await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).RemoveObjectAsync(bucketName, filePath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D1803);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 判断文件是否存在.
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件路径.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<bool> ExistsFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (KeyVariable.FileStoreType)
|
||||
{
|
||||
case OSSProviderType.Invalid:
|
||||
return FileHelper.Exists(filePath);
|
||||
default:
|
||||
filePath = filePath.Replace(@"\", "/");
|
||||
var bucketName = KeyVariable.BucketName;
|
||||
return await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).ObjectsExistsAsync(bucketName, filePath);
|
||||
}
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D8000);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件流.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<Stream> GetFileStream(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (KeyVariable.FileStoreType)
|
||||
{
|
||||
case OSSProviderType.Invalid:
|
||||
return FileHelper.FileToStream(filePath);
|
||||
default:
|
||||
filePath = filePath.Replace(@"\", "/");
|
||||
var bucketName = KeyVariable.BucketName;
|
||||
var url = await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).PresignedGetObjectAsync(bucketName, filePath, 86400);
|
||||
return (await url.GetAsStreamAsync()).Stream;
|
||||
}
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D1804);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 剪切文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath">源文件地址.</param>
|
||||
/// <param name="toFilePath">剪切地址.</param>
|
||||
/// <returns></returns>
|
||||
public async Task MoveFile(string filePath, string toFilePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (KeyVariable.FileStoreType)
|
||||
{
|
||||
case OSSProviderType.Invalid:
|
||||
FileHelper.MoveFile(filePath, toFilePath);
|
||||
break;
|
||||
default:
|
||||
filePath = filePath.Replace(@"\", "/");
|
||||
var bucketName = KeyVariable.BucketName;
|
||||
await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).CopyObjectAsync(bucketName, filePath, bucketName, toFilePath);
|
||||
await _oSSServiceFactory.Create(KeyVariable.FileStoreType.ToString()).RemoveObjectAsync(bucketName, filePath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D1804);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 导入导出(json文件)
|
||||
|
||||
/// <summary>
|
||||
/// 导出.
|
||||
/// </summary>
|
||||
/// <param name="jsonStr">json数据.</param>
|
||||
/// <param name="name">文件名.</param>
|
||||
/// <param name="exportFileType">文件后缀.</param>
|
||||
/// <returns></returns>
|
||||
public async Task<dynamic> Export(string jsonStr, string name, ExportFileType exportFileType = ExportFileType.json)
|
||||
{
|
||||
var _filePath = GetPathByType(string.Empty);
|
||||
name = DetectionSpecialStr(name);
|
||||
var _fileName = string.Format("{0}{1}.{2}", name, DateTime.Now.ParseToUnixTime(), exportFileType.ToString());
|
||||
var byteList = new UTF8Encoding(true).GetBytes(jsonStr.ToCharArray());
|
||||
var stream = new MemoryStream(byteList);
|
||||
await UploadFileByType(stream, _filePath, _fileName);
|
||||
_cacheManager.Set(_fileName, string.Empty);
|
||||
return new
|
||||
{
|
||||
name = _fileName,
|
||||
url = string.Format("/api/file/Download?encryption={0}", DESCEncryption.Encrypt(string.Format("{0}|{1}|json", _userManager.UserId, _fileName), "JNPF"))
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入.
|
||||
/// </summary>
|
||||
/// <param name="file">文件.</param>
|
||||
/// <returns></returns>
|
||||
public string Import(IFormFile file)
|
||||
{
|
||||
var stream = file.OpenReadStream();
|
||||
var byteList = new byte[file.Length];
|
||||
stream.Read(byteList, 0, (int)file.Length);
|
||||
stream.Position = 0;
|
||||
var sr = new StreamReader(stream, Encoding.Default);
|
||||
var json = sr.ReadToEnd();
|
||||
sr.Close();
|
||||
stream.Close();
|
||||
return json;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 分块式上传文件
|
||||
|
||||
/// <summary>
|
||||
/// 分片上传附件.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<dynamic> UploadChunk([FromForm] ChunkModel input)
|
||||
{
|
||||
// 碎片临时文件存储路径
|
||||
string directoryPath = Path.Combine(App.GetConfig<AppOptions>("JNPF_App", true).SystemPath, "TemporaryFile", input.identifier);
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(directoryPath))
|
||||
Directory.CreateDirectory(directoryPath);
|
||||
|
||||
// 碎片文件名称
|
||||
string chunkFileName = string.Format("{0}{1}{2}", input.identifier, "-", input.chunkNumber);
|
||||
string chunkFilePath = Path.Combine(directoryPath, chunkFileName);
|
||||
if (!FileHelper.Exists(chunkFilePath))
|
||||
{
|
||||
using (var streamLocal = File.Create(chunkFilePath))
|
||||
{
|
||||
await input.file.OpenReadStream().CopyToAsync(streamLocal);
|
||||
}
|
||||
}
|
||||
|
||||
return new { merge = input.chunkNumber == input.totalChunks };
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
FileHelper.DeleteDirectory(directoryPath);
|
||||
throw Oops.Oh(ErrorCode.D8001);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分片组装.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<FileControlsModel> Merge([FromForm] ChunkModel input)
|
||||
{
|
||||
try
|
||||
{
|
||||
input.fileName = DetectionSpecialStr(input.fileName);
|
||||
// 新文件名称
|
||||
var saveFileName = string.Format("{0}{1}{2}", DateTime.Now.ToString("yyyyMMdd"), RandomExtensions.NextLetterAndNumberString(new Random(), 5), Path.GetExtension(input.fileName));
|
||||
// 碎片临时文件存储路径
|
||||
string directoryPath = Path.Combine(App.GetConfig<AppOptions>("JNPF_App", true).SystemPath, "TemporaryFile", input.identifier);
|
||||
var chunkFiles = Directory.GetFiles(directoryPath);
|
||||
List<byte> byteSource = new List<byte>();
|
||||
var fs = new FileStream(Path.Combine(directoryPath, saveFileName), FileMode.Create);
|
||||
foreach (var part in chunkFiles.OrderBy(x => x.Length).ThenBy(x => x))
|
||||
{
|
||||
var bytes = FileHelper.ReadAllBytes(part);
|
||||
fs.Write(bytes, 0, bytes.Length);
|
||||
bytes = null;
|
||||
FileHelper.DeleteFile(part);
|
||||
}
|
||||
fs.Flush();
|
||||
fs.Close();
|
||||
Stream stream = new FileStream(Path.Combine(directoryPath, saveFileName), FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
var flag = await UploadFileByType(stream, GetPathByType(input.type), saveFileName);
|
||||
var fileSize = stream.Length;
|
||||
if (flag)
|
||||
{
|
||||
stream.Flush();
|
||||
stream.Close();
|
||||
FileHelper.DeleteDirectory(directoryPath);
|
||||
}
|
||||
return new FileControlsModel { name = saveFileName, url = string.Format("/api/file/Image/annex/{0}", saveFileName), fileExtension = input.extension, fileSize = input.fileSize.ParseToLong() };
|
||||
}
|
||||
catch (AppFriendlyException ex)
|
||||
{
|
||||
throw Oops.Oh(ErrorCode.D8003);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型获取文件存储路径.
|
||||
/// </summary>
|
||||
/// <param name="type">文件类型.</param>
|
||||
/// <returns></returns>
|
||||
public string GetPathByType(string type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case "userAvatar":
|
||||
return FileVariable.UserAvatarFilePath;
|
||||
case "mail":
|
||||
return FileVariable.EmailFilePath;
|
||||
case "IM":
|
||||
return FileVariable.IMContentFilePath;
|
||||
case "weixin":
|
||||
return FileVariable.MPMaterialFilePath;
|
||||
case "workFlow":
|
||||
case "annex":
|
||||
case "annexpic":
|
||||
return FileVariable.SystemFilePath;
|
||||
case "document":
|
||||
return FileVariable.DocumentFilePath;
|
||||
case "preview":
|
||||
return FileVariable.DocumentPreviewFilePath;
|
||||
case "screenShot":
|
||||
case "banner":
|
||||
case "bg":
|
||||
case "border":
|
||||
case "source":
|
||||
case "background":
|
||||
return FileVariable.BiVisualPath;
|
||||
case "template":
|
||||
return FileVariable.TemplateFilePath;
|
||||
case "codeGenerator":
|
||||
return FileVariable.GenerateCodePath;
|
||||
default:
|
||||
return FileVariable.TemporaryFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件大小.
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
public string GetFileSize(long size)
|
||||
{
|
||||
var fileSize = string.Empty;
|
||||
long factSize = 0;
|
||||
factSize = size;
|
||||
if (factSize < 1024.00)
|
||||
fileSize = factSize.ToString("F2") + "Byte";
|
||||
else if (factSize >= 1024.00 && factSize < 1048576)
|
||||
fileSize = (factSize / 1024.00).ToString("F2") + "KB";
|
||||
else if (factSize >= 1024.00 && factSize < 1048576)
|
||||
fileSize = (factSize / 1024.00 / 1024.00).ToString("F2") + "MB";
|
||||
else if (factSize >= 1024.00 && factSize < 1048576)
|
||||
fileSize = (factSize / 1024.00 / 1024.00 / 1024.00).ToString("F2") + "GB";
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件名特殊字符检测.
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public string DetectionSpecialStr(string fileName)
|
||||
{
|
||||
foreach (var item in KeyVariable.SpecialString)
|
||||
{
|
||||
fileName = fileName.Replace(item, string.Empty);
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
113
common/Tnb.Common.Core/Manager/Files/IFileManager.cs
Normal file
113
common/Tnb.Common.Core/Manager/Files/IFileManager.cs
Normal file
@@ -0,0 +1,113 @@
|
||||
using JNPF.Common.Enums;
|
||||
using JNPF.Common.Models;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace JNPF.Common.Core.Manager.Files
|
||||
{
|
||||
public interface IFileManager
|
||||
{
|
||||
#region 导入导出(json文件)
|
||||
|
||||
/// <summary>
|
||||
/// 导出.
|
||||
/// </summary>
|
||||
/// <param name="jsonStr">json数据.</param>
|
||||
/// <param name="name">文件名.</param>
|
||||
/// <param name="exportFileType">文件后缀.</param>
|
||||
/// <returns></returns>
|
||||
Task<dynamic> Export(string jsonStr, string name, ExportFileType exportFileType = ExportFileType.json);
|
||||
|
||||
/// <summary>
|
||||
/// 导入.
|
||||
/// </summary>
|
||||
/// <param name="file">文件.</param>
|
||||
/// <returns></returns>
|
||||
string Import(IFormFile file);
|
||||
#endregion
|
||||
|
||||
#region OSS
|
||||
|
||||
/// <summary>
|
||||
/// 根据存储类型上传文件.
|
||||
/// </summary>
|
||||
/// <param name="stream">文件流.</param>
|
||||
/// <param name="directoryPath">保存文件夹.</param>
|
||||
/// <param name="fileName">新文件名.</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> UploadFileByType(Stream stream, string directoryPath, string fileName);
|
||||
|
||||
/// <summary>
|
||||
/// 根据存储类型下载文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件路径.</param>
|
||||
/// <param name="fileDownLoadName">文件下载名.</param>
|
||||
/// <returns></returns>
|
||||
Task<FileStreamResult> DownloadFileByType(string filePath, string fileDownLoadName);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件夹下所有文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件前缀.</param>
|
||||
/// <returns></returns>
|
||||
Task<List<AnnexModel>> GetObjList(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// 删除文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
Task DeleteFile(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// 判断文件是否存在.
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件地址.</param>
|
||||
/// <returns></returns>
|
||||
Task<bool> ExistsFile(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// 获取指定文件流.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
Task<Stream> GetFileStream(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// 剪切文件.
|
||||
/// </summary>
|
||||
/// <param name="filePath">源文件地址.</param>
|
||||
/// <param name="toFilePath">剪切地址.</param>
|
||||
/// <returns></returns>
|
||||
Task MoveFile(string filePath, string toFilePath);
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 根据类型获取文件存储路径.
|
||||
/// </summary>
|
||||
/// <param name="type">文件类型.</param>
|
||||
/// <returns></returns>
|
||||
public string GetPathByType(string type);
|
||||
|
||||
/// <summary>
|
||||
/// 分片上传附件.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<dynamic> UploadChunk([FromForm] ChunkModel input);
|
||||
|
||||
/// <summary>
|
||||
/// 分片组装.
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
Task<FileControlsModel> Merge([FromForm] ChunkModel input);
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件大小.
|
||||
/// </summary>
|
||||
/// <param name="size"></param>
|
||||
/// <returns></returns>
|
||||
string GetFileSize(long size);
|
||||
}
|
||||
}
|
||||
148
common/Tnb.Common.Core/Manager/User/IUserManager.cs
Normal file
148
common/Tnb.Common.Core/Manager/User/IUserManager.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using JNPF.Common.Models.Authorize;
|
||||
using JNPF.Common.Models.User;
|
||||
using JNPF.Systems.Entitys.Permission;
|
||||
using SqlSugar;
|
||||
|
||||
namespace JNPF.Common.Core.Manager;
|
||||
|
||||
/// <summary>
|
||||
/// 用户管理抽象.
|
||||
/// </summary>
|
||||
public interface IUserManager
|
||||
{
|
||||
/// <summary>
|
||||
/// 用户编号.
|
||||
/// </summary>
|
||||
string UserId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户角色.
|
||||
/// </summary>
|
||||
List<string> Roles { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据库连接.
|
||||
/// </summary>
|
||||
ConnectionConfigOptions ConnectionConfig { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户ID.
|
||||
/// </summary>
|
||||
string TenantId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 租户数据库名称.
|
||||
/// </summary>
|
||||
string TenantDbName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户账号.
|
||||
/// </summary>
|
||||
string Account { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户昵称.
|
||||
/// </summary>
|
||||
string RealName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前用户 ToKen.
|
||||
/// </summary>
|
||||
string ToKen { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否管理员.
|
||||
/// </summary>
|
||||
bool IsAdministrator { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取请求端类型 pc 、 app.
|
||||
/// </summary>
|
||||
string UserOrigin { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户的数据范围.
|
||||
/// </summary>
|
||||
List<UserDataScopeModel> DataScope { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户当前组织及子组织.
|
||||
/// </summary>
|
||||
List<string> Subsidiary { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前用户下属.
|
||||
/// </summary>
|
||||
List<string> Subordinates { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户信息.
|
||||
/// </summary>
|
||||
UserEntity User { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取用户登录信息.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
Task<UserInfoModel> GetUserInfo();
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据条件.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体.</typeparam>
|
||||
/// <param name="moduleId">模块ID.</param>
|
||||
/// <param name="primaryKey">表主键.</param>
|
||||
/// <param name="isDataPermissions">是否开启数据权限.</param>
|
||||
/// <param name="tableNumber">联表编号.</param>
|
||||
/// <returns></returns>
|
||||
Task<List<IConditionalModel>> GetConditionAsync<T>(string moduleId, string primaryKey = "F_Id", bool isDataPermissions = true, string tableNumber = "")
|
||||
where T : new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据条件(带副表) .
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体.</typeparam>
|
||||
/// <param name="moduleId">模块ID.</param>
|
||||
/// <param name="primaryKey">表主键.</param>
|
||||
/// <param name="isDataPermissions">是否开启数据权限.</param>
|
||||
/// <returns></returns>
|
||||
Task<List<IConditionalModel>> GetDataConditionAsync<T>(string moduleId, string primaryKey, bool isDataPermissions = true)
|
||||
where T : new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据条件(在线开发专用).
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体.</typeparam>
|
||||
/// <param name="primaryKey">表主键.</param>
|
||||
/// <param name="moduleId">模块ID.</param>
|
||||
/// <param name="isDataPermissions">是否开启数据权限.</param>
|
||||
/// <returns></returns>
|
||||
Task<List<IConditionalModel>> GetCondition<T>(string primaryKey, string moduleId, bool isDataPermissions = true)
|
||||
where T : new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取代码生成数据条件.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">实体.</typeparam>
|
||||
/// <param name="moduleId">模块ID.</param>
|
||||
/// <param name="primaryKey">表主键.</param>
|
||||
/// <param name="isDataPermissions">是否开启数据权限.</param>
|
||||
/// <returns></returns>
|
||||
Task<List<CodeGenAuthorizeModuleResourceModel>> GetCodeGenAuthorizeModuleResource<T>(string moduleId, string primaryKey, bool isDataPermissions = true)
|
||||
where T : new();
|
||||
|
||||
/// <summary>
|
||||
/// 获取角色名称 根据 角色Ids.
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns></returns>
|
||||
Task<string> GetRoleNameByIds(string ids);
|
||||
|
||||
/// <summary>
|
||||
/// 根据角色Ids和组织Id 获取组织下的角色以及全局角色.
|
||||
/// </summary>
|
||||
/// <param name="roleIds">角色Id集合.</param>
|
||||
/// <param name="organizeId">组织Id.</param>
|
||||
/// <returns></returns>
|
||||
Task<List<string>> GetUserOrgRoleIds(string roleIds, string organizeId);
|
||||
}
|
||||
1801
common/Tnb.Common.Core/Manager/User/UserManager.cs
Normal file
1801
common/Tnb.Common.Core/Manager/User/UserManager.cs
Normal file
File diff suppressed because it is too large
Load Diff
22
common/Tnb.Common.Core/Mapper/Mapper.cs
Normal file
22
common/Tnb.Common.Core/Mapper/Mapper.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using JNPF.Common.Models.User;
|
||||
using JNPF.Systems.Entitys.Permission;
|
||||
using Mapster;
|
||||
|
||||
namespace JNPF.Common.Core.Mapper;
|
||||
|
||||
/// <summary>
|
||||
/// 对象映射.
|
||||
/// </summary>
|
||||
public class Mapper : IRegister
|
||||
{
|
||||
public void Register(TypeAdapterConfig config)
|
||||
{
|
||||
config.ForType<UserEntity, UserInfoModel>()
|
||||
.Map(dest => dest.userId, src => src.Id)
|
||||
.Map(dest => dest.userAccount, src => src.Account)
|
||||
.Map(dest => dest.userName, src => src.RealName)
|
||||
.Map(dest => dest.headIcon, src => "/api/File/Image/userAvatar/" + src.HeadIcon)
|
||||
.Map(dest => dest.prevLoginTime, src => src.PrevLogTime)
|
||||
.Map(dest => dest.prevLoginIPAddress, src => src.PrevLogIP);
|
||||
}
|
||||
}
|
||||
21
common/Tnb.Common.Core/Tnb.Common.Core.csproj
Normal file
21
common/Tnb.Common.Core/Tnb.Common.Core.csproj
Normal file
@@ -0,0 +1,21 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Import Project="$(SolutionDir)\common.props" />
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<GenerateDocumentationFile>False</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="RabbitMQ.Client" Version="6.4.0" />
|
||||
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\system\Tnb.Systems.Entitys\Tnb.Systems.Entitys.csproj" />
|
||||
<ProjectReference Include="..\..\visualdev\Tnb.VisualDev.Entitys\Tnb.VisualDev.Entitys.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Reference in New Issue
Block a user