😎1、优化种子初始化 2、优化重复提交特性 2、增加xml文件上传类型

This commit is contained in:
zuohuaijun 2025-01-13 10:44:39 +08:00
parent 22ef33ab6a
commit 24f67b54b4
6 changed files with 47 additions and 43 deletions

View File

@ -4,7 +4,7 @@
"Upload": { "Upload": {
"Path": "upload/{yyyy}/{MM}/{dd}", // "Path": "upload/{yyyy}/{MM}/{dd}", //
"MaxSize": 51200, // KB1024*50 "MaxSize": 51200, // KB1024*50
"ContentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "video/mp4", "application/wps-office.docx", "application/wps-office.xlsx", "application/wps-office.pptx", "application/vnd.android.package-archive" ], "ContentType": [ "image/jpg", "image/png", "image/jpeg", "image/gif", "image/bmp", "text/plain", "text/xml", "application/pdf", "application/msword", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "video/mp4", "application/wps-office.docx", "application/wps-office.xlsx", "application/wps-office.pptx", "application/vnd.android.package-archive" ],
"EnableMd5": false // MDF5- "EnableMd5": false // MDF5-
}, },
"OSSProvider": { "OSSProvider": {

View File

@ -49,7 +49,7 @@
<PackageReference Include="SSH.NET" Version="2024.2.0" /> <PackageReference Include="SSH.NET" Version="2024.2.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.5.1" /> <PackageReference Include="System.Linq.Dynamic.Core" Version="1.5.1" />
<PackageReference Include="System.Net.Http" Version="4.3.4" /> <PackageReference Include="System.Net.Http" Version="4.3.4" />
<PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1161" /> <PackageReference Include="TencentCloudSDK.Sms" Version="3.0.1162" />
<PackageReference Include="UAParser" Version="3.1.47" /> <PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup> </ItemGroup>

View File

@ -4,13 +4,15 @@
// //
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using Newtonsoft.Json;
using System.Security.Claims; using System.Security.Claims;
namespace Admin.NET.Core; namespace Admin.NET.Core;
/// <summary> /// <summary>
/// 防止重复请求过滤器特性 /// 防止重复请求过滤器特性(使用分布式锁,需确保系统支持分布式锁)
/// </summary> /// </summary>
[SuppressSniffer]
[AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)] [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = true)]
public class IdempotentAttribute : Attribute, IAsyncActionFilter public class IdempotentAttribute : Attribute, IAsyncActionFilter
{ {
@ -27,13 +29,18 @@ public class IdempotentAttribute : Attribute, IAsyncActionFilter
/// <summary> /// <summary>
/// 缓存前缀: Key+请求路由+用户Id+请求参数 /// 缓存前缀: Key+请求路由+用户Id+请求参数
/// </summary> /// </summary>
public string CacheKey { get; set; } public string CacheKey { get; set; } = CacheConst.KeyIdempotent;
/// <summary> /// <summary>
/// 是否直接抛出异常Ture是False返回上次请求结果 /// 是否直接抛出异常Ture是False返回上次请求结果
/// </summary> /// </summary>
public bool ThrowBah { get; set; } public bool ThrowBah { get; set; }
/// <summary>
/// 锁前缀
/// </summary>
public string LockPrefix { get; set; } = "lock_";
public IdempotentAttribute() public IdempotentAttribute()
{ {
} }
@ -45,46 +52,47 @@ public class IdempotentAttribute : Attribute, IAsyncActionFilter
var userId = httpContext.User?.FindFirstValue(ClaimConst.UserId); var userId = httpContext.User?.FindFirstValue(ClaimConst.UserId);
var cacheExpireTime = TimeSpan.FromSeconds(IntervalTime); var cacheExpireTime = TimeSpan.FromSeconds(IntervalTime);
var parameters = ""; var parameters = JsonConvert.SerializeObject(context.ActionArguments, Formatting.None, new JsonSerializerSettings
foreach (var parameter in context.ActionDescriptor.Parameters)
{ {
parameters += parameter.Name; NullValueHandling = NullValueHandling.Include,
parameters += context.ActionArguments[parameter.Name].ToJson(); DefaultValueHandling = DefaultValueHandling.Include
} });
var cacheKey = MD5Encryption.Encrypt($"{CacheKey}{path}{userId}{parameters}");
var sysCacheService = App.GetRequiredService<SysCacheService>();
if (sysCacheService.ExistKey(cacheKey))
{
if (ThrowBah) throw Oops.Oh(Message);
var cacheKey = CacheKey + MD5Encryption.Encrypt($"{path}{userId}{parameters}");
var sysCacheService = httpContext.RequestServices.GetService<SysCacheService>();
try try
{ {
var cachedResult = sysCacheService.Get<ResponseData>(cacheKey); // 分布式锁
context.Result = new ObjectResult(cachedResult.Value); using var distributedLock = sysCacheService.BeginCacheLock($"{LockPrefix}{cacheKey}") ?? throw Oops.Oh(Message);
}
catch (Exception ex) var cacheValue = sysCacheService.Get<ResponseData>(cacheKey);
if (cacheValue != null)
{ {
throw Oops.Oh($"{Message}-{ex}"); if (ThrowBah) throw Oops.Oh(Message);
} context.Result = new ObjectResult(cacheValue.Value);
return;
} }
else else
{ {
// 先加入一个空缓存,防止第一次请求结果没回来导致连续请求
sysCacheService.Set(cacheKey, "", cacheExpireTime);
var resultContext = await next(); var resultContext = await next();
if (resultContext.Result is ObjectResult objectResult) // 缓存请求结果 null 值不缓存
if (resultContext.Result is ObjectResult { Value: { } } objectResult)
{ {
var valueType = objectResult.Value.GetType(); var typeName = objectResult.Value.GetType().Name;
var responseData = new ResponseData var responseData = new ResponseData
{ {
Type = valueType.Name, Type = typeName,
Value = objectResult.Value Value = objectResult.Value
}; };
sysCacheService.Set(cacheKey, responseData, cacheExpireTime); sysCacheService.Set(cacheKey, responseData, cacheExpireTime);
} }
} }
} }
catch (Exception ex)
{
throw Oops.Oh($"{Message}-{ex}");
}
}
/// <summary> /// <summary>
/// 请求结果数据 /// 请求结果数据

