Просмотр исходного кода

1、添加字典缓存;2、添加字典值合法性校验属性

Ir0nMax 1 год назад
Родитель
Сommit
dfd979ab15

+ 75 - 0
Admin.NET/Admin.NET.Core/Attribute/DictAttribute.cs

@@ -0,0 +1,75 @@
+// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
+//
+// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
+//
+// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
+
+namespace Admin.NET.Core;
+
+/// <summary>
+/// 字典值合规性校验特性
+/// </summary>
+[SuppressSniffer]
+[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
+public class DictAttribute : ValidationAttribute, ITransient
+{
+    /// <summary>
+    /// 字典值合规性校验特性
+    /// </summary>
+    /// <param name="dictTypeCode"></param>
+    /// <param name="errorMessage"></param>
+    public DictAttribute(string dictTypeCode, string errorMessage = "字典值不合法!")
+    {
+        DictTypeCode = dictTypeCode;
+        ErrorMessage = errorMessage;
+    }
+
+    /// <summary>
+    /// 字典值合规性校验
+    /// </summary>
+    /// <param name="value"></param>
+    /// <param name="validationContext"></param>
+    /// <returns></returns>
+    protected override ValidationResult IsValid(object? value, ValidationContext validationContext)
+    {
+        var valueAsString = value?.ToString();
+
+        // 判断是否允许空值
+        if (AllowNullValue && value == null) return ValidationResult.Success;
+
+        // 是否忽略空字符串
+        if (AllowEmptyStrings && string.IsNullOrEmpty(valueAsString)) return ValidationResult.Success;
+
+        // 查询缓存中是否存在
+        var cacheServiceProvider = validationContext.GetRequiredService<SysCacheService>();
+        var sysDictDataServiceProvider = validationContext.GetRequiredService<SysDictDataService>();
+
+        string cacheKey = $"{CacheConst.KeyDict}{DictTypeCode}";
+        var dictDataList = cacheServiceProvider.Get<HashSet<SysDictData>>(cacheKey);
+        if (dictDataList == null)
+        {
+            dictDataList = sysDictDataServiceProvider.GetDataList(DictTypeCode).Result.ToHashSet();
+            cacheServiceProvider.Set(cacheKey, dictDataList);
+        }
+
+        if (!dictDataList.Select(u => u.Code).ToHashSet().Contains(valueAsString))
+            return new ValidationResult($"提示:{ErrorMessage}|字典【{DictTypeCode}】不包含【{valueAsString}】!");
+        else
+            return ValidationResult.Success;
+    }
+
+    /// <summary>
+    /// 字典编码
+    /// </summary>
+    public string DictTypeCode { get; set; }
+
+    /// <summary>
+    ///是否允许空字符串
+    /// </summary>
+    public bool AllowEmptyStrings { get; set; } = false;
+
+    /// <summary>
+    /// 允许空值,有值才验证,默认 false
+    /// </summary>
+    public bool AllowNullValue { get; set; } = false;
+}

+ 5 - 0
Admin.NET/Admin.NET.Core/Const/CacheConst.cs

@@ -85,4 +85,9 @@ public class CacheConst
     /// 系统配置缓存
     /// </summary>
     public const string KeyConfig = "sys_config:";
+
+    /// <summary>
+    /// 系统字典缓存
+    /// </summary>
+    public const string KeyDict = "sys_dict:";
 }

+ 1 - 1
Admin.NET/Admin.NET.Core/Entity/SysOrg.cs

@@ -47,7 +47,7 @@ public partial class SysOrg : EntityTenant
     /// </summary>
     [SugarColumn(ColumnDescription = "机构类型", Length = 64)]
     [MaxLength(64)]
-    public string? Type { get; set; }
+    public virtual string? Type { get; set; }
 
     /// <summary>
     /// 负责人Id

+ 33 - 5
Admin.NET/Admin.NET.Core/Service/Dict/SysDictDataService.cs

