feat: 新增请求访问统计功能
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
|
||||
namespace Yi.Framework.Bbs.Application.Extensions;
|
||||
|
||||
public static class AccessLogExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseAccessLog(this IApplicationBuilder app)
|
||||
{
|
||||
app.UseMiddleware<AccessLogMiddleware>();
|
||||
return app;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 访问日志中间件
|
||||
/// 并发最高,采用缓存,默认10分钟才会真正操作一次数据库
|
||||
///
|
||||
/// 需考虑一致性问题,又不能上锁影响性能
|
||||
/// </summary>
|
||||
public class AccessLogMiddleware : IMiddleware, ITransientDependency
|
||||
{
|
||||
private readonly IDistributedCache<AccessLogCacheItem> _accessLogCache;
|
||||
private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository;
|
||||
|
||||
public AccessLogMiddleware(IDistributedCache<AccessLogCacheItem> accessLogCache,
|
||||
ISqlSugarRepository<AccessLogAggregateRoot> 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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取今天的统计
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<AccessLogAggregateRoot?> 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;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using Volo.Abp.Application.Services;
|
||||
using Yi.Framework.Bbs.Application.Contracts.Dtos.AccessLog;
|
||||
using Yi.Framework.Bbs.Application.Contracts.IServices;
|
||||
using Yi.Framework.Bbs.Domain.Entities;
|
||||
using Yi.Framework.Bbs.Domain.Shared.Enums;
|
||||
using Yi.Framework.SqlSugarCore.Abstractions;
|
||||
|
||||
namespace Yi.Framework.Bbs.Application.Services
|
||||
@@ -11,7 +12,11 @@ namespace Yi.Framework.Bbs.Application.Services
|
||||
public class AccessLogService : ApplicationService, IAccessLogService
|
||||
{
|
||||
private readonly ISqlSugarRepository<AccessLogAggregateRoot> _repository;
|
||||
public AccessLogService(ISqlSugarRepository<AccessLogAggregateRoot> repository) { _repository = repository; }
|
||||
|
||||
public AccessLogService(ISqlSugarRepository<AccessLogAggregateRoot> repository)
|
||||
{
|
||||
_repository = repository;
|
||||
}
|
||||
|
||||
public DateTime GetWeekFirst()
|
||||
{
|
||||
@@ -45,16 +50,15 @@ namespace Yi.Framework.Bbs.Application.Services
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取全部访问流量(3个月)
|
||||
/// </summary>
|
||||
/// <param name="AccessLogType"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<List<AccessLogDto>> Get()
|
||||
public async Task<List<AccessLogDto>> GetListAsync([FromQuery] AccessLogTypeEnum AccessLogType)
|
||||
{
|
||||
var entities = await _repository._DbQueryable
|
||||
.Where(x=>x.CreationTime>=DateTime.Now.AddMonths(-3))
|
||||
var entities = await _repository._DbQueryable.Where(x => x.AccessLogType == AccessLogType)
|
||||
.Where(x => x.CreationTime >= DateTime.Now.AddMonths(-3))
|
||||
.OrderBy(x => x.CreationTime).ToListAsync();
|
||||
var output = entities.Adapt<List<AccessLogDto>>();
|
||||
output?.ForEach(x => x.CreationTime = x.CreationTime.Date);
|
||||
@@ -62,7 +66,7 @@ namespace Yi.Framework.Bbs.Application.Services
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 触发
|
||||
/// 首页点击触发
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpPost("access-log")]
|
||||
@@ -77,17 +81,20 @@ namespace Yi.Framework.Bbs.Application.Services
|
||||
}
|
||||
else
|
||||
{
|
||||
await _repository._Db.Updateable<AccessLogAggregateRoot>().SetColumns(it => it.Number == it.Number + 1).Where(it => it.Id == last.Id).ExecuteCommandAsync();
|
||||
await _repository._Db.Updateable<AccessLogAggregateRoot>().SetColumns(it => it.Number == it.Number + 1)
|
||||
.Where(it => it.Id == last.Id).ExecuteCommandAsync();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前周数据
|
||||
/// 获取当前周首页点击数据
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public async Task<AccessLogDto[]> GetWeekAsync()
|
||||
{
|
||||
var lastSeven = await _repository._DbQueryable.OrderByDescending(x => x.CreationTime).ToPageListAsync(1, 7);
|
||||
var lastSeven = await _repository._DbQueryable
|
||||
.Where(x => x.AccessLogType == AccessLogTypeEnum.HomeClick)
|
||||
.OrderByDescending(x => x.CreationTime).ToPageListAsync(1, 7);
|
||||
|
||||
return WeekTimeHandler(lastSeven.ToArray());
|
||||
}
|
||||
@@ -99,7 +106,8 @@ namespace Yi.Framework.Bbs.Application.Services
|
||||
/// <returns></returns>
|
||||
private AccessLogDto[] WeekTimeHandler(AccessLogAggregateRoot[] data)
|
||||
{
|
||||
data = data.Where(x => x.CreationTime >= GetWeekFirst()).OrderByDescending(x => x.CreationTime).DistinctBy(x => x.CreationTime.DayOfWeek).ToArray();
|
||||
data = data.Where(x => x.CreationTime >= GetWeekFirst()).OrderByDescending(x => x.CreationTime)
|
||||
.DistinctBy(x => x.CreationTime.DayOfWeek).ToArray();
|
||||
|
||||
Dictionary<DayOfWeek, AccessLogDto> processedData = new Dictionary<DayOfWeek, AccessLogDto>();
|
||||
|
||||
@@ -117,8 +125,8 @@ namespace Yi.Framework.Bbs.Application.Services
|
||||
// 如果当天有数据,则更新字典中的值为对应的Number
|
||||
var sss = data.Adapt<AccessLogDto>();
|
||||
processedData[dayOfWeek] = item.Adapt<AccessLogDto>();
|
||||
|
||||
}
|
||||
|
||||
var result = processedData.Values.ToList();
|
||||
|
||||
//此时的时间是周日-周一-周二,需要处理
|
||||
@@ -128,8 +136,5 @@ namespace Yi.Framework.Bbs.Application.Services
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user