This commit is contained in:
xiaolipro 2024-12-31 17:02:03 +08:00
parent d40e83ba9c
commit 87f096e0e6
8 changed files with 131 additions and 168 deletions

View File

@ -42,5 +42,11 @@
"UserName": "dev", "UserName": "dev",
"Password": "itd!@#123" "Password": "itd!@#123"
} }
},
"ElasticSearch": {
"NodeUrls": [ "http://elasticsearch-dev.default.svc.cluster.local:9200" ],
"LoginName": "elastic",
"Password": "afyTgmVb8jq6",
"Base64PassPassword": "Basic ZWxhc3RpYzphZnlUZ21WYjhqcTY="
} }
} }

View File

@ -1,6 +1,8 @@
using Fake.Modularity; using System.Configuration;
using Fake.Modularity;
using Fake.SqlSugarCore; using Fake.SqlSugarCore;
using Fake.UnitOfWork; using Fake.UnitOfWork;
using InterfaceForward.Repositories.Log.ES;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -14,11 +16,19 @@ public class InterfaceForwardRepositoriesModule : FakeModule
{ {
var configuration = context.Services.GetConfiguration(); var configuration = context.Services.GetConfiguration();
context.Services.AddSugarDbContext<InterfaceForwardDbContext>(options => context.Services.AddSugarDbContext<InterfaceForwardDbContext>(options =>
{ {
options.ConnectionString = configuration.GetConnectionString("Default")!; options.ConnectionString = configuration.GetConnectionString("Default")!;
options.DbType = DbType.MySql; options.DbType = DbType.MySql;
}); });
context.Services.AddScoped(typeof(IBasicRepository<>), typeof(BasicRepository<>)); context.Services.AddScoped(typeof(IBasicRepository<>), typeof(BasicRepository<>));
context.Services.Configure<ElasticSearchOptions>(options =>
{
configuration.GetSection("ElasticSearch").Bind(options);
#if !DEBUG
options.ShowLogInfo = false;
#endif
});
} }
} }

View File

