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

This commit is contained in:
zuohuaijun 2024-06-23 17:03:52 +08:00
parent e24efb3970
commit b9d762f97f
7 changed files with 132 additions and 7 deletions

View File

@ -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;
}

View File

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

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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

View File

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