03a9eb73c7
- Define annotation-driven operation log recording approach - Specify key business operations to be logged - Outline testing and deployment strategy - Address performance and security considerations
8.2 KiB
8.2 KiB
操作日志记录功能设计文档
日期: 2026-04-03
作者: 张翔
版本: 1.0
1. 概述
1.1 背景
当前系统的Dashboard操作日志一直显示0,原因是缺少操作日志记录功能。虽然数据库表、服务层和API都已就绪,但没有自动记录用户操作的机制。
1.2 目标
实现一个基于注解的操作日志记录功能,自动记录关键业务操作,为系统审计和问题追踪提供数据支持。
1.3 范围
只记录关键业务操作,包括:
- 用户管理:创建、更新、删除用户、修改密码、分配角色
- 角色管理:创建、更新、删除角色、分配权限
- 菜单管理:创建、更新、删除菜单
- 系统配置:创建、更新、删除配置
- 数据字典:创建、更新、删除字典
- 公告管理:创建、更新、删除公告
2. 架构设计
2.1 整体架构
采用AOP切面 + 注解驱动的架构:
用户请求 → Handler方法(带@OperationLog注解)
↓
OperationLogAspect拦截
↓
记录开始时间、获取请求参数
↓
执行业务方法
↓
记录结束时间、获取返回结果
↓
异步保存操作日志到数据库
↓
返回结果给用户
2.2 核心组件
@OperationLog注解:标记需要记录日志的方法OperationLogAspect切面:拦截注解方法,自动记录操作日志OperationLogService服务:已有的服务层,负责保存日志到数据库- 异步处理:使用Reactor的异步机制,不阻塞主业务流程
2.3 关键设计点
- 响应式编程:使用Reactor的Mono/Flux,与现有WebFlux架构保持一致
- 异步记录:日志记录不影响主业务流程性能
- 错误容错:日志记录失败不影响业务方法执行
- 自动获取上下文:从SecurityContext获取当前用户,从ServerWebExchange获取IP地址
3. 详细设计
3.1 注解定义
package cn.novalon.manage.sys.audit;
import java.lang.annotation.*;
/**
* 操作日志注解
* 标记需要记录操作日志的方法
*
* @author 张翔
* @date 2026-04-03
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OperationLog {
/**
* 操作名称
* 例如:"创建用户"、"删除角色"
*/
String operation();
/**
* 模块名称
* 例如:"用户管理"、"角色管理"
*/
String module();
}
3.2 切面实现
@Aspect
@Component
public class OperationLogAspect {
private final IOperationLogService logService;
private final ObjectMapper objectMapper;
@Around("@annotation(operationLog)")
public Object around(ProceedingJoinPoint point, OperationLog operationLog) throws Throwable {
long startTime = System.currentTimeMillis();
// 1. 获取请求信息
String username = getCurrentUsername();
String ip = getCurrentIp();
String method = point.getSignature().toShortString();
String params = serializeParams(point.getArgs());
// 2. 执行业务方法
Object result = null;
String status = "0"; // 0-成功, 1-失败
String errorMsg = null;
try {
result = point.proceed();
// 3. 处理响应式结果
if (result instanceof Mono) {
return ((Mono<?>) result)
.doOnSuccess(res -> {
long duration = System.currentTimeMillis() - startTime;
saveLogAsync(operationLog, username, ip, method,
params, res, duration, "0", null);
})
.doOnError(error -> {
long duration = System.currentTimeMillis() - startTime;
saveLogAsync(operationLog, username, ip, method,
params, null, duration, "1", error.getMessage());
});
}
return result;
} catch (Throwable error) {
status = "1";
errorMsg = error.getMessage();
throw error;
} finally {
if (!(result instanceof Mono)) {
long duration = System.currentTimeMillis() - startTime;
saveLogAsync(operationLog, username, ip, method,
params, result, duration, status, errorMsg);
}
}
}
private void saveLogAsync(OperationLog operationLog, String username,
String ip, String method, String params,
Object result, long duration, String status,
String errorMsg) {
// 异步保存日志,不阻塞主流程
Mono.fromRunnable(() -> {
cn.novalon.manage.sys.core.domain.OperationLog log =
new cn.novalon.manage.sys.core.domain.OperationLog();
log.setUsername(username);
log.setOperation(operationLog.module() + " - " + operationLog.operation());
log.setMethod(method);
log.setParams(params);
log.setResult(serializeResult(result));
log.setIp(ip);
log.setDuration(duration);
log.setStatus(status);
log.setErrorMsg(errorMsg);
logService.save(log).subscribe();
}).subscribeOn(Schedulers.boundedElastic()).subscribe();
}
}
3.3 需要记录的操作
用户管理模块
createUser()- 创建用户updateUser()- 更新用户deleteUser()- 删除用户changePassword()- 修改密码assignRoles()- 分配角色
角色管理模块
createRole()- 创建角色updateRole()- 更新角色deleteRole()- 删除角色assignPermissionsToRole()- 分配权限
菜单管理模块
createMenu()- 创建菜单updateMenu()- 更新菜单deleteMenu()- 删除菜单
其他模块
- 系统配置:创建、更新、删除配置
- 数据字典:创建、更新、删除字典
- 公告管理:创建、更新、删除公告
4. 测试策略
4.1 单元测试
OperationLogAspectTest:测试切面的核心逻辑
- 测试成功场景:方法执行成功,日志正确记录
- 测试失败场景:方法抛出异常,日志记录错误信息
- 测试响应式场景:Mono返回值的处理
- 测试上下文获取:用户、IP等信息的正确获取
4.2 集成测试
OperationLogIntegrationTest:测试完整的日志记录流程
- 调用带注解的API接口
- 验证日志是否正确保存到数据库
- 验证日志内容的完整性
4.3 E2E测试
在现有E2E测试中验证:
- 执行用户管理操作后,检查Dashboard操作日志数量是否增加
- 验证操作日志显示是否正确
5. 部署计划
5.1 阶段1:开发与测试(当前)
- 创建
@OperationLog注解 - 实现
OperationLogAspect切面 - 编写单元测试和集成测试
- 在关键Handler方法上添加注解
5.2 阶段2:验证
- 运行所有测试,确保功能正常
- 手动测试Dashboard操作日志显示
- 验证日志记录不影响系统性能
5.3 阶段3:上线
- 提交代码到Git
- 更新文档
- 部署到开发环境验证
6. 性能考虑
- 异步保存:日志保存使用异步方式,不阻塞主业务流程
- 索引优化:数据库表已有索引(created_at, username)
- 日志清理:建议后续添加定时任务清理历史日志(保留最近3个月)
7. 风险与缓解
| 风险 | 影响 | 缓解措施 |
|---|---|---|
| 日志记录失败影响业务 | 高 | 使用异步保存,失败时只记录错误日志,不影响业务流程 |
| 日志量过大影响性能 | 中 | 只记录关键操作,使用异步保存,定期清理历史日志 |
| 敏感信息泄露 | 高 | 参数序列化时排除敏感字段(如password) |
8. 后续优化
- 日志查询优化:添加更多查询条件(时间范围、操作类型等)
- 日志导出功能:支持导出操作日志为Excel
- 日志统计分析:统计用户操作频率、操作类型分布等
- 日志清理任务:定时清理历史日志,保留最近3个月数据