View File

@ -96,6 +96,11 @@ public class CacheConst
/// </summary> /// </summary>
public const string KeyDict = "sys_dict:"; public const string KeyDict = "sys_dict:";
/// <summary>
/// 重复请求(幂等)字典缓存
/// </summary>
public const string KeyIdempotent = "sys_idempotent:";
/// <summary> /// <summary>
/// Excel临时文件缓存 /// Excel临时文件缓存
/// </summary> /// </summary>

View File

@ -11,9 +11,6 @@ public static class SqlSugarSetup
// 多租户实例 // 多租户实例
public static ITenant ITenant { get; set; } public static ITenant ITenant { get; set; }
// 是否正在处理种子数据
private static bool _isHandlingSeedData = false;
/// <summary> /// <summary>
/// SqlSugar 上下文初始化 /// SqlSugar 上下文初始化
/// </summary> /// </summary>
@ -206,9 +203,6 @@ public static class SqlSugarSetup
// 数据审计 // 数据审计
db.Aop.DataExecuting = (oldValue, entityInfo) => db.Aop.DataExecuting = (oldValue, entityInfo) =>
{ {
// 若正在处理种子数据则直接返回
if (_isHandlingSeedData) return;
// 新增/插入 操作 // 新增/插入 操作
if (entityInfo.OperationType == DataFilterType.InsertByObject) if (entityInfo.OperationType == DataFilterType.InsertByObject)
{ {
@ -424,7 +418,6 @@ public static class SqlSugarSetup
private static void InitSeedData(SqlSugarScope db, DbConnectionConfig config) private static void InitSeedData(SqlSugarScope db, DbConnectionConfig config)
{ {
SqlSugarScopeProvider dbProvider = db.GetConnectionScope(config.ConfigId); SqlSugarScopeProvider dbProvider = db.GetConnectionScope(config.ConfigId);
_isHandlingSeedData = true;
Log.Information($"初始化种子数据 {config.DbType} - {config.ConfigId}"); Log.Information($"初始化种子数据 {config.DbType} - {config.ConfigId}");
var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>)))) var seedDataTypes = App.EffectiveTypes.Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.GetInterfaces().Any(i => i.HasImplementedRawGeneric(typeof(ISqlSugarEntitySeedData<>))))
@ -507,8 +500,6 @@ public static class SqlSugarSetup
Console.WriteLine($"初始化种子数据 {seedType.FullName,-58} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{seedDataTypeCount:D003},数据量:{seedDataList.Count:D003},新增 {insertCount:D003} 条记录,更新 {updateCount:D003} 条记录)"); Console.WriteLine($"初始化种子数据 {seedType.FullName,-58} ({config.ConfigId} - {Interlocked.Increment(ref taskIndex):D003}/{seedDataTypeCount:D003},数据量:{seedDataList.Count:D003},新增 {insertCount:D003} 条记录,更新 {updateCount:D003} 条记录)");
} }
} }
_isHandlingSeedData = false;
} }
/// <summary> /// <summary>

View File

@ -103,7 +103,7 @@
<el-radio :value="true"></el-radio> <el-radio :value="true"></el-radio>
</el-radio-group> </el-radio-group>
<el-upload ref="uploadRef" drag :auto-upload="false" :limit="1" :file-list="state.fileList" action :on-change="handleChange" accept=".jpg,.png,.bmp,.gif,.txt,.pdf,.xlsx,.docx"> <el-upload ref="uploadRef" drag :auto-upload="false" :limit="1" :file-list="state.fileList" action :on-change="handleChange" accept=".jpg,.png,.bmp,.gif,.txt,.xml,.pdf,.xlsx,.docx">
<el-icon class="el-icon--upload"> <el-icon class="el-icon--upload">
<ele-UploadFilled /> <ele-UploadFilled />
</el-icon> </el-icon>