🚀 feat(新增): 实现RedisCache注解

This commit is contained in:
bunny 2024-09-12 13:56:09 +08:00
parent faf760029e
commit a609bb1dd4
15 changed files with 154 additions and 39 deletions

View File

@ -0,0 +1,11 @@
namespace Bunny.Common.Attribute;
[AttributeUsage(AttributeTargets.Method)]
public class CacheableAttribute(string key, string durationString) : System.Attribute
{
// 构造函数接收一个表示时间的字符串参数
// 将字符串转换为TimeSpan
public string? Key { get; set; } = key;
public TimeSpan TimeDuration { get; set; } = TimeSpan.Parse(durationString);
}

View File

@ -1,6 +1,4 @@
namespace Bunny.Common.Attribute; namespace Bunny.Common.Attribute;
[AttributeUsage(AttributeTargets.Method)] [AttributeUsage(AttributeTargets.Method)]
public class TransactionAttribute : System.Attribute public class TransactionAttribute : System.Attribute;
{
}

View File

@ -7,6 +7,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Castle.Core" Version="5.1.1"/>
<PackageReference Include="log4net" Version="2.0.17"/> <PackageReference Include="log4net" Version="2.0.17"/>
<PackageReference Include="Microsoft.AspNetCore" Version="2.2.0"/> <PackageReference Include="Microsoft.AspNetCore" Version="2.2.0"/>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6"/> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6"/>

View File

@ -1,5 +1,6 @@
using Bunny.Dao.Entity; using Bunny.Dao.Entity;
using Bunny.Dao.Entity.System; using Bunny.Dao.Entity.System;
using Bunny.Dao.Entity.System.Dept;
using Bunny.Dao.Entity.System.Menu; using Bunny.Dao.Entity.System.Menu;
using Bunny.Dao.Entity.System.User; using Bunny.Dao.Entity.System.User;
using log4net; using log4net;
@ -30,6 +31,7 @@ public class EfCoreContext : DbContext
private string DbPath { get; } private string DbPath { get; }
public DbSet<Icons> Icons { get; set; } public DbSet<Icons> Icons { get; set; }
public DbSet<Dept> Dept { get; set; } public DbSet<Dept> Dept { get; set; }
public DbSet<DeptUsers> DeptUsers { get; set; }
public DbSet<Users> Users { get; set; } public DbSet<Users> Users { get; set; }
public DbSet<Roles> Roles { get; set; } public DbSet<Roles> Roles { get; set; }
public DbSet<Permissions> Permissions { get; set; } public DbSet<Permissions> Permissions { get; set; }
@ -44,7 +46,6 @@ public class EfCoreContext : DbContext
/// </summary> /// </summary>
protected override void OnConfiguring(DbContextOptionsBuilder options) protected override void OnConfiguring(DbContextOptionsBuilder options)
{ {
Log.Info("EfCoreContext 数据库连接...");
options.UseSqlServer(DbPath); options.UseSqlServer(DbPath);
} }

View File

@ -12,31 +12,28 @@ public static class RedisContext
public static void AddRedisContext(this WebApplicationBuilder builder) public static void AddRedisContext(this WebApplicationBuilder builder)
{ {
Task.Run(() => // 获取端口等配置信息
var host = AppSettings.GetConfig("Redis:Host");
var port = Convert.ToInt32(AppSettings.GetConfig("Redis:Port"));
var defaultDb = Convert.ToInt32(AppSettings.GetConfig("Redis:DefaultDB"));
var password = AppSettings.Get<string>("Redis:Password");
var timeout = Convert.ToInt32(AppSettings.GetConfig("Redis:AsyncTimeout"));
// 添加连接地址
EndPointCollection.Add(host, port);
// 初始化连接对象
var connect = ConnectionMultiplexer.Connect(new ConfigurationOptions
{ {
// 获取端口等配置信息 EndPoints = EndPointCollection,
var host = AppSettings.GetConfig("Redis:Host"); Password = password,
var port = Convert.ToInt32(AppSettings.GetConfig("Redis:Port")); DefaultDatabase = defaultDb,
var defaultDb = Convert.ToInt32(AppSettings.GetConfig("Redis:DefaultDB")); AsyncTimeout = timeout
var password = AppSettings.Get<string>("Redis:Password");
var timeout = Convert.ToInt32(AppSettings.GetConfig("Redis:AsyncTimeout"));
// 添加连接地址
EndPointCollection.Add(host, port);
// 初始化连接对象
var connect = ConnectionMultiplexer.Connect(new ConfigurationOptions
{
EndPoints = EndPointCollection,
Password = password,
DefaultDatabase = defaultDb,
AsyncTimeout = timeout
});
// 创建连接对象
RedisDatabase = connect.GetDatabase();
Log.Info("Redis 初始化...");
}); });
// 创建连接对象
RedisDatabase = connect.GetDatabase();
Log.Info("Redis 初始化...");
} }
} }

