perf: 优化日志保留与分页查询

- 降低普通只读请求的日志写入并保留敏感 GET 审计

- 增加数据库分批清理、时间索引和文件滚动容量上限

- 增加近 30 天筛选、稳定倒序和分页大小限制
This commit is contained in:
2026-07-30 14:21:36 +08:00
parent c78074a969
commit 03f45212ef
21 changed files with 732 additions and 19 deletions

View File

@@ -13,6 +13,7 @@ import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import tech.easyflow.log.annotation.LogRecord;
import tech.easyflow.log.entity.WriteLog;
import tech.easyflow.log.mapper.WriteLogMapper;
@@ -28,6 +29,7 @@ import static org.junit.Assert.assertSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -158,6 +160,47 @@ public class LogAspectTest {
assertNull(captor.getValue().getActionBody());
}
/**
* 验证未显式标注的 GET 请求不会产生操作日志。
*
* @throws Throwable 切面执行异常
*/
@Test
public void unannotatedGetShouldNotWriteLog() throws Throwable {
WriteLogMapper mapper = mock(WriteLogMapper.class);
LogAspect aspect = new LogAspect(mapper, properties());
request("{}", "GET");
ProceedingJoinPoint joinPoint = joinPoint("read");
when(joinPoint.proceed()).thenReturn("ok");
assertEquals("ok", aspect.doAround(joinPoint));
verify(mapper, never()).insert(any(WriteLog.class));
}
/**
* 验证显式标注的 GET 请求仍会产生操作日志。
*
* @throws Throwable 切面执行异常
*/
@Test
public void annotatedGetShouldWriteLog() throws Throwable {
WriteLogMapper mapper = mock(WriteLogMapper.class);
LogAspect aspect = new LogAspect(mapper, properties());
request("{}", "GET");
ProceedingJoinPoint joinPoint = joinPoint("auditedRead");
when(joinPoint.proceed()).thenReturn("ok");
try (MockedStatic<StpUtil> stp = Mockito.mockStatic(StpUtil.class)) {
stp.when(StpUtil::isLogin).thenReturn(false);
assertEquals("ok", aspect.doAround(joinPoint));
}
ArgumentCaptor<WriteLog> captor = ArgumentCaptor.forClass(WriteLog.class);
verify(mapper).insert(captor.capture());
assertEquals("审计读取", captor.getValue().getActionName());
}
/**
* 创建测试日志配置。
*
@@ -177,8 +220,21 @@ public class LogAspectTest {
* @throws IOException 输入流创建失败
*/
private HttpServletRequest request(String body) throws IOException {
return request(body, "POST");
}
/**
* 创建并绑定指定 HTTP 方法的测试请求。
*
* @param body JSON body
* @param httpMethod HTTP 方法
* @return 测试请求
* @throws IOException 输入流创建失败
*/
private HttpServletRequest request(String body, String httpMethod) throws IOException {
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getServletPath()).thenReturn("/api/v1/skill/update");
when(request.getMethod()).thenReturn(httpMethod);
when(request.getContentType()).thenReturn("application/json;charset=UTF-8");
when(request.getCharacterEncoding()).thenReturn(StandardCharsets.UTF_8.name());
when(request.getParameterNames()).thenReturn(Collections.emptyEnumeration());
@@ -196,9 +252,20 @@ public class LogAspectTest {
* @throws NoSuchMethodException 测试方法不存在
*/
private ProceedingJoinPoint joinPoint() throws NoSuchMethodException {
return joinPoint("update");
}
/**
* 创建指定控制器方法的测试连接点。
*
* @param methodName 控制器方法名
* @return 测试连接点
* @throws NoSuchMethodException 测试方法不存在
*/
private ProceedingJoinPoint joinPoint(String methodName) throws NoSuchMethodException {
ProceedingJoinPoint joinPoint = mock(ProceedingJoinPoint.class);
MethodSignature signature = mock(MethodSignature.class);
Method method = TestController.class.getMethod("update");
Method method = TestController.class.getMethod(methodName);
when(joinPoint.getSignature()).thenReturn(signature);
when(signature.getDeclaringType()).thenReturn(TestController.class);
when(signature.getMethod()).thenReturn(method);
@@ -249,5 +316,24 @@ public class LogAspectTest {
public Object update() {
return null;
}
/**
* 模拟普通读取入口。
*
* @return 空结果
*/
public Object read() {
return null;
}
/**
* 模拟需要审计的读取入口。
*
* @return 空结果
*/
@LogRecord("审计读取")
public Object auditedRead() {
return null;
}
}
}