using Microsoft.AspNetCore.Http; using Volo.Abp.Caching; using Volo.Abp.DependencyInjection; using Yi.Framework.Bbs.Domain.Entities; using Yi.Framework.Bbs.Domain.Shared.Caches; using Yi.Framework.Bbs.Domain.Shared.Enums; using Yi.Framework.SqlSugarCore.Abstractions; namespace Yi.Framework.Bbs.Application.Extensions; /// /// 访问日志中间件 /// 并发最高,采用缓存,默认10分钟才会真正操作一次数据库 /// /// 需考虑一致性问题,又不能上锁影响性能 /// public class AccessLogMiddleware : IMiddleware, ITransientDependency { private readonly IDistributedCache _accessLogCache; private readonly ISqlSugarRepository _repository; public AccessLogMiddleware(IDistributedCache accessLogCache, ISqlSugarRepository repository) { _accessLogCache = accessLogCache; _repository = repository; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { await next(context); //获取缓存 var cache = await _accessLogCache.GetAsync(AccessLogCacheConst.Key); //当前缓存需赋的值 long currentNumber = 1; //最后插入的时间 DateTime lastInsertTime = DateTime.Now; //cahce是空,创建缓存,当前数量从数据库中获取 //不等于空,如果大于当前天,插入数据库(间隔超过10分钟,也插入) //获取当前访问数量 //没有缓存 if (cache is null) { //获取数据库今天最后最后一条数据 var currentDayEntity = await GetDateAccessLogEntityAsync(); //数据库有数据,以数据库数据为准+1 if (currentDayEntity is not null) { currentNumber = currentDayEntity.Number + 1; } //数据库没有数据,就是默认的1,重新开始 } else { //有缓存,根据根据缓存的值来 currentNumber = cache.Number + 1; lastInsertTime = cache.LastInsertTime; //数据库持久化 //缓存的日期大于当天的日期,插入到数据库,同时缓存变成0,重新开始统计 if (cache.LastModificationTime.Date > DateTime.Today) { await _repository.InsertAsync(new AccessLogAggregateRoot() { AccessLogType = AccessLogTypeEnum.Request, Number = currentNumber }); currentNumber = 0; } else { if (cache.LastInsertTime <= DateTime.Now - TimeSpan.FromMinutes(10)) { //这里还需要判断数据库是否有值,不能之间更新 //缓存的时间大于当前数据库时间10分钟之后,更新(减少数据库交互,10分钟才更新一次) var currentDayEntity = await GetDateAccessLogEntityAsync(); if (currentDayEntity is null) { await _repository.InsertAsync(new AccessLogAggregateRoot() { AccessLogType = AccessLogTypeEnum.Request, Number = currentNumber }); } await _repository.UpdateAsync(currentDayEntity); } } } //覆盖缓存 var newCache = new AccessLogCacheItem(currentNumber) { LastInsertTime = lastInsertTime }; await _accessLogCache.SetAsync(AccessLogCacheConst.Key, newCache); } /// /// 获取今天的统计 /// /// private async Task GetDateAccessLogEntityAsync() { //获取数据库今天最后最后一条数据 var currentDayEntity = await _repository._DbQueryable .Where(x => x.AccessLogType == AccessLogTypeEnum.Request) .Where(x => x.CreationTime == DateTime.Today) .OrderByDescending(x => x.CreationTime) .FirstAsync(); return currentDayEntity; } }