View File

@ -0,0 +1,73 @@
using System.Reflection;
using Bunny.Common.Attribute;
using Bunny.Common.Context.Middleware;
using Bunny.Dao.Common.Constant;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using IDatabase = StackExchange.Redis.IDatabase;
namespace Bunny.Common.Filter;
/// <summary>
/// Redis缓存注解
/// </summary>
public class CacheIiAsyncActionFilter : IAsyncActionFilter
{
private readonly IDatabase _redisDatabase = RedisContext.RedisDatabase!;
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var actionDesc = context.ActionDescriptor as ControllerActionDescriptor;
var hasCacheableAttribute = actionDesc?.MethodInfo.IsDefined(typeof(CacheableAttribute), false) ?? false;
// 如果没有加注解直接返回
if (!hasCacheableAttribute)
{
await next();
return;
}
// 获取注解中的值
var cacheableAttribute = actionDesc?.MethodInfo.GetCustomAttribute<CacheableAttribute>();
// 注解为空
if (cacheableAttribute?.Key == null)
{
await next();
return;
}
// 缓存的key
var cacheKey = cacheableAttribute.Key;
// 缓存时间
var duration = cacheableAttribute.TimeDuration;
// 缓存数据
var cachedData = _redisDatabase.StringGet(cacheKey);
// 如果注解中有值将值赋值给返回结果
if (!cachedData.IsNullOrEmpty)
{
context.Result = new ContentResult
{
Content = cachedData.ToString(),
ContentType = "application/json"
};
return;
}
// 如果注解中没有值,赋值内容
var result = (ObjectResult)next().GetAwaiter().GetResult().Result!;
var jsonSettings = new JsonSerializerSettings
{
DateFormatString = LocalDateTimeConstant.DefaultDateTimeSecondFormat,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
// 现在你可以访问 result.Data
var json = JsonConvert.SerializeObject(result.Value, jsonSettings);
_redisDatabase.StringSet(cacheKey, json, duration);
}
}

View File

@ -2,7 +2,7 @@
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
namespace Bunny.Dao.Entity.System; namespace Bunny.Dao.Entity.System.Dept;
[Comment("系统部门表")] [Comment("系统部门表")]
[Table("System_Dept")] [Table("System_Dept")]

View File

@ -0,0 +1,12 @@
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;
namespace Bunny.Dao.Entity.System.Dept;
[Comment("部门和用户关系表")]
[Table("System_DeptUsers")]
public class DeptUsers : BaseEntity
{
[Comment("部门id")] public Guid DeptId { get; init; }
[Comment("用户id")] public Guid UserId { get; init; }
}

View File