@ -1,97 +1,84 @@
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Reflection; using System.Reflection;
using Elasticsearch.Net; using Elasticsearch.Net;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Nest; using Nest;
namespace InterfaceForward.Repositories.Log.ES; namespace InterfaceForward.Repositories.Log.ES;
public class ConnectionFactory public class ConnectionFactory : ISingletonDependency
{ {
internal static ElasticSearchOptions _options; private readonly ILogger<ConnectionFactory> _logger;
internal static ConnectionSettings _connectionSettings; private readonly ElasticSearchOptions _options;
private static ConcurrentDictionary<Type, IElasticClient> _clientDic = new(); private readonly ConnectionSettings _connectionSettings;
private readonly ConcurrentDictionary<Type, IElasticClient> _clientDic = new();
#region
/// <summary> public ConnectionFactory(IOptions<ElasticSearchOptions> options, ILogger<ConnectionFactory> logger)
/// 构造函数
/// </summary>
/// <param name="options"></param>
public ConnectionFactory(IOptions<ElasticSearchOptions> options)
{ {
if (_options == null) _logger = logger;
_options = options.Value; _options = options.Value;
if (_connectionSettings == null) var uris = new List<Uri>();
foreach (var item in _options.NodeUrls)
{ {
var uris = new List<Uri>(); uris.Add(new Uri(item));
foreach (var item in _options.NodeUrls)
{
uris.Add(new Uri(item));
}
//using var connectionPool = new SniffingConnectionPool(uris);//集群连接池支持嗅探ping
using var connectionPool = new SingleNodeConnectionPool(uris[0]);//单点连接池
_connectionSettings = new ConnectionSettings(connectionPool).BasicAuthentication(_options.LoginName, _options.Password);
} }
}
#endregion
#region //using var connectionPool = new SniffingConnectionPool(uris);//集群连接池支持嗅探ping
using var connectionPool = new SingleNodeConnectionPool(uris[0]); //单点连接池
_connectionSettings =
new ConnectionSettings(connectionPool).BasicAuthentication(_options.LoginName, _options.Password);
}
public IElasticClient GetContext(Type type) public IElasticClient GetContext(Type type)
{ {
IElasticClient client = null;
//如果有缓存,直接从缓存返回 //如果有缓存,直接从缓存返回
if (_clientDic.ContainsKey(type)) if (_clientDic.TryGetValue(type, out var value))
{ {
client = _clientDic[type]; return value;
} }
else
IElasticClient client;
var defaultIndex = "";
var attr = type.GetCustomAttribute<ElasticsearchTypeAttribute>(false);
if (attr == null)
throw new Exception("未找到指定对象的index名称");
defaultIndex = !_options.IndexPrefix.IsNullOrWhiteSpace()
? $"{_options.IndexPrefix}{attr.RelationName}"
: attr.RelationName;
_connectionSettings.DefaultIndex(defaultIndex);
//是否输出日志
if (_options.ShowLogInfo)
{ {
var defaultIndex = ""; _connectionSettings.EnableDebugMode();
client = new ElasticClient(_connectionSettings
var attr = type.GetCustomAttribute<ElasticsearchTypeAttribute>(false); //打印请求、回复,可能影响性能
if (attr == null) .DisableDirectStreaming()
throw new Exception("未找到指定对象的index名称"); .OnRequestCompleted(apiCallDetails =>
//如果启用了index前缀
var useIndexNamePrefix = type.GetCustomAttributes(typeof(UseIndexPrefixAttribute), true).Any();
if (useIndexNamePrefix && string.IsNullOrEmpty(_options.IndexPrefix))
throw new Exception($"{type}启用了index前缀却没在配置文件中找到相关配置请检查配置项[ElasticSearchIndexPrefix]是否指定!");
defaultIndex = useIndexNamePrefix ? $"{_options.IndexPrefix}{attr.RelationName}" : attr.RelationName;
_connectionSettings.DefaultIndex(defaultIndex);
//是否输出日志
if (_options.ShowLogInfo)
{
_connectionSettings.EnableDebugMode();
client = new ElasticClient(_connectionSettings
//打印请求、回复,可能影响性能
.DisableDirectStreaming()
.OnRequestCompleted(apiCallDetails =>
{ {
string infos = GetInfosFromApiCallDetails(apiCallDetails); string infos = GetInfosFromApiCallDetails(apiCallDetails);
Console.WriteLine($"{Environment.NewLine}{infos}{Environment.NewLine}"); Console.WriteLine($"{Environment.NewLine}{infos}{Environment.NewLine}");
})); }));
}
else
{
client = new ElasticClient(_connectionSettings);
}
_clientDic.TryAdd(type, client);
} }
else
{
client = new ElasticClient(_connectionSettings);
}
_clientDic.TryAdd(type, client);
return client; return client;
} }
#region
/// <summary> /// <summary>
/// 输出执行结果 /// 输出执行结果
/// </summary> /// </summary>
@ -100,11 +87,8 @@ public class ConnectionFactory
private string GetInfosFromApiCallDetails(IApiCallDetails details) private string GetInfosFromApiCallDetails(IApiCallDetails details)
{ {
var infos = $@" var infos = $@"
|-{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")} |-{DateTime.Now:yyyy-MM-dd HH:mm:ss ffff}
|-{details.DebugInformation} "; |-{details.DebugInformation} ";
return infos; return infos;
} }
#endregion
#endregion
} }

View File

@ -4,35 +4,15 @@ namespace InterfaceForward.Repositories.Log.ES;
public abstract class ElasticSearchContextAbstract<T> : IElasticsearchClientService<T> where T : IdBaseIndex, new() public abstract class ElasticSearchContextAbstract<T> : IElasticsearchClientService<T> where T : IdBaseIndex, new()
{ {
private readonly string _indexName;
protected IElasticClient Context { get; }
#region protected ElasticSearchContextAbstract(ConnectionFactory connectionFactory)
private readonly IElasticClient _client;
private string _indexName;
public ElasticSearchContextAbstract(ConnectionFactory connectionFactory)
{ {
_client = connectionFactory.GetContext(typeof(T)); Context = connectionFactory.GetContext(typeof(T));
_indexName = _client.ConnectionSettings.DefaultIndex; _indexName = Context.ConnectionSettings.DefaultIndex;
}
#endregion
#region
public IElasticClient Context
{
get
{
return _client;
}
} }
#endregion
#region
/// <summary>
/// 新增文档
/// </summary>
/// <param name="data">索引数据</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public virtual async Task<string> IndexDocumentAsync(T data) public virtual async Task<string> IndexDocumentAsync(T data)
{ {
var response = await Context.IndexAsync(data, request => request.Index(_indexName)); var response = await Context.IndexAsync(data, request => request.Index(_indexName));
@ -42,13 +22,6 @@ public abstract class ElasticSearchContextAbstract<T> : IElasticsearchClientServ
return response.Id; return response.Id;
} }
/// <summary>
/// 批量新增文档
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public virtual async Task<BulkResponse> IndexManyDocumentAsync(List<T> list, bool refresh = false) public virtual async Task<BulkResponse> IndexManyDocumentAsync(List<T> list, bool refresh = false)
{ {
var response = await Context.IndexManyAsync<T>(list, _indexName); var response = await Context.IndexManyAsync<T>(list, _indexName);
@ -60,47 +33,22 @@ public abstract class ElasticSearchContextAbstract<T> : IElasticsearchClientServ
return response; return response;
} }
#endregion
#region Id删除文档
/// <summary>
/// 根据Id删除文档
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public virtual async Task DeleteByIdAsync(string id) public virtual async Task DeleteByIdAsync(string id)
{ {
var response = await Context.DeleteAsync<T>(id, i => i.Index(_indexName)); var response = await Context.DeleteAsync<T>(id, i => i.Index(_indexName));
if (!response.IsValid) if (!response.IsValid)
throw new Exception($"数据删除失败,原因:{response.DebugInformation}"); throw new Exception($"数据删除失败,原因:{response.DebugInformation}");
} }
#endregion
#region
/// <summary>
/// 修改指定的文档
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public virtual async Task UpdateAsync(string id, T data) public virtual async Task UpdateAsync(string id, T data)
{ {
var response = await Context.UpdateAsync<T>(id, u => u.Doc(data).Index(_indexName)); var response = await Context.UpdateAsync<T>(id, u => u.Doc(data).Index(_indexName));
if (!response.IsValid) if (!response.IsValid)
throw new Exception($"数据修改失败,原因:{response.DebugInformation}"); throw new Exception($"数据修改失败,原因:{response.DebugInformation}");
} }
#endregion
#region ID获取单条 public virtual async Task<T?> GetByIdAsync(string id)
/// <summary>
/// 根据ID获取单条文档
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
public virtual async Task<T> GetByIdAsync(string id)
{ {
var response = await Context.GetAsync<T>(id, i => i.Index(_indexName)); var response = await Context.GetAsync<T>(id, i => i.Index(_indexName));
if (response.Source != null) if (response.Source != null)
@ -108,11 +56,10 @@ public abstract class ElasticSearchContextAbstract<T> : IElasticsearchClientServ
switch (response.ApiCall.HttpStatusCode) switch (response.ApiCall.HttpStatusCode)
{ {
case 200: return response?.Source; case 200: return response.Source;
case 404: return null; case 404: return null;
default: throw new Exception($"数据查询失败,原因:{response.DebugInformation}"); default: throw new Exception($"数据查询失败,原因:{response.DebugInformation}");
} }
} }
#endregion
} }

View File

@ -5,31 +5,25 @@ public class ElasticSearchOptions
/// <summary> /// <summary>
/// 是否显示日志 /// 是否显示日志
/// </summary> /// </summary>
public bool ShowLogInfo { get; set; } = false; public bool ShowLogInfo { get; set; }
/// <summary> /// <summary>
/// 服务节点 /// 服务节点
/// </summary> /// </summary>
public List<string> NodeUrls { get; set; } public List<string> NodeUrls { get; set; } = [];
/// <summary> /// <summary>
/// 索引前缀 /// 索引前缀
/// </summary> /// </summary>
public string IndexPrefix { get; set; } public string? IndexPrefix { get; set; }
/// <summary> /// <summary>
/// 登录账号 /// 登录账号
/// </summary> /// </summary>
public string LoginName { get; set; } public string LoginName { get; set; } = null!;
/// <summary> /// <summary>
/// 登录密码(明文) /// 登录密码(明文)
/// </summary> /// </summary>
public string Password { get; set; } public string Password { get; set; } = null!;
/// <summary>
/// 登录密码(加密)
/// </summary>
public string Base64PassPassword { get; set; }
} }