@@ -13,11 +13,13 @@ namespace Admin.NET.Core.Service;
 [AllowAnonymous]
 public class SysDictDataService : IDynamicApiController, ITransient
 {
+    private readonly SysCacheService _sysCacheService;
     private readonly SqlSugarRepository<SysDictData> _sysDictDataRep;
 
-    public SysDictDataService(SqlSugarRepository<SysDictData> sysDictDataRep)
+    public SysDictDataService(SqlSugarRepository<SysDictData> sysDictDataRep, SysCacheService sysCacheService)
     {
         _sysDictDataRep = sysDictDataRep;
+        _sysCacheService = sysCacheService;
     }
 
     /// <summary>
@@ -40,6 +42,7 @@ public class SysDictDataService : IDynamicApiController, ITransient
     /// 获取字典值列表 🔖
     /// </summary>
     /// <returns></returns>
+    [UnitOfWork]
     [DisplayName("获取字典值列表")]
     public async Task<List<SysDictData>> GetList([FromQuery] GetDataDictDataInput input)
     {
@@ -67,6 +70,7 @@ public class SysDictDataService : IDynamicApiController, ITransient
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
+    [UnitOfWork]
     [ApiDescriptionSettings(Name = "Update"), HttpPost]
     [DisplayName("更新字典值")]
     public async Task UpdateDictData(UpdateDictDataInput input)
@@ -77,6 +81,9 @@ public class SysDictDataService : IDynamicApiController, ITransient
         isExist = await _sysDictDataRep.IsAnyAsync(u => u.Code == input.Code && u.DictTypeId == input.DictTypeId && u.Id != input.Id);
         if (isExist) throw Oops.Oh(ErrorCodeEnum.D3003);
 
+        var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == input.DictTypeId).Select(u => u.DictType.Code).FirstAsync();
+        _sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}");
+
         await _sysDictDataRep.UpdateAsync(input.Adapt<SysDictData>());
     }
 
@@ -85,6 +92,7 @@ public class SysDictDataService : IDynamicApiController, ITransient
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
+    [UnitOfWork]
     [ApiDescriptionSettings(Name = "Delete"), HttpPost]
     [DisplayName("删除字典值")]
     public async Task DeleteDictData(DeleteDictDataInput input)
@@ -93,6 +101,9 @@ public class SysDictDataService : IDynamicApiController, ITransient
         if (dictData == null)
             throw Oops.Oh(ErrorCodeEnum.D3004);
 
+        var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == dictData.Id).Select(u => u.DictType.Code).FirstAsync();
+        _sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}");
+
         await _sysDictDataRep.DeleteAsync(dictData);
     }
 
@@ -112,6 +123,7 @@ public class SysDictDataService : IDynamicApiController, ITransient
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
+    [UnitOfWork]
     [DisplayName("修改字典值状态")]
     public async Task SetStatus(DictDataInput input)
     {
@@ -122,6 +134,9 @@ public class SysDictDataService : IDynamicApiController, ITransient
         if (!Enum.IsDefined(typeof(StatusEnum), input.Status))
             throw Oops.Oh(ErrorCodeEnum.D3005);
 
+        var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == dictData.Id).Select(u => u.DictType.Code).FirstAsync();
+        _sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}");
+
         dictData.Status = input.Status;
         await _sysDictDataRep.UpdateAsync(dictData);
     }
@@ -134,10 +149,20 @@ public class SysDictDataService : IDynamicApiController, ITransient
     [NonAction]
     public async Task<List<SysDictData>> GetDictDataListByDictTypeId(long dictTypeId)
     {
-        return await _sysDictDataRep.AsQueryable()
-            .Where(u => u.DictTypeId == dictTypeId)
-            .OrderBy(u => new { u.OrderNo, u.Code })
-            .ToListAsync();
+        var dictType = await _sysDictDataRep.GetByIdAsync(dictTypeId);
+        var dictDataList = _sysCacheService.Get<List<SysDictData>>($"{CacheConst.KeyDict}{dictTypeId}");
+
+        if (dictDataList == null)
+        {
+            dictDataList = await _sysDictDataRep.AsQueryable()
+                .Where(u => u.DictTypeId == dictTypeId)
+                .OrderBy(u => new { u.OrderNo, u.Code })
+                .ToListAsync();
+
+            _sysCacheService.Set($"{CacheConst.KeyDict}{dictType.Code}", dictDataList);
+        }
+
+        return dictDataList;
     }
 
     /// <summary>