@ -61,7 +61,6 @@ public class UserService : IUserService
/// 批量添加数据 /// 批量添加数据
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
[Transaction]
public void AddBatchBlogs(string url) public void AddBatchBlogs(string url)
{ {
var list = new List<Users>(); var list = new List<Users>();
@ -119,6 +118,7 @@ public class UserService : IUserService
/// </summary> /// </summary>
/// <param name="page"></param> /// <param name="page"></param>
/// <param name="limit"></param> /// <param name="limit"></param>
[Cacheable("UserService::Get", "00:00:59")]
public PageResult<Users> QueryPage(int page, int limit) public PageResult<Users> QueryPage(int page, int limit)
{ {
var items = DbContext.Users.Take(limit).Skip(page).ToList(); var items = DbContext.Users.Take(limit).Skip(page).ToList();

View File

@ -19,9 +19,27 @@ public static class AddAutofacConfig
.Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType)
.PropertiesAutowired(); //支持属性注入 .PropertiesAutowired(); //支持属性注入
// 注入EfCore上下文对象 // 系统相关注入
builder.RegisterType<EfCoreContext>(); SystemRegisterType(builder);
// 服务相关注入
ServiceRegisterType(builder);
}
/// <summary>
/// 系统相关注入
/// </summary>
/// <param name="builder">ContainerBuilder</param>
private static void SystemRegisterType(ContainerBuilder builder)
{
builder.RegisterType<EfCoreContext>();
}
/// <summary>
/// 服务相关注入
/// </summary>
/// <param name="builder">ContainerBuilder</param>
private static void ServiceRegisterType(ContainerBuilder builder)
{
// 注入Service服务 // 注入Service服务
builder.RegisterType<BaseService>().As<IBaseService>(); builder.RegisterType<BaseService>().As<IBaseService>();
builder.RegisterType<UserService>().As<IUserService>(); builder.RegisterType<UserService>().As<IUserService>();

View File

@ -20,6 +20,8 @@ public class BaseConfig(WebApplicationBuilder builder)
// 配置日志相关 // 配置日志相关
builder.Logging.AddLog4Net("Configuration/log4net.config"); builder.Logging.AddLog4Net("Configuration/log4net.config");
// 添加 ASP.NET 自带缓存
builder.Services.AddMemoryCache();
// 自定义时间格式 // 自定义时间格式
builder.Services.AddControllers().AddJsonOptions(options => builder.Services.AddControllers().AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter())); options.JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter()));

View File

@ -1,5 +1,4 @@
using Bunny.Common.Attribute; using Bunny.Common.Filter;
using Bunny.Common.Filter;
using Bunny.Service.Job.JobService; using Bunny.Service.Job.JobService;
using Lazy.Captcha.Core; using Lazy.Captcha.Core;
using Lazy.Captcha.Core.Generator; using Lazy.Captcha.Core.Generator;
@ -34,6 +33,7 @@ public static class ServiceRegistration
option.Filters.Add<ValidateModelStateAttribute>(); option.Filters.Add<ValidateModelStateAttribute>();
option.Filters.Add<TransactionIAsyncActionFilter>(); option.Filters.Add<TransactionIAsyncActionFilter>();
option.Filters.Add<AuthorizationFilter>(); option.Filters.Add<AuthorizationFilter>();
option.Filters.Add(typeof(CacheIiAsyncActionFilter));
}); });
} }

View File

@ -1,4 +1,5 @@
using Bunny.Dao.Common.Result; using Bunny.Common.Attribute;
using Bunny.Dao.Common.Result;
using Bunny.Dao.Dto.System; using Bunny.Dao.Dto.System;
using Bunny.Dao.Entity.System.User; using Bunny.Dao.Entity.System.User;
using Bunny.Service.IService; using Bunny.Service.IService;
@ -32,6 +33,7 @@ public class BlogController : ControllerBase
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
[HttpGet] [HttpGet]
[Cacheable("QueryBlog", "00:00:59")]
public Result<List<Users>> QueryBlog() public Result<List<Users>> QueryBlog()
{ {
var vo = UserService.QueryBlog(); var vo = UserService.QueryBlog();

View File

@ -16,9 +16,9 @@
"Audience": "Audience" "Audience": "Audience"
}, },
"Redis": { "Redis": {
"Host": "47.120.65.66", "Host": "192.168.3.98",
"Port": "6379", "Port": "6379",
"Password": "02120212", "Password": "123456",
"DefaultDB": 6, "DefaultDB": 6,
"AsyncTimeout": 300 "AsyncTimeout": 300
}, },

View File

@ -16,9 +16,9 @@
"Audience": "Audience" "Audience": "Audience"
}, },
"Redis": { "Redis": {
"Host": "47.120.65.66", "Host": "192.168.3.98",
"Port": "6379", "Port": "6379",
"Password": "02120212", "Password": "123456",
"DefaultDB": 6, "DefaultDB": 6,
"AsyncTimeout": 300 "AsyncTimeout": 300
}, },