View File

@ -4,10 +4,47 @@ namespace InterfaceForward.Repositories.Log.ES;
public interface IElasticsearchClientService<T> where T : class public interface IElasticsearchClientService<T> where T : class
{ {
/// <summary>
/// 新增文档
/// </summary>
/// <param name="data">索引数据</param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
Task<string> IndexDocumentAsync(T data); Task<string> IndexDocumentAsync(T data);
Task<T> GetByIdAsync(string Id);
Task UpdateAsync(string id, T input); /// <summary>
Task DeleteByIdAsync(string id); /// 批量新增文档
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="refresh"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
Task<BulkResponse> IndexManyDocumentAsync(List<T> list, bool refresh); Task<BulkResponse> IndexManyDocumentAsync(List<T> list, bool refresh);
/// <summary>
/// 根据ID获取单条文档
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
Task<T?> GetByIdAsync(string id);
/// <summary>
/// 修改指定的文档
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="id"></param>
/// <param name="data"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
Task UpdateAsync(string id, T data);
/// <summary>
/// 根据Id删除文档
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
/// <exception cref="Exception"></exception>
Task DeleteByIdAsync(string id);
} }

View File

@ -1,16 +0,0 @@
namespace InterfaceForward.Repositories.Log.ES;
[AttributeUsage(AttributeTargets.Class)]
public class UseIndexPrefixAttribute : Attribute
{
public UseIndexPrefixAttribute()
{
}
public UseIndexPrefixAttribute(string indexPrefix)
{
IndexPrefix = indexPrefix;
}
public string IndexPrefix { get; }
}

View File

@ -1,5 +1,6 @@
using InterfaceForward.Domain.Shared.Dtos; using InterfaceForward.Domain.Shared.Dtos;
using InterfaceForward.Repositories.Log.Entitys; using InterfaceForward.Repositories.Log.Entitys;
using InterfaceForward.Repositories.Log.ES;
using InterfaceForward.Repositories.Log.ValueObjects; using InterfaceForward.Repositories.Log.ValueObjects;
using Nest; using Nest;
@ -8,7 +9,7 @@ namespace InterfaceForward.Repositories.Log.Services
/// <summary> /// <summary>
/// 日志仓储 /// 日志仓储
/// </summary> /// </summary>
public interface ILogRepository public interface ILogRepository : IElasticsearchClientService<LogIndex>
{ {
/// <summary> /// <summary>
/// 应用id /// 应用id