@@ -179,6 +204,9 @@ public class SysDictDataService : IDynamicApiController, ITransient
     [NonAction]
     public async Task DeleteDictData(long dictTypeId)
     {
+        var dictTypeCode = await _sysDictDataRep.AsQueryable().Where(u => u.DictTypeId == dictTypeId).Select(u => u.DictType.Code).FirstAsync();
+        _sysCacheService.Remove($"{CacheConst.KeyDict}{dictTypeCode}");
+
         await _sysDictDataRep.DeleteAsync(u => u.DictTypeId == dictTypeId);
     }
 }

+ 11 - 1
Admin.NET/Admin.NET.Core/Service/Dict/SysDictTypeService.cs

@@ -15,12 +15,15 @@ public class SysDictTypeService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<SysDictType> _sysDictTypeRep;
     private readonly SysDictDataService _sysDictDataService;
+    private readonly SysCacheService _sysCacheService;
 
     public SysDictTypeService(SqlSugarRepository<SysDictType> sysDictTypeRep,
-        SysDictDataService sysDictDataService)
+        SysDictDataService sysDictDataService,
+        SysCacheService sysCacheService)
     {
         _sysDictTypeRep = sysDictTypeRep;
         _sysDictDataService = sysDictDataService;
+        _sysCacheService = sysCacheService;
     }
 
     /// <summary>
@@ -52,6 +55,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
+    [UnitOfWork]
     [AllowAnonymous]
     [DisplayName("获取字典类型-值列表")]
     public async Task<List<SysDictData>> GetDataList([FromQuery] GetDataDictTypeInput input)
@@ -84,6 +88,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
+    [UnitOfWork]
     [ApiDescriptionSettings(Name = "Update"), HttpPost]
     [DisplayName("更新字典类型")]
     public async Task UpdateDictType(UpdateDictTypeInput input)
@@ -96,6 +101,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
         if (isExist)
             throw Oops.Oh(ErrorCodeEnum.D3001);
 
+        _sysCacheService.Remove($"{CacheConst.KeyDict}{input.Code}");
         await _sysDictTypeRep.UpdateAsync(input.Adapt<SysDictType>());
     }
 
@@ -104,6 +110,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
+    [UnitOfWork]
     [ApiDescriptionSettings(Name = "Delete"), HttpPost]
     [DisplayName("删除字典类型")]
     public async Task DeleteDictType(DeleteDictTypeInput input)
@@ -133,6 +140,7 @@ public class SysDictTypeService : IDynamicApiController, ITransient
     /// </summary>
     /// <param name="input"></param>
     /// <returns></returns>
+    [UnitOfWork]
     [DisplayName("修改字典类型状态")]
     public async Task SetStatus(DictTypeInput input)
     {
@@ -143,6 +151,8 @@ public class SysDictTypeService : IDynamicApiController, ITransient
         if (!Enum.IsDefined(typeof(StatusEnum), input.Status))
             throw Oops.Oh(ErrorCodeEnum.D3005);
 
+        _sysCacheService.Remove($"{CacheConst.KeyDict}{dictType.Code}");
+
         dictType.Status = input.Status;
         await _sysDictTypeRep.UpdateAsync(dictType);
     }

+ 6 - 0
Admin.NET/Admin.NET.Core/Service/Org/Dto/OrgInput.cs

@@ -31,6 +31,12 @@ public class AddOrgInput : SysOrg
     /// </summary>
     [Required(ErrorMessage = "机构名称不能为空")]
     public override string Name { get; set; }
+
+    /// <summary>
+    /// 机构类型
+    /// </summary>
+    [Dict("org_type", ErrorMessage = "机构类型不能合法", AllowNullValue = true, AllowEmptyStrings = true)]
+    public override string? Type { get; set; }
 }
 
 public class UpdateOrgInput : AddOrgInput

+ 1 - 0
Admin.NET/Admin.NET.Core/Service/User/Dto/UserInput.cs

@@ -14,6 +14,7 @@ public class UserInput : BaseIdInput
     /// <summary>
     /// 状态
     /// </summary>
+    [Dict("StatusEnum")]
     public StatusEnum Status { get; set; }
 }